Deref coercion澄清解释

3

考虑以下示例:

fn main() {
    let string: String = "A string".to_string();
    let string_ref: &String = &string;
    let str_ref_a: &str = string_ref;  // A
    let str_ref_b: &str = &string;     // B
}

这两行代码有什么不同呢?string_ref&String类型,因此我理解在第A行中我们使用了Deref coercion。那么第B行呢?可以说它与Deref coercion无关,只是因为这个原因直接借用了一个String作为str吗?

impl Borrow<str> for String {
    #[inline]
    fn borrow(&self) -> &str {
        &self[..]
    }
}
2个回答

2
不。这两行都涉及到解引用强制转换。
Borrow特质在任何方面都不是特殊的 - 它不为编译器所知(不是语言项)。而Deref特质是已知的。
“Deref”和“Borrow”(以及“AsRef”)之间的区别在于,“Deref”只能对一个类型实现一次(因为“Target”是相关类型而不是泛型参数),而“AsRef”(和“Borrow”)需要一个泛型参数,因此可以多次实现。这是因为“Deref”是用于智能指针的:如果我是一个T,就应该实现Deref<Target = T>(请注意,“智能指针”的准确定义正在变化)。Stringstr(加上了其他功能),Vecslice。Box<T>T
另一方面,AsRefBorrow 是转换特征。如果我可以被视为 T,则应该实现 AsRef<T>。例如,String 可以被视为 str。但是,以 strOsStr 为例。 str 不是一个 OsStr,但如果它是,就可以像它一样对待它。因此它实现了 AsRef<OsStr>BorrowAsRef 相同,只是它有额外的要求(即,它应具有与原始值相同的 EqHashOrd)。

好的。但是,impl Borrow<str> for String 的目的是什么?在什么情况下会调用它的 borrow() 函数?可以说字符串中的 deref coercion 使得对 string.borrow() 的显式调用有些无意义吗? - at54321
@at54321 已添加解释。 - Chayim Friedman
如果我理解得正确的话,在 Deref trait 中的 Target 也可以是泛型类型(不一定是具体类型)。书中的代码示例展示了 Deref 的实现。 - Ham
@Ham 是的,这是真的,就像任何关联类型一样。 - Chayim Friedman

1

这两种方法本质上是等价的,都涉及到解引用强制转换:

let str_ref_a: &str = string_ref;  // A
let str_ref_b: &str = &string;     // B

上面的值string是类型为String的,所以表达式&string是类型为&String的,由于String实现了Deref<Target=str>,因此进行deref coercion后转换为&str
关于你提出的有关Borrow的问题:不,你没有在string值上调用borrow()。相反,应该这样写:
let str_ref_b: &str = string.borrow(); // Borrow::borrow() on String

也就是说,与deref()不同的是,调用borrow()并不会自动插入。


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