此代码无法编译:
fn ref_on_int<T>(_: T) where T: AsRef<i32> {}
fn main() {
ref_on_int(&0_i32)
}
因为
the trait bound `i32: std::convert::AsRef<i32>` is not satisfied
为什么会这样?
例如,对于像new这样的新类型,这可能很有用
struct MyInt(i32);
impl AsRef<i32> for MyInt {
/* etc. */
}
那么你可以无差别地传递关于i32
或MyInt
上的引用的引用,因为在记忆中我们在两种情况下都有i32
。
AsRef
和Borrow
乍一看非常相似,但它们用于不同的事物。 The Book很好地描述了它们之间的区别:
当您想要抽象不同类型的借用时,或者当您构建一个以等效方式处理拥有和借用值的数据结构时,例如散列和比较,请选择
Borrow
。如果要直接将某些内容转换为引用,并选择编写通用代码,请选择
AsRef
。
在你的情况下,Borrow
是一个更合理的选择,因为没有涉及转换。
至于为什么AsRef
没有在不同的整数类型之间实现的问题,我想这会违背Rust对于演员表达的意图;我认为这与问题Why can't I compare two integers of different types?相似。
这是一个authoritative answer by Aaron Turon:
Borrow
提供了一个全面的实施T: Borrow<T>
,这对于使上述收藏品运作良好至关重要。AsRef
提供了一个不同的毯子实现,基本上&T: AsRef<U>
每当T: AsRef<U>
,这对fs::open
这样的API很重要,因为它可以使用更简单和更灵活的签名。由于连贯性,您不能同时使用这两种实现,因此每个特征都在做出适合其用例的选择。
我认为这是AsRef
和Borrow
的差异之一。
也就是说,Borrow<T>
直接用于&T
,而AsRef<T>
没有用于&T
。
有趣的是,如果T实施AsRef<U>
,&T
是为AsRef<U>
实施的。也就是说,如果您可以将AsRef
与类型一起使用,则可以在同一时间引用它。
另一个有趣的事情是Borrow<T>
是为&T
实施的,但也为T
实施!