做淘寶客網(wǎng)站用什么系統(tǒng)線上推廣怎么做
一、一個(gè)實(shí)際問(wèn)題
用一個(gè)線性代數(shù)庫(kù)的求逆矩陣函數(shù)時(shí),讓我很不爽,我必須按照下面的形式寫(xiě)調(diào)用代碼:
...if let Some(inv_mat) = try_inverse(mat.clone()) {...}...
注意 try_inverse
函數(shù)的參數(shù)傳遞形式,函數(shù)參數(shù)是 mat.clone()
而不是 mat
,因?yàn)檫@個(gè) mat
變量后面我還得使用。有看了幾個(gè)其他的線性代數(shù)庫(kù),大都是按照這個(gè)形式定義的。我不得不思考一下為什么要這么干。
我們看這個(gè)函數(shù)的幾種可能的聲明形式:
fn try_inverse(mat: Mat) -> Option<Mat> {...} // .... (1)fn try_inverse(mat: &Mat) -> Option<Mat> {...} // .... (2)fn try_inverse(mat: &mut Mat) -> Option<Mat> {...} // .... (3)
下面分別討論:
1、fn try_inverse(mat: Mat) -> Option
我們有兩種辦法向函數(shù)傳遞參數(shù)。如果 mat
函數(shù)調(diào)用后不再使用,可以直接把變量所有權(quán)轉(zhuǎn)移給函數(shù),按下面形式調(diào)用:
...if let Some(inv_mat) = try_inverse(mat) {...}...
如果 mat 在函數(shù)調(diào)用后還有別的用途,必須保留變量所有權(quán),把變量克隆一份傳遞給函數(shù),按照下面的方法調(diào)用:
...if let Some(inv_mat) = try_inverse(mat.clone()) {...}...
為什么么要這樣傳遞參數(shù)?原因是,逆矩陣是在原矩陣的基礎(chǔ)上構(gòu)建出來(lái)了,這個(gè)構(gòu)建過(guò)程會(huì)逐步覆蓋掉原矩陣的數(shù)據(jù)。因此,求逆矩陣函數(shù)需要獲得參數(shù)的所有權(quán),在原矩陣基礎(chǔ)上完成逆矩陣構(gòu)建。
如果得不到所有權(quán)又如何?
2、fn try_inverse(mat: &Mat) -> Option
如果參數(shù)采用傳遞引用的方式,函數(shù)調(diào)用就變成了以下形式:
if let Some(inv_mat) = try_inverse(&mat) {...}
對(duì)我們來(lái)講很是方便,但是這里存在一個(gè)效率問(wèn)題。
無(wú)論 mat
我們后續(xù)是否使用,try_inverse()
都要首先克隆一個(gè)備份,然后在此基礎(chǔ)上構(gòu)建逆矩陣。也就是說(shuō),引用傳參,形式上看調(diào)用方式很簡(jiǎn)潔,但是運(yùn)行效率不高。而上面?zhèn)髦档姆绞?#xff0c;在參數(shù)后續(xù)不再使用時(shí),可以省去變量完整克隆的運(yùn)算時(shí)間。
那么,傳遞可修改引用可行嗎?
3、fn try_inverse(mat: &mut Mat) -> Option
答案是不可以。我們看傳入變量 &mut Mat
和返回結(jié)果 Option<Mat>
的語(yǔ)法形式就可以判斷出,函數(shù)的結(jié)果和參數(shù)必須是兩個(gè)獨(dú)立的矩陣,不可能在參數(shù)的基礎(chǔ)上構(gòu)建逆矩陣。如果想利用傳入的可變引用,函數(shù)聲明需要改成下面的形式:
fn try_inverse(mat: &mut Mat) -> Option<&Mat> {...} // .... (4)
這又涉及到變量生命周期問(wèn)題了。不難看出這個(gè)方式傳入?yún)?shù)和返回結(jié)果,是一種導(dǎo)致語(yǔ)義復(fù)雜化、后患無(wú)窮的方法。
綜上所述,函數(shù)聲明(1)是一種最合適的形式,它把參數(shù)的克隆權(quán)交給了使用者,可避免不必要的克隆。聲明(2) 雖然讓使用者感覺(jué)很簡(jiǎn)潔,但犧牲了算法效率。聲明(3)讓參數(shù)變量冒著被修改的副作用,但沒(méi)換來(lái)任何好處,所以不推薦。聲明(4)的副作用問(wèn)題多多,更不推薦。
二、函數(shù)傳參技術(shù)要點(diǎn)
1、 foo(x)
:
foo(x)
的語(yǔ)法意義
- 如果foo函數(shù)的參數(shù)是按值接收(即它需要一個(gè)所有權(quán)的拷貝),那么你可以直接傳遞x。
- 這種方式下,x的所有權(quán)會(huì)被移動(dòng)到foo函數(shù)中,之后你就不能再使用原始的x了,因?yàn)镽ust的所有權(quán)規(guī)則不允許一個(gè)值有多個(gè)所有者。
foo(x)
的參數(shù)潛在的問(wèn)題
- 開(kāi)發(fā)應(yīng)用程序時(shí),參數(shù)
x
大部分是胖指針類型的。如果我們希望函數(shù)foo
調(diào)用后,傳入的參數(shù)在函數(shù)執(zhí)行后還能繼續(xù)使用,這種參數(shù)定義模式下,我們必須按照下面的形式調(diào)用:
...foo(x.clone());...
也就是說(shuō),需要把變量的一個(gè)完整克隆移動(dòng)到函數(shù)的參數(shù)棧,這樣才不會(huì)影響變量 x
在函數(shù)調(diào)用后的可用性。但是,變量的完全克隆操作的代價(jià)通常很高。
2、 foo(&x)
:
- 如果
foo
函數(shù)接收一個(gè)引用作為參數(shù)(例如fn foo(x: &T)
),則你應(yīng)該傳遞x
的引用(&x
)。 - 在這種情況下,
foo
函數(shù)將獲得x
的借用,而不是所有權(quán)。這意味著你可以在調(diào)用foo
之后繼續(xù)使用x
。 - 需要注意的是,根據(jù)Rust的借用規(guī)則,你不能在借用期間修改
x
(除非foo
接收一個(gè)可變引用,即fn foo(x: &mut T)
,并且你確實(shí)需要修改x
)。
3、foo(x.clone())
:
- 如果
foo
函數(shù)需要一個(gè)值的拷貝,但你希望在調(diào)用之后仍然保留對(duì)原始x
的使用權(quán),你可以克隆x
并傳遞克隆的版本。 - 這意味著你將創(chuàng)建一個(gè)
x
的完整拷貝,并將其傳遞給foo
函數(shù),同時(shí)保留原始x
的所有權(quán)和使用權(quán)。 - 使用
clone()
可能會(huì)有性能開(kāi)銷,特別是當(dāng)x
很大時(shí),因?yàn)樗婕暗絻?nèi)存的分配和數(shù)據(jù)的復(fù)制。
在選擇使用哪種方式時(shí),你應(yīng)該考慮以下因素:
- 函數(shù)的參數(shù)類型和要求。
- 你是否需要在調(diào)用函數(shù)之后繼續(xù)使用
x
。 x
的大小和復(fù)制成本。- 是否有必要避免潛在的副作用或修改。
總的來(lái)說(shuō),在Rust中,這三種方式的選擇受到語(yǔ)言所有權(quán)和借用規(guī)則的深刻影響,你需要根據(jù)具體情況來(lái)決定使用哪一種。