為什么使用Rust重寫并不能解決所有問(wèn)題
Rust 安全、快速,并承諾消除代碼庫(kù)中臭名昭著的內(nèi)存錯(cuò)誤。但這是否意味著你應(yīng)該用Rust重寫所有的項(xiàng)目呢?不完全是。
在某些情況下,用Rust重寫可能很好,但它并不是解決所有軟件開(kāi)發(fā)問(wèn)題的通用方法。讓我們通過(guò)一些代碼片段、類比和一些笑料來(lái)深入了解其中的原因。
Rust的優(yōu)勢(shì):為什么要大肆宣傳?
1,內(nèi)存安全:Rust的借用檢查器消除了內(nèi)存相關(guān)的錯(cuò)誤,如空指針解引用和數(shù)據(jù)競(jìng)爭(zhēng)。
2,性能:Rust的運(yùn)行速度幾乎和C或C++一樣快,但崩潰要少得多。如果你正在構(gòu)建高性能系統(tǒng),Rust是最好的選擇。
3,現(xiàn)代工具:與其他一些語(yǔ)言(例:JavaScript)相比,Rust的包管理器和構(gòu)建工具:Cargo,使依賴管理變成一件輕松的事情。
Rust的信條是安全、快速和穩(wěn)定。誰(shuí)不想這樣呢?現(xiàn)在,讓我們來(lái)探討一下,為什么這并不意味著應(yīng)該使用Rust來(lái)重寫所有當(dāng)前的代碼庫(kù)。
重寫謬誤
Joel Spolsky的經(jīng)典博客文章“你永遠(yuǎn)不應(yīng)該做的事情”警告不要丟棄現(xiàn)有已工作的代碼。為什么?因?yàn)橹貙憰?huì)引入bug,浪費(fèi)多年的調(diào)試知識(shí),并減緩進(jìn)度。用Rust重寫會(huì)放大這些風(fēng)險(xiǎn),因?yàn)镽ust的學(xué)習(xí)曲線非常陡峭。
示例:重構(gòu)與重寫
假設(shè)有這樣一個(gè)Python函數(shù):
# Python: 計(jì)算階乘
def factorial(n):
if n == 0:
return 1
return n * factorial(n - 1)
但是想要Rust的速度和安全性。代碼是這樣的:
// Rust: 計(jì)算階乘
fn factorial(n: u64) -> u64 {
match n {
0 => 1,
_ => n * factorial(n - 1),
}
}
很好,但是重寫值得嗎?對(duì)于像這樣的一小段代碼,可能不會(huì)。Python代碼運(yùn)行良好,對(duì)于新開(kāi)發(fā)人員來(lái)說(shuō)更容易閱讀和維護(hù)。如果性能成為一個(gè)問(wèn)題,可以使用PyO3等工具使用Rust庫(kù)優(yōu)化這個(gè)特定的函數(shù),而不是重寫所有內(nèi)容。
學(xué)習(xí)曲線:不是每個(gè)人都是Rustacean
Rust的語(yǔ)法可能會(huì)讓習(xí)慣于更傳統(tǒng)語(yǔ)言的開(kāi)發(fā)人員感到陌生。像借用、生命周期和所有權(quán)這樣的概念是強(qiáng)大的,但也令人生畏。如果你的團(tuán)隊(duì)還不熟悉Rust,那就做好項(xiàng)目延遲和混亂的準(zhǔn)備。
考慮一下這個(gè)簡(jiǎn)單的任務(wù):在Rust中修改一個(gè)向量
fn main() {
let mut numbers = vec![1, 2, 3];
for num in &mut numbers {
*num += 1;
}
println!("{:?}", numbers);
}
看起來(lái)很好,但是如果你忘記使用&mut或者用*解除引用,借用檢查器會(huì)報(bào)錯(cuò)。來(lái)自JavaScript或Python的開(kāi)發(fā)人員可能會(huì)覺(jué)得他們被欺騙了。
下面是Python中的等效函數(shù):
numbers = [1, 2, 3]
for i in range(len(numbers)):
numbers[i] += 1
print(numbers)
簡(jiǎn)單多了,對(duì)吧?Rust在前期更加努力地工作以保證安全性,這對(duì)于系統(tǒng)編程來(lái)說(shuō)是非常棒的,但是對(duì)于較小的、不容易出錯(cuò)的項(xiàng)目來(lái)說(shuō)是多余的。
并非所有代碼都需要Rust的特性
因?yàn)椤癛ust很酷”而用Rust重寫你的個(gè)人待辦事項(xiàng)列表應(yīng)用程序,就像用工業(yè)級(jí)鋼梁建造一個(gè)鳥舍,過(guò)度工程對(duì)任何人都沒(méi)有幫助。
假設(shè)你正在編寫一個(gè)腳本來(lái)重命名一些文件:
Python:
import os
def rename_files():
for filename in os.listdir("."):
if filename.endswith(".txt"):
os.rename(filename, filename.replace(".txt", ".md"))
rename_files()
Rust:
use std::fs;
use std::io;
fn rename_files() -> io::Result<()> {
for entry in fs::read_dir(".")? {
let entry = entry?;
let path = entry.path();
ifletSome(extension) = path.extension() {
if extension == "txt" {
let new_name = path.with_extension("md");
fs::rename(path, new_name)?;
}
}
}
Ok(())
}
fn main() {
rename_files().unwrap();
}
Rust的解決方案更加健壯,但是如果你的腳本只運(yùn)行一次,那么額外的復(fù)雜性值得嗎?對(duì)于快速的一次性任務(wù),Python等高級(jí)腳本語(yǔ)言通常是更好的選擇。
開(kāi)發(fā)人員的生產(chǎn)力:權(quán)衡
Rust編寫更多代碼來(lái)實(shí)現(xiàn)與其他語(yǔ)言相同的結(jié)果。對(duì)于安全關(guān)鍵型系統(tǒng),這種權(quán)衡是值得的,但是在開(kāi)發(fā)速度比運(yùn)行時(shí)性能更重要的環(huán)境中,這種權(quán)衡會(huì)降低項(xiàng)目開(kāi)發(fā)的速度。
如果正在構(gòu)建MVP或原型,應(yīng)該使用一種能夠快速迭代的語(yǔ)言。一旦驗(yàn)證了你的想法并需要擴(kuò)展,就可以考慮在Rust中重寫性能關(guān)鍵部分。
“完美工具”謬論
沒(méi)有語(yǔ)言是完美的,Rust也一樣。
Rust的優(yōu)勢(shì)為:
- 系統(tǒng)編程(例如,操作系統(tǒng),游戲引擎)。
- 性能關(guān)鍵型應(yīng)用程序。
- 在多線程程序中的安全性。
但不太理想的是:
- 快速原型
- 腳本和自動(dòng)化
- 經(jīng)驗(yàn)有限的Rust團(tuán)隊(duì)
總結(jié):使用Rust,但要明智地使用它
Rust是一門具有突破性特性的非凡語(yǔ)言,它值得大肆宣傳,但它也需要大量的時(shí)間和精力來(lái)采用。用Rust重寫項(xiàng)目可能不是你想要的奇跡解決方案。
相反,應(yīng)該考慮使用Rust的地方:關(guān)鍵的性能瓶頸、內(nèi)存安全的api,或者穩(wěn)定性至關(guān)重要的長(zhǎng)期項(xiàng)目。
因此,不要把Python、JavaScript或Go代碼庫(kù)扔進(jìn)垃圾桶。Rust可能是你需要的英雄,但不是每一場(chǎng)戰(zhàn)斗都需要。