Rust那些事之Borrow VS AsRef​

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云原生数据库 PolarDB MySQL 版,Serverless 5000PCU 100GB
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
简介: 【4月更文挑战第3天】Rust中的Borrow和AsRef是相似的trait,都提供了一个方法来获取引用。Borrow需要借用值的Hash、Eq和Ord与拥有值相等,适合结构体的单字段借用;而AsRef无此限制,有默认实现,可接受引用或值。当需要特殊trait一致性时(如HashMap的键值比较),使用Borrow;当仅需简单引用转换时,使用AsRef。

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

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

pub trait Borrow<Borrowed: ?Sized> {
   
    fn borrow(&self) -> &Borrowed;
}

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

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

使用方式如下:


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 还要求对于借用值的Hash、Eq 和 Ord 与拥有值相等。因此,如果你只想借用结构体的单个字段,你可以实现 AsRef,但不能实现 Borrow。

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

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

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


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

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下面代码可以正常工作。


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,则不可以,报错:


the trait `std::convert::AsRef<i32>` is not implemented for `{integer}`

示例:


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); 
}
目录
相关文章
|
1月前
|
Rust 安全 程序员
Rust vs Go:解析两者的独特特性和适用场景
在讨论 Rust 与 Go 两种编程语言哪种更优秀时,我们将探讨它们在性能、简易性、安全性、功能、规模和并发处理等方面的比较。同时,我们看看它们有什么共同点和根本的差异。现在就来看看这个友好而公平的对比。
|
1月前
|
存储 缓存 Rust
【Rust】——所有权:Stack(栈内存)vs Heap(堆内存)(重点)
【Rust】——所有权:Stack(栈内存)vs Heap(堆内存)(重点)
33 0
|
10月前
|
Rust Go C++
Rust vs Go:常用语法对比(十三)(1)
Rust vs Go:常用语法对比(十三)(1)
67 0
|
10月前
|
Rust Go C++
Rust vs Go:常用语法对比(七)(1)
Rust vs Go:常用语法对比(七)(1)
49 0
|
10月前
|
Rust Go C++
Rust vs Go:常用语法对比(四)(1)
Rust vs Go:常用语法对比(四)(1)
126 0
|
10月前
|
Rust Go C++
Rust vs Go:常用语法对比(十三)(2)
Rust vs Go:常用语法对比(十三)(2)
79 1
|
10月前
|
Rust Go C++
Rust vs Go:常用语法对比(十二)(2)
Rust vs Go:常用语法对比(十二)(2)
64 0
|
10月前
|
Rust Go C++
Rust vs Go:常用语法对比(十二)(1)
Rust vs Go:常用语法对比(十二)(1)
72 0
|
10月前
|
Rust Go C++
Rust vs Go:常用语法对比(十一)(2)
Rust vs Go:常用语法对比(十一)(2)
58 0
|
10月前
|
Rust Go C++
Rust vs Go:常用语法对比(十一)(1)
Rust vs Go:常用语法对比(十一)(1)
49 0