此代码无法编译:
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
为什么会这样?
例如,对于像
这样的新类型,这可能很有用struct MyInt(i32);
impl AsRef<i32> for MyInt {
/* etc. */
}
然后你可以无动于衷地传递i32
上的引用或MyInt
上的引用,因为在内存中我们都有i32
。
答案 0 :(得分:3)
AsRef
和Borrow
乍一看非常相似,但它们用于不同的事情。 The Book很好地描述了它们之间的区别:
如果要抽象不同类型,请选择
Borrow
借用,或者当你构建一个对待所拥有的数据结构时 并以等价的方式借用价值,例如哈希和 比较。如果要将某些内容转换为引用,请选择
AsRef
直接,你正在编写通用代码。
在您的情况下,Borrow
是一个更合理的选择,因为不涉及转换。
关于为什么AsRef
没有在不同的整数类型之间实现的问题,我想这会违背Rust对表现形式的表达;我认为这与问题Why can't I compare two integers of different types?类似。
答案 1 :(得分:3)
这里是authoritative answer by Aaron Turon:
Borrow
提供了一个全面的实现T: Borrow<T>
,它是必不可少的,用于使上述集合正常工作。AsRef
提供了一个不同的覆盖实现,基本上是&T: AsRef<U>
的{{1}},这对于像T: AsRef<U>
这样可以使用更简单,更灵活的签名的API来说非常重要。由于一致性,您不能同时拥有全部的实现,因此每个特征都在做出适合其用例的选择。
答案 2 :(得分:2)
我认为这是AsRef
和Borrow
之间的差异之一。
也就是说,Borrow<T>
直接针对&T
实施,而AsRef<T>
未针对&T
实施。
有趣的是,如果T实现AsRef<U>
,则&T
会为AsRef<U>
实施。也就是说,如果您可以将AsRef
与类型一起使用,则可以在同一时间引用它。
另一个有趣的事情是Borrow<T>
已经为&T
实施,但也为T
实施了!