鍍金池/ 教程/ Java/ <code>Deref</code> 強制多態(tài)
哲學家就餐問題
鏈接進階
名詞中英文對照
測試
引用和借用
泛型
方法語法
函數(shù)
不安全代碼
并發(fā)
裝箱語法和模式
注釋
棧和堆
運算符與重載
語法索引
文檔
固有功能
所有權
循環(huán)
通用函數(shù)調用語法
不定長類型
<code>const</code> 和 <code>static</code>
迭代器
其他語言中的 Rust
枚舉
詞匯表
If語句
猜猜看
錯誤處理
生命周期
編譯器插件
發(fā)布途徑
閉包
trait 對象
不使用標準庫
關聯(lián)常量
外部函數(shù)接口(FFI)
類型轉換
原生類型
匹配
參考文獻
Rust 編程語言
內聯(lián)匯編
條件編譯
選擇你的保證
學習 Rust
`type`別名
自定義內存分配器
屬性
if let
高效 Rust
可變性
語法和語義
模式
基準測試
結構體
變量綁定
語言項
切片模式
<code>Deref</code> 強制多態(tài)
關聯(lián)類型
裸指針
<code>Borrow</code> 和 <code>AsRef</code>
準備
Rust 開發(fā)版
字符串

<code>Deref</code> 強制多態(tài)

deref-coercions.md
commit 024aa9a345e92aa1926517c4d9b16bd83e74c10d

標準庫提供了一個特殊的特性,Deref。它一般用來重載*,解引用運算符:

use std::ops::Deref;

struct DerefExample<T> {
    value: T,
}

impl<T> Deref for DerefExample<T> {
    type Target = T;

    fn deref(&self) -> &T {
        &self.value
    }
}

fn main() {
    let x = DerefExample { value: 'a' };
    assert_eq!('a', *x);
}

這對編寫自定義指針類型很有用。然而,有一個與Deref相關的語言功能:“解引用強制多態(tài)(deref coercions)”。規(guī)則如下:如果你有一個U類型,和它的實現(xiàn)Deref<Target=T>,(那么)&U的值將會自動轉換為&T。這是一個例子:

fn foo(s: &str) {
    // borrow a string for a second
}

// String implements Deref<Target=str>
let owned = "Hello".to_string();

// therefore, this works:
foo(&owned);

在一個值的前面用&號獲取它的引用。所以owned是一個String,&owned是一個&String,而因為impl Deref<Target=str> for String,&String將會轉換為&str,而它是foo()需要的。

這就是了。這是Rust唯一一個為你進行一個自動轉換的地方,不過它增加了很多靈活性。例如,Rc<T>類型實現(xiàn)了Deref<Target=T>,所以這可以工作:

use std::rc::Rc;

fn foo(s: &str) {
    // borrow a string for a second
}

// String implements Deref<Target=str>
let owned = "Hello".to_string();
let counted = Rc::new(owned);

// therefore, this works:
foo(&counted);

我們所做的一切就是把我們的String封裝到了一個Rc<T>里。不過現(xiàn)在我們可以傳遞Rc<String>給任何我們有一個String的地方。foo的簽名并無變化,不過它對這兩個類型都能正常工作。這個例子有兩個轉換:Rc<String>轉換為String接著是String轉換為&str。只要類型匹配Rust將可以做任意多次這樣的轉換。

標準庫提供的另一個非常通用的實現(xiàn)是:

fn foo(s: &[i32]) {
    // borrow a slice for a second
}

// Vec<T> implements Deref<Target=[T]>
let owned = vec![1, 2, 3];

foo(&owned);

向量可以Deref為一個切片。

Deref和方法調用

當調用一個方法時Deref也會出現(xiàn)。考慮下面的例子:

struct Foo;

impl Foo {
    fn foo(&self) { println!("Foo"); }
}

let f = &&Foo;

f.foo();

即便f&&Foo,而foo接受&self,這也是可以工作的。因為這些都是一樣的:

f.foo();
(&f).foo();
(&&f).foo();
(&&&&&&&&f).foo();

一個&&&&&&&&&&&&&&&&Foo類型的值仍然可以調用Foo定義的方法,因為編譯器會插入足夠多的*來使類型正確。而正因為它插入*,它用了Deref。

上一篇:結構體下一篇:if let