# 方法語法
> [method-syntax.md](https://github.com/rust-lang/rust/blob/master/src/doc/book/method-syntax.md)
commit 6ba952020fbc91bad64be1ea0650bfba52e6aab4
函數是偉大的,不過如果你在一些數據上調用了一堆函數,這將是令人尷尬的。考慮下面代碼:
~~~
baz(bar(foo));
~~~
我們可以從左向右閱讀,我們會看到“baz bar foo”。不過這不是函數被調用的順序,調用應該是從內向外的:“foo bar baz”。如果能這么做不是更好嗎?
~~~
foo.bar().baz();
~~~
幸運的是,正如對上面那個問題的猜測,你可以!Rust 通過`impl`關鍵字提供了使用*方法調用語法*(*method call syntax*)。
### 方法調用
這是它如何工作的:
~~~
struct Circle {
x: f64,
y: f64,
radius: f64,
}
impl Circle {
fn area(&self) -> f64 {
std::f64::consts::PI * (self.radius * self.radius)
}
}
fn main() {
let c = Circle { x: 0.0, y: 0.0, radius: 2.0 };
println!("{}", c.area());
}
~~~
這會打印`12.566371`。
我們創建了一個代表圓的結構體。我們寫了一個`impl`塊,并且在里面定義了一個方法,`area`。
方法的第一參數比較特殊,`&self`。它有3種變體:`self`,`&self`和`&mut self`。你可以認為這第一個參數就是`x.foo()`中的`x`。這3種變體對應`x`可能的3種類型:`self`如果它只是棧上的一個值,`&self`如果它是一個引用,然后`&mut self`如果它是一個可變引用。因為我們我們的`area`以`&self`作為參數,我們就可以可以像其他參數那樣使用它。因為我們知道是一個`Circle`,我們可以像任何其他結構體那樣訪問`radius`字段。
我們應該默認使用`&self`,就像相比獲取所有權你應該更傾向于借用,同樣相比獲取可變引用更傾向于不可變引用一樣。這是一個三種變體的例子:
~~~
struct Circle {
x: f64,
y: f64,
radius: f64,
}
impl Circle {
fn reference(&self) {
println!("taking self by reference!");
}
fn mutable_reference(&mut self) {
println!("taking self by mutable reference!");
}
fn takes_ownership(self) {
println!("taking ownership of self!");
}
}
~~~
你可以有任意多個`impl`塊。上面的例子也可以被寫成這樣:
~~~
struct Circle {
x: f64,
y: f64,
radius: f64,
}
impl Circle {
fn reference(&self) {
println!("taking self by reference!");
}
}
impl Circle {
fn mutable_reference(&mut self) {
println!("taking self by mutable reference!");
}
}
impl Circle {
fn takes_ownership(self) {
println!("taking ownership of self!");
}
}
~~~
### 鏈式方法調用(Chaining method calls)
現在我們知道如何調用方法了,例如`foo.bar()`。那么我們最開始的那個例子呢,`foo.bar().baz()`?我們稱這個為“方法鏈”,我們可以通過返回`self`來做到這點。
~~~
struct Circle {
x: f64,
y: f64,
radius: f64,
}
impl Circle {
fn area(&self) -> f64 {
std::f64::consts::PI * (self.radius * self.radius)
}
fn grow(&self, increment: f64) -> Circle {
Circle { x: self.x, y: self.y, radius: self.radius + increment }
}
}
fn main() {
let c = Circle { x: 0.0, y: 0.0, radius: 2.0 };
println!("{}", c.area());
let d = c.grow(2.0).area();
println!("{}", d);
}
~~~
注意返回值:
~~~
# struct Circle;
# impl Circle {
fn grow(&self, increment: f64) -> Circle {
# Circle } }
~~~
我們看到我們返回了一個`Circle`。通過這個函數,我們可以增長一個圓的面積到任意大小。
### 關聯函數(Associated functions)
我們也可以定義一個不帶`self`參數的關聯函數。這是一個Rust代碼中非常常見的模式:
~~~
struct Circle {
x: f64,
y: f64,
radius: f64,
}
impl Circle {
fn new(x: f64, y: f64, radius: f64) -> Circle {
Circle {
x: x,
y: y,
radius: radius,
}
}
}
fn main() {
let c = Circle::new(0.0, 0.0, 2.0);
}
~~~
這個*關聯函數*(*associated function*)為我們構建了一個新的`Circle`。注意靜態函數是通過`Struct::method()`語法調用的,而不是`ref.method()`語法。
### 創建者模式(Builder Pattern)
我們說我們需要我們的用戶可以創建圓,不過我們只允許他們設置他們關心的屬性。否則,`x`和`y`將是`0.0`,并且`radius`將是`1.0`。Rust 并沒有方法重載,命名參數或者可變參數。我們利用創建者模式來代替。它看起像這樣:
~~~
struct Circle {
x: f64,
y: f64,
radius: f64,
}
impl Circle {
fn area(&self) -> f64 {
std::f64::consts::PI * (self.radius * self.radius)
}
}
struct CircleBuilder {
x: f64,
y: f64,
radius: f64,
}
impl CircleBuilder {
fn new() -> CircleBuilder {
CircleBuilder { x: 0.0, y: 0.0, radius: 1.0, }
}
fn x(&mut self, coordinate: f64) -> &mut CircleBuilder {
self.x = coordinate;
self
}
fn y(&mut self, coordinate: f64) -> &mut CircleBuilder {
self.y = coordinate;
self
}
fn radius(&mut self, radius: f64) -> &mut CircleBuilder {
self.radius = radius;
self
}
fn finalize(&self) -> Circle {
Circle { x: self.x, y: self.y, radius: self.radius }
}
}
fn main() {
let c = CircleBuilder::new()
.x(1.0)
.y(2.0)
.radius(2.0)
.finalize();
println!("area: {}", c.area());
println!("x: {}", c.x);
println!("y: {}", c.y);
}
~~~
我們在這里又聲明了一個結構體,`CircleBuilder`。我們給它定義了一個創建者函數。我們也在`Circle`中定義了`area()`方法。我們還定義了另一個方法`CircleBuilder: finalize()`。這個方法從構造器中創建了我們最后的`Circle`。現在我們使用類型系統來強化我們的考慮:我們可以用`CircleBuilder`來強制生成我們需要的`Circle`。
- 前言
- 貢獻者
- 1.介紹
- 2.準備
- 3.學習 Rust
- 3.1.猜猜看
- 3.2.哲學家就餐問題
- 3.3.其它語言中的 Rust
- 4.語法和語義
- 4.1.變量綁定
- 4.2.函數
- 4.3.原生類型
- 4.4.注釋
- 4.5.If語句
- 4.6.循環
- 4.7.所有權
- 4.8.引用和借用
- 4.9.生命周期
- 4.10.可變性
- 4.11.結構體
- 4.12.枚舉
- 4.13.匹配
- 4.14.模式
- 4.15.方法語法
- 4.16.Vectors
- 4.17.字符串
- 4.18.泛型
- 4.19.Traits
- 4.20.Drop
- 4.21.if let
- 4.22.trait 對象
- 4.23.閉包
- 4.24.通用函數調用語法
- 4.25.crate 和模塊
- 4.26.const和static
- 4.27.屬性
- 4.28.type別名
- 4.29.類型轉換
- 4.30.關聯類型
- 4.31.不定長類型
- 4.32.運算符和重載
- 4.33.Deref強制多態
- 4.34.宏
- 4.35.裸指針
- 4.36.不安全代碼
- 5.高效 Rust
- 5.1.棧和堆
- 5.2.測試
- 5.3.條件編譯
- 5.4.文檔
- 5.5.迭代器
- 5.6.并發
- 5.7.錯誤處理
- 5.8.選擇你的保證
- 5.9.外部函數接口
- 5.10.Borrow 和 AsRef
- 5.11.發布途徑
- 5.12.不使用標準庫
- 6.Rust 開發版
- 6.1.編譯器插件
- 6.2.內聯匯編
- 6.4.固有功能
- 6.5.語言項
- 6.6.鏈接進階
- 6.7.基準測試
- 6.8.裝箱語法和模式
- 6.9.切片模式
- 6.10.關聯常量
- 6.11.自定義內存分配器
- 7.詞匯表
- 8.語法索引
- 9.參考文獻
- 附錄:名詞中英文對照