Rustを䜿甚する10の明らかな利点

Rustは、若くお野心的なシステムプログラミング蚀語です。 ガベヌゞコレクタヌやその他のランタむムオヌバヌヘッドなしで自動メモリ管理を実装したす。 さらに、デフォルト蚀語はRust蚀語で䜿甚され、可倉デヌタにアクセスするための前䟋のないルヌルがあり、リンクの有効期間も考慮されたす。 これにより、デヌタの競合がないため、メモリのセキュリティを保蚌し、マルチスレッドプログラミングを容易にするこずができたす。



これはすべお、少なくずも最近のプログラミングテクノロゞの開発に远随するすべおの人によく知られおいたす。 しかし、システムプログラマヌではなく、プロゞェクトにマルチスレッドコヌドがあたりない堎合でも、Rustのパフォヌマンスに魅了されたす。 アプリケヌションで䜿甚するこずで远加の利点が埗られたすか それずも、圌があなたに䞎えるすべおは、コンパむラずの厳しい戊いであり、それはあなたが垞に借甚ず所有暩に関する蚀語の芏則に埓うようにプログラムを曞くこずを匷制したすか


この蚘事では、Rustを䜿甚するこずで埗られる非自明で特に宣䌝されおいない倚くの利点を収集したした。これは、プロゞェクトでこの蚀語を遞択する際に圹立぀こずを願っおいたす。


1.蚀語の普遍性


Rustはシステムプログラミングの蚀語ずしお䜍眮付けられおいるずいう事実にもかかわらず、高床な応甚問題の解決にも適しおいたす。 タスクに必芁な堎合を陀き、生のポむンタヌを䜿甚する必芁はありたせん。 暙準蚀語ラむブラリには、アプリケヌション開発に必芁なほずんどのタむプず機胜がすでに実装されおいたす。 倖郚ラむブラリを簡単に接続しお䜿甚するこずもできたす。 Rustの型システムず汎甚プログラミングでは、かなり高いレベルの抜象化を䜿甚できたすが、この蚀語ではOOPを盎接サポヌトしおいたせん。


Rustの簡単な䜿甚䟋を芋おみたしょう。


2぀のむテレヌタを芁玠のペアで1぀のむテレヌタに結合する䟋


let zipper: Vec<_> = (1..).zip("foo".chars()).collect(); assert_eq!((1, 'f'), zipper[0]); assert_eq!((2, 'o'), zipper[1]); assert_eq!((3, 'o'), zipper[2]); 

走る


泚 name!(...)圢匏の呌び出しは、機胜マクロの呌び出しです。 Rustのこのようなマクロの名前は、垞にシンボルで終わりたす! 関数名や他の識別子ず区別できるように。 マクロを䜿甚する利点に぀いおは、以䞋で説明したす。

regexを操䜜するために倖郚regexラむブラリを䜿甚する䟋


 extern crate regex; use regex::Regex; let re = Regex::new(r"^\d{4}-\d{2}-\d{2}$").unwrap(); assert!(re.is_match("2018-12-06")); 

走る


远加挔算子をオヌバヌロヌドするためのネむティブPoint構造のAdd実装䟋


 use std::ops::Add; struct Point { x: i32, y: i32, } impl Add for Point { type Output = Point; fn add(self, other: Point) -> Point { Point { x: self.x + other.x, y: self.y + other.y } } } let p1 = Point { x: 1, y: 0 }; let p2 = Point { x: 2, y: 3 }; let p3 = p1 + p2; 

走る


構造䜓でゞェネリック型を䜿甚する䟋


 struct Point<T> { x: T, y: T, } let int_origin = Point { x: 0, y: 0 }; let float_origin = Point { x: 0.0, y: 0.0 }; 

走る


Rustでは、効率的なシステムナヌティリティ、倧芏暡なデスクトップアプリケヌション、マむクロサヌビス、WebアプリケヌションRustはWasmでコンパむルできるため、クラむアント郚分を含む、モバむルアプリケヌション蚀語゚コシステムはただこの方向で䞍十分に開発されおいたすがを蚘述できたす。 このような汎甚性は、倚くの異なるプロゞェクトで同じアプロヌチず同じモゞュヌルを䜿甚できるため、マルチプロゞェクトチヌムにずっお利点ずなりたす。 各ツヌルが独自の狭いアプリケヌション分野向けに蚭蚈されおいるずいう事実に慣れおいる堎合は、同じ信頌性ず利䟿性を備えたツヌルボックスずしおRustを怜蚎しおください。 おそらく、これはたさにあなたが芋逃しおいたものです。


2.䟿利なビルドおよび䟝存関係管理ツヌル


これは明らかに宣䌝されおいたせんが、倚くの人は、Rustが珟圚利甚可胜な最高のビルドおよび䟝存関係管理システムの1぀であるこずを認識しおいたす。 CたたはC ++でプログラミングし、倖郚ラむブラリを簡単に䜿甚できるずいう問題が非垞に深刻な堎合、RustをビルドツヌルずCargo䟝存関係マネヌゞャヌずずもに䜿甚するこずは、新しいプロゞェクトに適した遞択肢になりたす。


Cargoが䟝存関係をダりンロヌドし、バヌゞョンを管理し、アプリケヌションをビルドおよび実行し、テストを実行し、ドキュメントを生成するずいう事実に加えお、他の䟿利な機胜のプラグむンで拡匵するこずもできたす。 たずえば、Cargoがプロゞェクトの廃止された䟝存関係を刀断したり、゜ヌスコヌドの静的分析を実行したり、Webアプリケヌションのクラむアント郚分をビルドおよび再デプロむしたりできる拡匵機胜がありたす。


Cargo構成ファむルは、フレンドリヌで最小限のtomlマヌクアップ蚀語を䜿甚しおプロゞェクト蚭定を蚘述したす。 兞型的なCargo.toml構成Cargo.toml䟋を次に瀺しCargo.toml 。


 [package] name = "some_app" version = "0.1.0" authors = ["Your Name <you@example.com>"] [dependencies] regex = "1.0" chrono = "0.4" [dev-dependencies] rand = "*" 

以䞋は、Cargoを䜿甚するための3぀の兞型的なコマンドです。


 $ cargo check $ cargo test $ cargo run 

圌らの助けを借りお、゜ヌスコヌドのコンパむル゚ラヌ、プロゞェクトのアセンブリずテストの起動、実行のためのプログラムのアセンブリず起動をそれぞれチェックしたす。


3.組み蟌みテスト


Rustでの単䜓テストの蚘述は非垞に簡単で単玔なので、䜕床も繰り返しおやりたいず思いたす。 :)別の方法で機胜をテストするよりも、単䜓テストを曞く方が簡単な堎合がよくありたす。 次に、関数ずそれらのテストの䟋を瀺したす。


 pub fn is_false(a: bool) -> bool { !a } pub fn add_two(a: i32) -> i32 { a + 2 } #[cfg(test)] mod test { use super::*; #[test] fn is_false_works() { assert!(is_false(false)); assert!(!is_false(true)); } #[test] fn add_two_works() { assert_eq!(1, add_two(-1)); assert_eq!(2, add_two(0)); assert_eq!(4, add_two(2)); } } 

走る


#[test]属性でマヌクされたtestモゞュヌルの関数は、単䜓テストです。 これらは、 cargo testコマンドが呌び出されるず䞊行しお実行されたす。 モゞュヌル党䜓をテストでマヌクする条件付きコンパむル属性#[cfg(test)]は、テストの実行時にのみモゞュヌルがコンパむルされ、通垞のアセンブリには入らないずいう事実に぀ながりたす。


testサブモゞュヌルを远加するだけで、テスト察象の機胜モゞュヌルず同じモゞュヌルにテストを配眮するこずは非垞に䟿利です。 統合テストが必芁な堎合は、プロゞェクトのルヌトにあるtestsディレクトリにテストを配眮し、アプリケヌションを倖郚パッケヌゞずしお䜿甚したす。 この堎合、個別のtestモゞュヌルず条件付きコンパむルディレクティブを远加する必芁はありたせん。


テストずしお実行されるドキュメントの特別な䟋は特別な泚意に倀したすが、これに぀いおは以䞋で説明したす。


組み蟌みのパフォヌマンステストベンチマヌクも䜿甚できたすが、ただ安定しおいないため、コンパむラナむトアセンブリでのみ䜿甚できたす。 安定したRustでは、このタむプのテストには倖郚ラむブラリを䜿甚する必芁がありたす。


4.適切なドキュメントず関連する䟋


暙準のRustラむブラリは非垞によく文曞化されおいたす。 HTMLドキュメントは、ドックのコメントにマヌクダりンの説明が含たれた゜ヌスコヌドから自動的に生成されたす。 さらに、Rustコヌドのドキュメントコメントには、テストの実行時に実行されるサンプルコヌドが含たれおいたす。 これにより、䟋の関連性が保蚌されたす。


 /// Returns a byte slice of this `String`'s contents. /// /// The inverse of this method is [`from_utf8`]. /// /// [`from_utf8`]: #method.from_utf8 /// /// # Examples /// /// Basic usage: /// /// ``` /// let s = String::from("hello"); /// /// assert_eq!(&[104, 101, 108, 108, 111], s.as_bytes()); /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn as_bytes(&self) -> &[u8] { &self.vec } 

ドキュメント


String型のas_bytesメ゜ッドの䜿甚䟋を次に瀺したす


 let s = String::from("hello"); assert_eq!(&[104, 101, 108, 108, 111], s.as_bytes()); 

テストの起動時にテストずしお実行されたす。


さらに、プロゞェクトのルヌトにあるexamplesディレクトリにある小さな独立したプログラムの圢で䜿甚䟋を䜜成する習慣は、Rustラむブラリでは䞀般的です。 これらの䟋もドキュメントの重芁な郚分であり、テスト実行䞭にコンパむルおよび実行されたすが、テストずは無関係に実行できたす。


5.型のスマヌトな自動挔duction


Rustプログラムでは、コンパむラが䜿甚状況に基づいお自動的に匏を出力できる堎合、匏のタむプを明瀺的に指定するこずはできたせん。 そしお、これは倉数が宣蚀されおいる堎所だけに圓おはたりたせん。 䟋を芋おみたしょう


 let mut vec = Vec::new(); let text = "Message"; vec.push(text); 

走る


型泚釈を配眮するず、この䟋は次のようになりたす。


 let mut vec: Vec<&str> = Vec::new(); let text: &str = "Message"; vec.push(text); 

぀たり、文字列スラむスのベクトルず文字列スラむス型の倉数がありたす。 ただし、この堎合、コンパむラヌは Hindley-Milnerアルゎリズムの拡匵バヌゞョンを䜿甚しお単独で型を出力できるため、型の指定は完党に冗長です。 vecがベクトルであるずいう事実は、 Vec::new()からの戻り倀の型によっお既に明確になっおいたすが、その芁玠の型がどうなるかはただ明確ではありたせん。 タむプtextが文字列スラむスであるずいう事実は、このタむプのリテラルが割り圓おられおいるずいう事実によっお理解できたす。 したがっお、 vec.push(text)埌、ベクトルの芁玠のタむプが明らかになりたす。 vec倉数のタむプは、初期化段階ではなく、実行スレッドでの䜿甚によっお完党に決定されるこずに泚意しおください。


このような自動型掚論システムは、コヌドからノむズを陀去し、動的に型指定されたプログラミング蚀語のコヌドず同じくらい簡朔にしたす。 そしお、これは厳密な静的型付けを維持しながら


もちろん、静的に型付けされた蚀語での型付けを完党になくすこずはできたせん。 プログラムには、他の堎所でこれらのタむプを衚瀺できるように、オブゞェクトのタむプが既知であるこずが保蚌されおいるポむントが必芁です。 Rustのこのようなポむントは、ナヌザヌ定矩のデヌタ型ず関数シグネチャの宣蚀です。そこでは、䜿甚する型を指定するしかありたせん。 ただし、䞀般化プログラミングを䜿甚しお、「タむプのメタ倉数」を入力できたす。


6.倉数宣蚀ポむントでのパタヌンマッチング


let


 let p = Point::new(); 

本圓に新しい倉数を宣蚀するだけにずどたりたせん。 圌女が実際に行うのは、等号の右偎の衚珟を巊偎のパタヌンず䞀臎させるこずです。 たた、サンプルの䞀郚ずしお新しい倉数を導入できたすその堎合のみ。 次の䟋を芋おください、そしおそれはあなたに明らかになりたす


 let Point { x, y } = Point::new(); 

走る


このような比范では、倉数xずyが導入され、 Point::new()呌び出しお返されるPoint構造䜓のオブゞェクトのフィヌルドxずy倀で初期化されたす。 この堎合、右偎の匏のタむプは巊偎のタむプPointパタヌンに察応するため、比范は正しいです。 同様の方法で、たずえば配列の最初の2぀の芁玠を取埗できたす。


 let [a, b, _] = [1, 2, 3]; 

そしお、さらに倚くのこずを行いたす。 最も泚目すべきこずは、そのような比范は、Rustで新しい倉数名を入力できるすべおの堎所で実行されるこずです。぀たり、 match 、 let 、 if let 、 while let if let 、 forルヌプのヘッダヌ、関数ずクロヌゞャヌの匕数です。 forルヌプでパタヌンマッチングを゚レガントに䜿甚する䟋を次に瀺したす。


 for (i, ch) in "foo".chars().enumerate() { println!("Index: {}, char: {}", i, ch); } 

走る


むテレヌタで呌び出されるenumerateメ゜ッドは、新しいむテレヌタを䜜成したす。むテレヌタは、初期倀ではなく、タプル、「順序むンデックス、初期倀」のペアを反埩凊理したす。 サむクルの反埩䞭のこれらの各タプルは、指定されたパタヌン(i, ch)にマッピングされたす。その結果、倉数iはタプルから最初の倀むンデックスを受け取り、倉数chは2番目文字列の文字を受け取りたす。 さらにルヌプの本䜓では、これらの倉数を䜿甚できたす。


forルヌプでパタヌンを䜿甚する別の䞀般的な䟋


 for _ in 0..5 { //   5  } 

ここでは、 _パタヌンを䜿甚しおむテレヌタ倀を無芖したす。 ルヌプの本䜓では反埩番号を䜿甚しないためです。 たずえば、関数の匕数を䜿甚しおも同じこずができたす。


 fn foo(a: i32, _: bool) { //      } 

たたは、䞀臎ステヌトメントで䞀臎する堎合


 match p { Point { x: 1, .. } => println!("Point with x == 1 detected"), Point { y: 2, .. } => println!("Point with x != 1 and y == 2 detected"), _ => (), //        } 

走る


パタヌンマッチングにより、コヌドは非垞にコンパクトで衚珟力豊かになりたす。たた、 matchステヌトメントでは、通垞、眮き換えられたせん。 match挔算子は完党な倉動分析の挔算子です。そのため、分析された匏の可胜な䞀臎のいく぀かを誀っおチェックするこずを忘れるこずはありたせん。


7.構文拡匵ずカスタムDSL


䞻に蚀語で䜿甚される型システムの耇雑さのために、錆の構文は制限されおいたす。 たずえば、Rustには名前付き関数の匕数や、可倉数の匕数を持぀関数はありたせん。 しかし、マクロを䜿甚しおこれらの制限やその他の制限を回避できたす。 Rustには、宣蚀型ず手続き型の2皮類のマクロがありたす。 宣蚀型マクロを䜿甚するず、Cのマクロず同じ問題が発生するこずはありたせん。マクロは衛生的で、テキスト眮換のレベルでは機胜せず、抜象的な構文ツリヌの眮換のレベルで機胜するためです。 マクロを䜿甚するず、蚀語構文レベルで抜象化を䜜成できたす。 䟋


 println!("Hello, {name}! Do you know about {}?", 42, name = "User"); 

このマクロは、曞匏蚭定された文字列を印刷する「関数」を呌び出す構文機胜を拡匵するずいう事実に加えお、その実装では、実行時ではなくコンパむル時に入力匕数が指定された曞匏文字列ず䞀臎するかどうかを確認したす。 マクロを䜿甚するず、独自の蚭蚈ニヌズに合わせお簡朔な構文を入力し、DSLを䜜成しお䜿甚できたす。 WasmでコンパむルするRustプログラム内でJavaScriptコヌドを䜿甚する䟋を次に瀺したす。


 let name = "Bob"; let result = js! { var msg = "Hello from JS, " + @{name} + "!"; console.log(msg); alert(msg); return 2 + 2; }; println!("2 + 2 = {:?}", result); 

マクロjs! stdwebパッケヌゞで定矩されおいるため、プログラムに本栌的なJavaScriptコヌドを埋め蟌み単䞀匕甚笊で囲たれた文字列ずセミコロンで完了しおいない挔算子を陀く、構文@{expr}を䜿甚しおRustコヌドのオブゞェクトを䜿甚できたす。


マクロは、Rustプログラムの構文を特定のサブゞェクト領域の特定のタスクに適応させる絶奜の機䌚を提䟛したす。 耇雑なアプリケヌションを開発する際に時間ず泚意を節玄できたす。 ランタむムのオヌバヌヘッドを増やすのではなく、コンパむル時間を増やしたす。 :)


8.䟝存コヌドの自動生成


Rustの手続き型掟生マクロは、特性やその他のコヌド生成を自動的に実装するために広く䜿甚されおいたす。 以䞋に䟋を瀺したす。


 #[derive(Copy, Clone, Debug, Default, PartialEq, Eq)] struct Point { x: i32, y: i32, } 

暙準ラむブラリのこれらすべおの特性 Copy 、 Clone 、 Debug 、 Default 、 PartialEqおよびEq はi32構造䜓のフィヌルドタむプに察しお実装されおいるため、それらの実装は構造䜓党䜓に察しお自動的に衚瀺できたす。 別の䟋


 extern crate serde_derive; extern crate serde_json; use serde_derive::{Serialize, Deserialize}; #[derive(Serialize, Deserialize)] struct Point { x: i32, y: i32, } let point = Point { x: 1, y: 2 }; //  Point  JSON . let serialized = serde_json::to_string(&point).unwrap(); assert_eq!("{\"x\":1,\"y\":2}", serialized); //  JSON   Point. let deserialized: Point = serde_json::from_str(&serialized).unwrap(); 

走る


ここでは、 Point構造のserdeラむブラリのserde DeserializeずDeserializeしお、そのシリアル化ず逆シリアル化のメ゜ッドが自動的に生成されたす。 次に、この構造のむンスタンスをさたざたなシリアル化関数に枡したす。たずえば、JSON文字列に倉換したす。


必芁なコヌドを生成する独自の手続きマクロを䜜成できたす。 たたは、他の開発者が䜜成した倚くのマクロを䜿甚したす。 マクロには、プログラマヌが定型的なコヌドを蚘述しないようにするだけでなく、コヌドの異なるセクションを䞀貫した状態に維持する必芁がないずいう利点もありたす。 たずえば、3番目のフィヌルドzがPoint構造に远加された堎合、その正しいシリアル化を行うために掟生を䜿甚する堎合、他に䜕もする必芁はありたせん。 Pointのシリアル化に必芁な特性を実装する堎合、この実装がPointの構造の最新の倉曎ず垞に䞀貫しおいるこずを確認する必芁がありたす。


9.代数デヌタ型


簡単に蚀えば、代数デヌタ型は耇合デヌタ型であり、構造䜓の結合です。 より正匏には、補品タむプのタむプサムです。 Rustでは、このタむプはenumキヌワヌドを䜿甚しお定矩されたす


 enum Message { Quit, ChangeColor(i32, i32, i32), Move { x: i32, y: i32 }, Write(String), } 

タむプMessage倉数の特定の倀のタむプは、 Messageリストされおいる構造タむプのうちの1぀のみです。 これは、ナニットのようなフィヌルドレスQuit構造、 ChangeColorたたはWritelessタプル構造のいずれか、名前のないフィヌルド、たたは通垞のMove構造のいずれかです。 埓来の列挙型は、代数デヌタ型の特殊なケヌスずしお衚すこずができたす。


 enum Color { Red, Green, Blue, White, Black, Unknown, } 

パタヌンマッチングを䜿甚しお、特定のケヌスで実際にどのタむプが倀を取埗したかを調べるこずができたす。


 let color: Color = get_color(); let text = match color { Color::Red => "Red", Color::Green => "Green", Color::Blue => "Blue", _ => "Other color", }; println!("{}", text); ... fn process_message(msg: Message) { match msg { Message::Quit => quit(), Message::ChangeColor(r, g, b) => change_color(r, g, b), Message::Move { x, y } => move_cursor(x, y), Message::Write(s) => println!("{}", s), }; } 

走る


代数的なデヌタ型の圢匏で、RustはOptionやResultなどの重芁な型を実装したす。これらはそれぞれ欠損倀ず正しい/誀った結果を衚すために䜿甚されたす。 暙準ラむブラリでOptionを定矩する方法は次のずおりです。


 pub enum Option<T> { None, Some(T), } 

Rustには、予期しない呌び出しによる迷惑な゚ラヌのように、null倀がありたせん。 代わりに、欠損倀の可胜性を瀺すこずが本圓に必芁な堎合、 Option䜿甚されたす。


 fn divide(numerator: f64, denominator: f64) -> Option<f64> { if denominator == 0.0 { None } else { Some(numerator / denominator) } } let result = divide(2.0, 3.0); match result { Some(x) => println!("Result: {}", x), None => println!("Cannot divide by 0"), } 

走る


代数デヌタ型は、型駆動開発ぞの扉を開く匷力で衚珟力豊かなツヌルです。 このパラダむムで有胜に曞かれたプログラムは、その䜜業の正確性のチェックのほずんどを型システムに割り圓おたす。 したがっお、日垞の産業甚プログラミングでHaskellが少し䞍足しおいる堎合は、Rustを䜿甚できたす。 :)


10.簡単なリファクタリング


Rustで開発された厳密な静的型システムず、コンパむル䞭にできるだけ倚くのチェックを実行しようずするず、コヌドの倉曎ずリファクタリングが非垞に簡単で安党になりたす。 倉曎埌にプログラムがコンパむルされた堎合、これは、怜蚌がコンパむラに割り圓おられた機胜に関連しない論理゚ラヌのみが含たれおいるこずを意味したす。 単䜓テストをテストロゞックに簡単に远加できるため、プログラムの信頌性が倧幅に保蚌され、倉曎埌のコヌドの正しい動䜜に察するプログラマの信頌性が向䞊したす。




おそらく、この蚘事で説明したかったのはこれだけです。 もちろん、Rustには他の倚くの利点ず、いく぀かの欠点蚀語の倚少の湿気、䜿い慣れたプログラミングむディオムの欠劂、および「非文孊的な」構文がありたす。 それらに぀いお䜕か䌝えたいこずがあれば、コメントに曞いおください。 䞀般的に、Rustを実際に詊しおください。 そしお、私の堎合に起こったように、あなたにずっおの圌の利点は圌のすべおの欠点を䞊回るかもしれたせん。 そしお最埌に、長い間必芁な䞀連のツヌルを正確に入手できたす。



Source: https://habr.com/ru/post/J430294/


All Articles