Rust 如何将可变引用转换为通用特征中的不可变引用?

问题描述 投票:0回答:1

我试图为自定义结构实现

From
特征,以便将其从 reference 构建到另一个结构:

struct Base { ...properties }

struct Derived { ...other_properties }

impl From<&Base> for Derived {
    fn from(value: &Base) -> Self {
        Self { ... }
    }
}

一切都很好,直到我尝试在函数内调用它,并以

Base
实例的可变引用作为参数:

fn foo(base: &mut Base) {
    ...do stuff on base
    let derived = Derived::from(base);
}

我认为编译器可以检测到具有相同类型的引用并将其作为不可变而不是可变传递,这样就可以了,但我却遇到了编译错误:

不满足特质界限

Derived: From<&mut Base>
特征
From<&Base>
是针对
Derived

实现的

然后,我尝试用自己的代码重现该问题,因此我创建了一个特征

CustomFrom
,其中包含一个与
from
特征中的
From
具有相同签名的函数:

trait CustomFrom<T> {
    fn custom_from(base: T) -> Self;
}

并实施它:

impl CustomFrom<&Base> for Derived {
    fn custom_from(value: &Base) -> Self {
        Self { ... }
    }
}

并以与最初的

from
相同的方式命名它:

fn foo(base: &mut Base) {
    ...do stuff on base
    let derived = Derived::from(base);
    let custom = Derived::custom_from(base);

}

除了这次编译器对我的自定义特征使用没问题。

我知道我可以通过使用

Derived::from(& *base);
拨打电话来解决问题,但我想知道:

这两个特征有什么区别?

为什么编译器能够使用我的特征而不是标准特征的不可变引用?

完整的最小示例:

struct Base {
    a: u8,
    b: u8,
    c: u8,
    d: u8,
    e: u8,
    f: u8,
}

trait CustomFrom<T> {
    fn custom_from(param: T) -> Self;
}

impl Base {
    fn new(a: u8, b: u8, c: u8, d: u8, e: u8, f: u8) -> Self {
        Self { a, b, c, d, e, f }
    }
    fn a(&self) -> &u8 {
        &self.a
    }
    fn c(&self) -> &u8 {
        &self.c
    }
    fn d(&self) -> &u8 {
        &self.d
    }
}

struct Derived {
    a: u8,
    c: u8,
    d: u8,
}

impl From<&Base> for Derived {
    fn from(base: &Base) -> Self {
        Self {
            a: *base.a(),
            c: *base.c(),
            d: *base.d()
        }
    }
}

impl CustomFrom<&Base> for Derived {
    fn custom_from(base: &Base) -> Self {
        Self {
            a: *base.a(),
            c: *base.c(),
            d: *base.d()
        }
    }
}

fn main() {
    let mut base = Base::new(1, 2, 3, 4, 5, 6);
    let ex = Derived::from(&base);
}

fn foo(base: &mut Base) {
    let test1 = Derived::from(base);
    let test2 = Derived::custom_from(base);
}

fn bar(mut base: Base) {
    let test1 = Derived::from(&base);
    let test2 = Derived::custom_from(&base);
}
rust ref
1个回答
1
投票

您的

CustomFrom
复制似乎有效,因为如果特征只有一个实现,编译器可以进行额外的扣除。如果您引入另一种实现,例如
impl CustomFrom<()> for Derived
,那么它也不适用于
&mut Base
:

error[E0277]: the trait bound `Derived: CustomFrom<&mut Base>` is not satisfied
  --> src/main.rs:72:17
   |
72 |     let test2 = Derived::custom_from(base);
   |                 ^^^^^^^ the trait `CustomFrom<&mut Base>` is not implemented for `Derived`
   |
   = help: the following other types implement trait `CustomFrom<T>`:
             <Derived as CustomFrom<&Base>>
             <Derived as CustomFrom<()>>

游乐场链接

除此之外,编译器通常不会执行任何强制转换(如

&mut T
&T
)来找到合适的特征实现。

© www.soinside.com 2019 - 2024. All rights reserved.