如何为self的不同可变性实现一个trait。

3

给定一个带有u32字段的结构体。它只有一个重载的方法,可以用作该字段的设置器和获取器。

pub struct Struct {
    value: u32
}
pub trait Trait<T> {
    fn method(&mut self, arg: T);
}
impl Trait<u32> for Struct {
    fn method(&mut self, arg: u32) {
        self.value = arg;
    }
}
impl Trait<&mut u32> for Struct {
    fn method(&mut self, arg: &mut u32) {
        *arg = self.value;
    }
}

这个结构的一个可能用途如下:
fn main() {    
    let mut s = Struct { value: 0 };
    let mut v = 0;
    s.method(&mut v);
    println!("The value of s is: {}", v);
    s.method(3);
    s.method(&mut v);
    println!("The value of s is: {}", v);
}

在使用结构体作为 ffi 接口时,调用重载方法而非直接访问字段的优点有两个。一方面,该方法仍然可以修改值,例如先将 &str 转换为 CString,然后将 *const u8 存储为值,这使字符串可用于 C。另一方面,重载该方法还使得在 C 中可以使用给定的名称,而不是编写 setValuegetValue,例如。然而,正如您在此处所见,其中一个方法不需要对 self 进行可变引用,因为它不会更改值字段,但由于特性需要,无论哪种情况都会使用它。该结构体不仅被配置然后用作 ffi 方法的参数,还可以作为该方法的返回值出现,在这种情况下,它将作为不可变引用返回,并且只能从中读取。自定义的特性实现将如下所示。
impl Trait<u32> for Struct {
    fn method(&mut self, arg: u32) {
        self.value = arg;
    }
}
impl Trait<&mut u32> for Struct {
    fn method(&self, arg: &mut u32) {
        *arg = self.value;
    }
}

显然,这里无法工作,因为第二个实现块的方法签名与trait不同。我已经尝试使用arbitrary_self_types功能将self参数定义为trait中的另一个通用参数,但不幸的是,这并没有起作用。


那么你有什么问题? - Herohtar
此外,泛型不是重载。Rust 没有函数重载。 - Herohtar
那么问题是,我如何让这段代码工作起来:fn main() {
let s = Struct { value: 0 }; let mut v = 0; s.method(&mut v); println!("The value of s is: {}", v); } 而不破坏 fn main() {
let mut s = Struct { value: 0 }; s.method(34); }
- Goldenprime
如果不是重载,那么在Rust中,对于同名但针对不同参数集有不同实现的方法,正确的表达式是什么? - Goldenprime
那只是泛型。函数重载意味着你有相同的方法名称,但参数数量不同。泛型允许你拥有一个接受不同类型参数的方法,并且可以根据类型进行不同的实现。 - Herohtar
显示剩余2条评论
1个回答

3

您不能通过参数化来处理可变性。

参见:

您可以在self上进行参数化,但它将不再是一个方法,而只是关联函数:

pub trait Trait<This, T> {
    fn method(this: This, arg: T);
}
impl Trait<&mut Self, u32> for Struct {
    fn method(this: &mut Self, arg: u32) {
        this.value = arg;
    }
}
impl Trait<&Self, &mut u32> for Struct {
    fn method(this: &Self, arg: &mut u32) {
        *arg = this.value;
    }
}

fn main() {
    let mut s = Struct { value: 0 };
    let mut v = 0;
    Struct::method(&s, &mut v);
    println!("The value of s is: {}", v);
    Struct::method(&mut s, 3);
    Struct::method(&s, &mut v);
    println!("The value of s is: {}", v);
}

给定草案RFC 精炼的特质实现,提出了在特质实现中可能会出现“精炼”特质的可能性,即编写一个不太通用的impl(例如,在特质中不安全的impl中是安全的方法),将来也许有可能精炼可变性(尽管我没有看到相关讨论),但这只会放宽使用具体实例时的限制,而不是泛型。

无论如何,我认为这个设计是不正确的。只需使用普通的value()set_value()方法,它们简单明了。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接