Rust那些事之Borrow VS AsRef

最近看到两个trait长得挺像,带着疑惑前来学习一下。

Borrow VS AsRef

Borrow与AsRef是Rust中非常相似的两个trait,分别是:

go 复制代码
pub trait Borrow<Borrowed: ?Sized> {
    fn borrow(&self) -> &Borrowed;
}

pub trait AsRef<T: ?Sized> {
    fn as_ref(&self) -> &T;
}

可以看到这两个从接口层面是一样的。

使用方式如下:

go 复制代码
let s = String::from("Hello World");
let s_ref: &str = s.borrow(); // using Borrow
let s_ref: &str = s.as_ref(); // using AsRef

那么问题来的,什么时候使用Borrow,什么时候使用AsRef呢?

1.trait一致性

  • Borrow also requires that Hash, Eq and Ord for a borrowed value are equivalent to those of the owned value. For this reason, if you want to borrow only a single field of a struct you can implement AsRef, but not Borrow.

Borrow 还要求对于借用值的HashEqOrd 与拥有值相等。因此,如果你只想借用结构体的单个字段,你可以实现 AsRef,但不能实现 Borrow

如果类型T1实现了Borrow<T2>,在为T1实现一些特殊的trait(例如:Eq、Ord、Hash)时,其行为应该与T2有相同的行为。

例如:标准库 HashMap 对 get() 和 get_mut() 方法使用了Borrow 特征。K是HashMap的key,而get接收的是k类型是&Q

例如:HashMap<String, xx>,K就是String,Q就是str,这允许我们可以传递任何可以作为 K 借用的类型 Q。通过额外要求 Q: Hash + Eq,它表明要求 K 和 Q 具有产生相同结果的 Hash 和 Eq trait的实现。

go 复制代码
impl<K, V> HashMap<K, V> {
    pub fn get<Q>(&self, k: &Q) -> Option<&V>
    where
        K: Borrow<Q>,
        Q: Hash + Eq + ?Sized
    {
        // ...
    }
}

https://doc.rust-lang.org/std/borrow/trait.Borrow.html

2.默认实现

  • Unlike AsRef, Borrow has a blanket impl for any T, and can be used to accept either a reference or a value. (See also note on AsRef's reflexibility below.)

AsRef 不同,Borrow 为任何 T 都有一个默认实现,并且可以用来接受引用或值。

例如:使用Borrow下面代码可以正常工作。

go 复制代码
use std::borrow::Borrow;

fn print_value<T: Borrow<i32>>(value: T) {
    println!("Value is: {}", value.borrow());
}

fn main() {
    let number = 42;
    print_value(&number); 
    print_value(number); 
}

而如果使用AsRef,则不可以,报错:

go 复制代码
the trait `std::convert::AsRef<i32>` is not implemented for `{integer}`

示例:

go 复制代码
fn print_value<T: AsRef<i32>>(value: T) {
    println!("Value is: {}", value.as_ref());
}

fn main() {
    let number = 42;
    print_value(&number); 
    print_value(number); 
}

https://doc.rust-lang.org/std/convert/trait.AsRef.html#relation-to-borrow


往期回顾:

我的春招求职面经

热度更新,手把手实现工业级线程池

相关推荐
yufei-coder2 分钟前
C#基础语法
开发语言·c#·.net
长天一色2 分钟前
【ECMAScript 从入门到进阶教程】第三部分:高级主题(高级函数与范式,元编程,正则表达式,性能优化)
服务器·开发语言·前端·javascript·性能优化·ecmascript
_.Switch14 分钟前
Python机器学习模型的部署与维护:版本管理、监控与更新策略
开发语言·人工智能·python·算法·机器学习
醉颜凉16 分钟前
银河麒麟桌面操作系统修改默认Shell为Bash
运维·服务器·开发语言·bash·kylin·国产化·银河麒麟操作系统
NiNg_1_23422 分钟前
Vue3 Pinia持久化存储
开发语言·javascript·ecmascript
带带老表学爬虫31 分钟前
java数据类型转换和注释
java·开发语言
qianbo_insist33 分钟前
simple c++ 无锁队列
开发语言·c++
千里码aicood38 分钟前
【2025】springboot教学评价管理系统(源码+文档+调试+答疑)
java·spring boot·后端·教学管理系统
QMCY_jason40 分钟前
Ubuntu 安装RUST
linux·ubuntu·rust
BigYe程普44 分钟前
我开发了一个出海全栈SaaS工具,还写了一套全栈开发教程
开发语言·前端·chrome·chatgpt·reactjs·个人开发