我有一个可以处于两种模式中的对象:源或接收器。它始终位于其中一个中,并且在编译时始终是已知的(当您传递给您知道的对象时,如果您要读取或写入它显然)。
我可以将所有方法放在同一个对象上,只是假设我不会被调用不正确或出错,或者我认为我可以做两个 单个底层对象的元组结构,并将方法附加到那些元组结构。这些方法几乎完全不相交。
有点滥用这样一个事实,即两个元组结构具有相同的布局,并且对于转换和元组存储没有任何开销。
认为这类似于Java ByteBuffer
和您编写的相关类,然后翻转然后读取然后翻转并写入更多。除此之外会发现使用中的错误。
然而,这似乎有点不寻常,可能会因为这么小的问题而过于混乱。似乎有更好的方法可以做到这一点 - 只需要零开销,因此没有动态调度。
https://play.rust-lang.org/?gist=280d2ec2548e4f38e305&version=stable
#[derive(Debug)]
struct Underlying {
a: u32,
b: u32,
}
#[derive(Debug)]
struct FaceA(Underlying);
impl FaceA {
fn make() -> FaceA { FaceA(Underlying{a:1,b:2}) }
fn doa(&self) { println!("FaceA do A {:?}", *self); }
fn dou(&self) { println!("FaceA do U {:?}", *self); }
fn tob(&self) -> &FaceB { unsafe{std::mem::transmute::<&FaceA,&FaceB>(self)} }
}
#[derive(Debug)]
struct FaceB(Underlying);
impl FaceB {
fn dob(&self) { println!("FaceB do B {:?}", *self); }
fn dou(&self) { println!("FaceB do U {:?}", *self); }
fn toa(&self) -> &FaceA { unsafe{std::mem::transmute::<&FaceB,&FaceA>(self)} }
}
fn main() {
let a = FaceA::make();
a.doa();
a.dou();
let b = a.tob();
b.dob();
b.dou();
let aa = b.toa();
aa.doa();
aa.dou();
}
答案 0 :(得分:4)
首先,您似乎并不了解Rust的所有权如何运作;您可能想阅读Ownership chapter of the Rust Book。具体来说,您对原始FaceA
进行重新别名化的方式就是如何专门启用您想要避免的内容。此外,所有借款都是不可改变的,因此不清楚你打算如何做任何突变。
因此,我从头开始编写了一个新示例,涉及两种具有不相交接口的类型(view on playpen)。
#[derive(Debug)]
pub struct Inner {
pub value: i32,
}
impl Inner {
pub fn new(value: i32) -> Self {
Inner {
value: value,
}
}
}
#[derive(Debug)]
pub struct Upper(Inner);
impl Upper {
pub fn new(inner: Inner) -> Self {
Upper(inner)
}
pub fn into_downer(self) -> Downer {
Downer::new(self.0)
}
pub fn up(&mut self) {
self.0.value += 1;
}
}
#[derive(Debug)]
pub struct Downer(Inner);
impl Downer {
pub fn new(inner: Inner) -> Self {
Downer(inner)
}
pub fn into_upper(self) -> Upper {
Upper::new(self.0)
}
pub fn down(&mut self) {
self.0.value -= 1;
}
}
fn main() {
let mut a = Upper::new(Inner::new(0));
a.up();
let mut b = a.into_downer();
b.down();
b.down();
b.down();
let mut c = b.into_upper();
c.up();
show_i32(c.0.value);
}
#[inline(never)]
fn show_i32(v: i32) {
println!("v: {:?}", v);
}
此处,into_upper
和into_downer
方法使用主题值,阻止任何人在之后使用它(尝试在调用{{a
之后访问a.into_downer()
1}})。
这不应该特别低效;这里没有堆分配,Rust非常擅长有效地移动值。如果您有点好奇,这就是main
函数在启用优化的情况下编译的内容:
mov edi, -1
jmp _ZN8show_i3220h2a10d619fa41d919UdaE
它实际上是整个程序的内容(除了我明确告诉它的show
函数而不是内联)。除非分析显示这是一个严重的性能问题,否则我不会担心它。