Edited at

The Rust Programming Languageのイントロダクションを日本語訳してみた

More than 3 years have passed since last update.

拙い部分もありますがよろしくお願いします。

原文はhttps://doc.rust-lang.org/stable/book/README.html にあります。

原文のライセンスはこちら→https://github.com/rust-lang/rust/blob/master/COPYRIGHT


The Rust Programming Language

ようこそ!このブックでは「Rust」プログラミング言語についてあなたに教えます。Rustは「安全性」、「高速性」そして「並行性」の三つのゴールを主眼としたシステムプログラミング言語です。 他の言語が得意としない一定数のユースケースのために有用な言語を作り、ガベージコレクタ-なしでそのゴールを維持します:。そのゴールは他の言語への組み込み、特定の領域や時間要件を持つプログラム、デバイスドライバーやオペレーティングシステムのような、低レベルのコードを書けるようにすることです。Rustは現在この領域をターゲットにする他の言語の上に、実行時にオーバーヘッドを生じない多数のコンパイル時安全性チェックを行うと同時に全てのデータ競合を除去する改良を加えています。また Rustには、幾つか高級言語のように感じる抽象化がありますが 、これらを「ゼロコストの抽象化」として達成するための狙いもあります。それにも関わらず、Rustは低級言語のような正確な制御を可能にします。

"The Rust Programming Language"は7つのセクションに分かれています。このイントロダクションを先頭に、次のとおりに分かれます。



  • Getting Started - Rustによる開発のためのコンピューターの設定する


  • Learn Rust(日本語) - 小規模なプロジェクトでRustプログラミングを学習する



  • Effective Rust - よりよいRustのコードを書くための高度な概念


  • Syntax and Semantics - Rustを少しずつ噛み砕いて、小さく塊にする 1


  • Nightly Rust - 安定版ビルドにはまだ入っていない最先端の機能 1


  • Glossary - 本文中で使用される用語のリファレンス


  • Academic Research - Rustに影響を与えた文献


このイントロダクションを読んだ後、あなたの好みに応じて ‘Learn Rust’ か ‘Syntax and Semantics’に飛び込んでいくことになるでしょう。もしあなたがプロジェクトに取り組みたいと思ったなら'Learn Rust'を、あるいは、 もしあなたが小さいスタートを好み、かつ、次のステップに移動する前に徹底的に、単一の概念を学習したいと思ったたなら‘Syntax and Semantics’ が、お役に立てるでしょう。豊富な相互リンクがこれらのページを一つにものに繋いでくれるはずです。 2


Contributing

この文書のソースファイルはGithub上にあり、そこから生成されたものです。 Github:github.com/rust-lang/rust/tree/master/src/doc/trpl3


A brief introduction to Rust

Rustに興味を持たれましたか?いくつかの小さいコードサンプルでRustのいくつかの強力な部分を調べてみましょう。

Rustをユニークにする主な概念に'ownership'と呼ばれるものがあります。下の小さな例を考えてみましょう。

fn main(){

let mut x = vec!["Hello","World"];
}

このプログラムは、xという名前の変数バインディングを作成します。この値のバインディングは標準ライブラリで決められたマクロを介して作成される'vector'であるVecです。このマクロはvecを呼び出し、"!"でマクロを呼び出します。これは、物事を明示的にするという Rustの大原則に準じるものです。マクロは関数呼び出しより大幅に複雑なことを可能にし、そのため視覚的にも異なるものになります。 この”!”は構文解析を助け、記述のためのツールの作成を容易にしたりなど、重要なものです。

Rustでは標準ではバインディングされた変数はイミュータブルつまり変化しない値であり、”mut”を使用することで"x"を変化する値にすることが出来ます。後半の例では、このベクトルを変化させるものとして扱うかも知れません。

また、ここで型注釈を必要としなかったことに注目してください: Rustは静的型付け言語であると同時に、明示的に型を宣言する必要もないのです。Rustは型推論によって静的型付けのパワーと冗長な型注釈をうまく釣り合わせています。

Rustはヒープ割り当てよりもスタック割り当てを好みます: "x"はスタックに直接配置されます。 しかしながら、 「Vec」型はベクトルの要素のための空間をヒープに割り当てます。 もし、あなたがこの区別に慣れていない場合、今のところそれを無視しておくか、「The Stack and the Heap」で調べることが出来ます。システムプログラミング言語として、 Rustは、メモリー割り当てを制御する方法をあなたに提供しますが、入門程度であれば、ほとんど必要とされないでしょう。

前の文で、「ownership」はRustにおいて鍵となる新しい概念であると述べました。 Rustにおける用語では、 "x"はベクトルを「所有」するといいます。これはxがスコープの外に出たとき、ベクトルのメモリーが開放されることを意味します。これはRustコンパイラによって決定論的に行われ、ガベージコレクターなどを解するものではありません。言い換えると、Rustでは、貴方自身でmallocやfreeのような関数を呼び出す必要がないということです: コンパイラが静的にメモリーの確保もしくは開放の必要性を決定し、それらの呼び出しを挿入します。誤るのは人の性ですが、コンパイラは見逃しません。

上記の例に、別の1文を加えてみましょう:

fn main() {

let mut x = vec!["Hello", "world"];

let y = &x[0];
}

ここでは、新たにの割り当てを導入しました。このケースでは、yは最初の要素であるベクトルに対する「reference」です。Rustにおける参照は他の言語におけるポインタに似ていますが、コンパイル時における安全性のチェックが追加されています。参照はそれ自体を所有することではなく、むしろ指し示す対象から「借りて」来ることによる所有権システムと相互に作用します。この違いは、参照がスコープの外に出た時に、それが根本的なメモリ解放を行わないということです 。もしそれがないなら、割り当ての二重開放になってしまいます。which is bad!(訳注1)

3つ目の文を加えてみましょう。 一件問題なく見えますが、コンパイルエラーになるケースです:

fn main() {

let mut x = vec!["Hello", "world"];

let y = &x[0];

x.push("foo");
}

pushはベクトルの最後に新しい別の要素を付け加えるメソッドです。コンパイルしようとすると次のエラーを得られます:

error: cannot borrow `x` as mutable because it is also borrowed as immutable

x.push("foo");
^
note: previous borrow of `x` occurs here; the immutable borrow prevents
subsequent moves or mutable borrows of `x` until the borrow ends
let y = &x[0];
^
note: previous borrow ends here
fn main() {

}
^

Whew!4 Rustコンパイラは非常に詳細なエラーを発生時にくれますが、これはその一つです。 エラーに書かれている通り、作成するバインディングが変更可能である間は、まだpushを呼び出すことが出来ません。 その理由は我々がすでにベクトルへの参照であるyをすでに持っているからです。参照は無効にすることができるので、他の参照が存在する間に何かに変更を加える事はとても危険です。この特定のケースでは、ベクトルを作成するとき、3つの要素のための領域だけが確保されたかもしれません。4つ目の要素を追加するということは、すべての要素に新しいメモリー領域を割り当て、古い値を新しい領域にコピーし、そのメモリを指し示す内部ポインターを更新することを意味するかもしれません。それらはきっと正常に動きます。問題はが更新されず、「ダングリングポインター5」が発生しているだろうということです。それはまずいことです。 この場合yの使用はエラーであり、そのためコンパイラーはエラーをキャッチしてくれました。

ではどうすればこの問題を解決できるでしょう? 取るべき方法は2つあります。 一つ目は参照ではなくコピーを利用する方法です。:

fn main() {

let mut x = vec!["Hello", "world"];

let y = x[0].clone();

x.push("foo");
}

Rustは標準でmoveセマンティクスであり、何らかのデータをコピーさせたい場合は、clone() メソッドを呼び出します. この例では、yはもはやxに格納されたベクトルへの参照ではなく、その最初の要素である”Hello”のコピーになります。そうすると特に参照を持っていないので、push()は正常に機能します。

もし本当に参照をしたいなら、別のオプションが必要です: 何かの変更をしようとする前に、参照がスコープの外にでることを確認します。それは次のようになります。:

fn main() {

let mut x = vec!["Hello", "world"];

{
let y = &x[0];
}

x.push("foo");
}

中括弧を使って追加で内部スコープを作成してみました。push()を呼び出す前にyスコープの外になって、万事解決です。

この「ownership」の概念はダングリングポインターを防止するだけではなく、イテレーターの無効化や並行処理など、関連する問題と全体に良い効果を与えます。


感想

翻訳難しい。翻訳家さんすごい。

つぎは、Getting Startedだ(予定は未定)Learn Rustになりました。

その他、ご意見、ご感想ございましたらコメント、編集リクエストなどよろしくお願いします。


訳注一覧





  1. 未翻訳です。頑張ります。リクエストのお陰で理解することが出来ました。ありがとうございます。 



  2. Copious cross-linking connects these parts together.ってどういう意味何ですか?あってますかね?と言うかこの段落翻訳難しい。 cross-linkingを相互リンクとして捉えると理解出来ました。ご指摘ありがとうございました。 



  3. 原文の方です。多分。 



  4. あえてそのまま残しました。 



  5. プログラムの実行中に不正なメモリ領域やアドレスを指す可能性のあるポインタ。又はその状態。CやC++などでは致命的なバグにつながる可能性もある。