方法語(yǔ)法

2018-08-12 22:03 更新

方法語(yǔ)法

函數(shù)很好,但是如果你想要在一些數(shù)據(jù)上調(diào)用很多函數(shù),那是非常不合適的。請(qǐng)思考以下代碼:

baz(bar(foo)));

我們從左往右讀這些代碼,就會(huì)看到 ‘baz bar foo’。但是這并不是我們由內(nèi)-外調(diào)用函數(shù)的順序:‘foo bar baz’。如果我們這樣寫(xiě),會(huì)不會(huì)更好?

foo.bar().baz();

幸運(yùn)的是,你可能已經(jīng)猜到了,關(guān)于上面問(wèn)題的答案,可以! Rust 提供了一種可以通過(guò) impl 關(guān)鍵字來(lái)使用‘方法調(diào)用語(yǔ)法’的能力。

方法調(diào)用

以下代碼展示了它是怎樣工作的:

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。

我們已經(jīng)建了一個(gè)表示一個(gè)圓的結(jié)構(gòu)體。然后我們寫(xiě)一個(gè) impl 塊,同時(shí)我們?cè)趬K中定義一個(gè)方法,area。

方法使用一個(gè)特殊的第一參數(shù),其中有三個(gè)變量:self,&self&mut self。你可以將這個(gè)第一參數(shù)想象成 foo.bar() 中的 foo。這三種變量對(duì)應(yīng)于 foo 可能成為的三種東西:如果它只是堆棧中的一個(gè)值使用 self,如果它是一個(gè)引用使用 &self,如果它是一個(gè)可變引用使用 &mut self。因?yàn)槲覀兪褂昧?&self作為 area 的參數(shù),我們可以像其他參數(shù)一樣使用它。由于我們知道它是一個(gè) Circle,我們可以像訪問(wèn)其它結(jié)構(gòu)體一樣,訪問(wèn) radius。

我們應(yīng)默認(rèn)使用 &self,同時(shí)相對(duì)于取得所有權(quán),你應(yīng)該更傾向于借用,以及使用不可變的引用來(lái)頂替可變的引用。以下是關(guān)于所有三個(gè)變量的一個(gè)例子:

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!");
}
}

鏈接方法調(diào)用

所以,至此我們知道了怎樣去調(diào)用一個(gè)方法,諸如 foo.bar()。但是我們?cè)瓉?lái)的例子 foo.bar().baz() 的例子怎么辦?這就是所謂的‘方法鏈接’,我們可以通過(guò)返回 self 來(lái)完成它。

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);
}

檢查返回類(lèi)型:

fn grow(&self) -> Circle {

我們只是說(shuō)我們返回了一個(gè) Circle。通過(guò)這個(gè)方法,我們可以將一個(gè)新的圓圈增加到任意大小。

關(guān)聯(lián)函數(shù)

你還可以定義一個(gè)不使用 self 作為參數(shù)的關(guān)聯(lián)函數(shù)。以下代碼是在 Rust 代碼中非常常見(jiàn)的一種模式:

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);
} #

這個(gè)‘關(guān)聯(lián)函數(shù)’為我們生成一個(gè)新的 Circle。請(qǐng)注意,關(guān)聯(lián)函數(shù)被 Struct::function() 語(yǔ)法調(diào)用,而不是 ref.method() 語(yǔ)法。其他一些語(yǔ)言稱(chēng)關(guān)聯(lián)函數(shù)為‘靜態(tài)方法’。

生成器模式

假如我們想要我們的用戶(hù)能夠創(chuàng)建 Circles,但是我們只允許他們?cè)O(shè)置他們關(guān)心的屬性。否則,xy 的屬性將會(huì)是 0.0,同時(shí) radius1.0。Rust 沒(méi)有方法重載,參數(shù)命名或者變量參數(shù)。我們使用生成器模式來(lái)代替它。如以下代碼所示:

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);
}

我們這里所做的就是建立了另一個(gè)結(jié)構(gòu)體,CircleBuilder。我們已經(jīng)對(duì)它定義了我們的生成器方法。我們也已經(jīng)在 Circle 上定義了我們的 area() 方法。我們又在 CircleBuilder 上定義了另一方法:finalize()。這個(gè)方法從生成器中創(chuàng)建了我們的最后的 Circle?,F(xiàn)在,我們已經(jīng)使用類(lèi)型系統(tǒng)來(lái)強(qiáng)化我們關(guān)心的事情:我們可以使用在 CircleBuilder 上的方法來(lái)限制以我們選擇的任何方式制作 Circle。

以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)