直接回答:两者签名几乎相同(fn as_ref(&self) -> &T / fn borrow(&self) -> &T),区别在语义契约:Borrow<T> 要求借出的 &T 与原类型在 Hash/Eq/Ord 上行为完全一致——是“同一身份”的借用;AsRef<T> 只是廉价引用转换,不做这种保证,表达的是“可以看作”。
展开解析:Borrow 的存在是为了 HashMap<String, V>::get(&str) 这类 API:key 是 String,查询却传 &str,map 必须保证对二者算出相同哈希、判定相同相等,因此查询类型要满足 String: Borrow<Q>——违反它就会出现“明明插入了却查不到”的诡异 bug。AsRef 的典型用法是参数多态:fn open(p: impl AsRef<Path>) 能同时接受 &str、String、PathBuf,std 的文件 API 大量采用。设计原则:集合类型的查找接口用 Borrow 约束,普通入参多态用 AsRef。
let mut m: HashMap<String, i32> = HashMap::new();
m.insert("k".to_string(), 1);
m.get("k"); // 能传 &str,靠 String: Borrow<str>
追问方向:为什么 Eq/Hash 一致性是 Borrow 的硬性要求?Cow 与这两个 trait 的关系?Deref 与 AsRef 怎么选?
(约 560 字)