Rust:Borrow/BorrowMut trait

708 阅读3分钟

Borrow/BorrowMut trait的定义和作用

BorrowBorrowMut是Rust标准库中的两个trait,它们用于抽象出借用类型的行为。

Borrow trait定义了一个borrow方法,该方法接受一个&self参数,并返回一个不可变引用。它通常用于实现类型之间的借用关系。

use std::borrow::Borrow;

fn check<T: Borrow<str>>(s: T) {
    assert_eq!("Hello", s.borrow());
}

fn main() {
    let s = "Hello".to_string();
    check(s);
}

上面的代码定义了一个check函数,它接受一个泛型参数T,该参数必须实现了Borrow<str> trait。在函数体内,我们调用了s.borrow()方法来获取一个不可变引用。

与此类似,BorrowMut trait定义了一个borrow_mut方法,该方法接受一个&mut self参数,并返回一个可变引用。它通常用于实现类型之间的可变借用关系。

use std::borrow::BorrowMut;

fn check<T: BorrowMut<[i32]>>(mut s: T) {
    s.borrow_mut()[0] = 42;
}

fn main() {
    let mut v = vec![0, 1, 2];
    check(&mut v);
    assert_eq!(42, v[0]);
}

上面的代码定义了一个check函数,它接受一个泛型参数T,该参数必须实现了BorrowMut<[i32]> trait。在函数体内,我们调用了s.borrow_mut()方法来获取一个可变引用。

如何在自定义类型中实现Borrow/BorrowMut trait

要在自定义类型中实现Borrow/BorrowMut trait,我们需要为该类型定义一个borrowborrow_mut方法。例如,下面是一个简单的结构体和它对Borrow/BorrowMut trait的实现:

use std::borrow::{Borrow, BorrowMut};

struct Wrapper<T>(T);

impl<T> Borrow<T> for Wrapper<T> {
    fn borrow(&self) -> &T {
        &self.0
    }
}

impl<T> BorrowMut<T> for Wrapper<T> {
    fn borrow_mut(&mut self) -> &mut T {
        &mut self.0
    }
}

fn main() {
    let w = Wrapper(42);
    assert_eq!(42, *w.borrow());
    
    let mut w = Wrapper(0);
    *w.borrow_mut() = 42;
    assert_eq!(42, *w.borrow());
}

上面的代码定义了一个Wrapper结构体,并为它实现了Borrow和BorrowMut trait。在borrow和borrow_mut方法中,我们分别返回了对内部数据的不可变和可变引用。

Borrow/BorrowMut trait在标准库中的应用

Rust标准库中有许多地方使用了Borrow和BorrowMut trait。例如,在集合类型(如HashMap、BTreeMap等)中,我们可以使用任何实现了Borrow trait的类型作为键来查找元素。

use std::collections::HashMap;

let mut map = HashMap::new();
map.insert("foo".to_string(), 42);

assert_eq!(map.get("foo"), Some(&42));

上面的代码创建了一个HashMap,并插入了一对键值对。在调用get方法时,我们使用了一个字符串字面量作为键。由于字符串字面量实现了Borrow trait,所以我们可以直接使用它来查找元素。

Borrow/BorrowMut trait和其他trait的区别

除了Borrow/BorrowMut trait之外,Rust还提供了其他几种trait,如AsRef、AsMut等。这些trait都用于抽象出类型之间的转换关系,但它们之间有一些区别。

例如,AsRef trait定义了一个as_ref方法,该方法接受一个&self参数,并返回一个不可变引用。它通常用于将类型转换为不可变引用。

与此类似,AsMut trait定义了一个as_mut方法,该方法接受一个&mut self参数,并返回一个可变引用。它通常用于将类型转换为可变引用。

Borrow/BorrowMut和AsRef/AsMut都是Rust标准库中的trait,它们都用于抽象出类型之间的转换关系。但它们之间有一些区别:前者用于实现借用关系,后者则用于实现转换关系。

实例演示

下面是一个简单的例子,演示如何使用Borrow/BorrowMut trait来抽象出借用关系:

use std::borrow::{Borrow, BorrowMut};

#[derive(Debug)]
struct Person {
    name: String,
    age: u8,
}

impl Borrow<String> for Person {
    fn borrow(&self) -> &String {
        &self.name
    }
}

impl Borrow<u8> for Person {
    fn borrow(&self) -> &u8 {
        &self.age
    }
}

impl BorrowMut<u8> for Person {
    fn borrow_mut(&mut self) -> &mut u8 {
        &mut self.age
    }
}

fn main() {
    let alice = Person {
        name: "Alice".to_string(),
        age: 30,
    };
    
    assert_eq!("Alice", alice.borrow());
    
    let mut bob = Person {
        name: "Bob".to_string(),
        age: 40,
    };
    
    *bob.borrow_mut() += 1;
    
    assert_eq!(41, *bob.borrow());
}

上面的代码定义了一个Person结构体,并为它实现了Borrow和BorrowMut trait。在main函数中,我们创建了两个Person实例,并使用了borrow和borrow_mut方法来获取对内部数据的引用。 from刘金,转载请注明原文链接。感谢!