Rustを始めよう
Rust学習期1回目ですね。
わりとダラダラ勉強していても身につくもんも身につかないし、忘備録としてこれを書き始めようと思いました。
ハロワ
fn main() {
println!("Hello world!");
}
まずはHelloWorldですね。
モダンな高級言語なだけあり、ここら辺は割とシンプルなものになっています。
関数
Rustはfunction の略語であるfnを使用しfn 関数名 -> 戻り値の型
で書きます。
functionを略称する系の類似だとGolangとかのfuncですかね。僕はどちらかというとGolangの略仕方の方が好きです。
さて実際にadd関数を書いていきます
fn add(a: i32, b: i32) -> i32 {
a + b
}
fn main() {
let result = add(5, 3);
println!("計算結果: {}", result);
}
Haskellとか通ってきてないので-> i32で戻り値表現してるのすごい違和感する。
大体はconst hoge = ():number => {}
とかfunc add(i int, j int) int
とかなんでこう言わんとしてることわかります?
C++なんかint add
とかですし
所有権
Rustでは所有権という概念があります。
コードブロック上で出た変数の権利はそのコードブロックが持ち、コードブロックが終了すると破棄されるっていうあれです。
fn main() {
let s = String::from("Hello World");
println!("{}", s);
}
ただこれはより厳密性を求める所有権を持つのがRustです。
所有権の移動
所有権は一度に1つの場所にしか存在できないという原則があります。
所有者が値を他の変数に渡すと、元の所有者はその値をもう使用できなくなるんです。
それでは無心でlet s1にsを代入してみましょう。
fn main() {
let s = String::from("Hello World");
let s1 = s;
println!("{}", s);
}
タチ悪いのがこれ、コーディングエラーにならんのですが、コンパイルエラーになるんです。
The Rust Programming Language 日本語版とほぼ同じコードですね。
sに入っている"Hello World"の所有権はs1に移動します。
そのためsはなんの所有権も持たなくなるため、コンパイル時にエラーとなるわけですね。
ただCopy型i32, u32, i64, u64, i8, u8, i128, u128
等は、そのまま値がコピーされるため動きます。
fn main() {
let i1 = 2;
let i2 = i1
println!("{}", i1);
}
参照渡し(戒め)値渡しとポインタ渡しが明示的に行われていないから発狂しそうw
所有権の借用(不変)
C++とかはポインタを渡すことで変数がポインタを共有することができましたが、Rustももちろんできます。
ただ不変と可変の借用の仕方があります。
fn main() {
let s = String::from("Hello");
let s2 = &s;
println!("{}", s);
println!("{}", s2);
}
この場合、s1とs2共に変更できなくなります。つまり
fn main() {
let s = String::from("Hello");
let s2 = &s;
println!("{}", s);
println!("{}", s2);
s.push_str(", World!");
}
こんなことすると、エラーとなるわけですね。
理屈としてはsはs2に貸出してんだから、s2の資産勝手にいじっていいわけねーだろと、s2は借りてんだから勝手に壊すなやが両立するわけです。
これのおかげでC++のようにポインタ渡して元の値変えたら、参照している渡し先の値が変わったなんてことがなくなるわけですね。
所有権の借用(可変)
一応、可変借用というものがあります。
例えば銀行からカーローンで買った車改造しますよね?(あれ規約的にアウトな気がしますが)
あんな感じで……借用した変数を扱うことができます。
fn main() {
let mut s = String::from("Hello");
let s2 = &mut s;
s2.push_str(", World!");
println!("{}", s2);
}
さっきはlet s2 = &s;
でしたがlet s2 = &mut s;
となりmut(mutable)がつくことにより可変になるわけですね。
ただ、銀行のカーローンで買った車を銀行が権利保有しているが銀行が「おしカスタマイズしよう」と思い立ってできないのと同じように、以下の場合はエラーとなります。
fn main() {
let mut s = String::from("Hello");
let s2 = &mut s;
s2.push_str(", World!");
println!("{}", s2);
s.push_str(", World!");
}
頭爆散しそう、まぁポインタ渡しとんだから現在ポインタの情報を占有している変数を意識してコーディングしろ!!ってことなんだろうけど……
エディタ側でエラー検知できないから、めちゃくちゃ難しく感じるのは僕だけなんでしょうか?
所有権の破棄
fn main() {
let mut s = String::from("Hello");
let s2 = &s;
let s_mut1 = &mut s;
let s_mut2 = &mut s;
println!("{}", s);
}
所有権の可変借用s_mut1とs_mut2が存在しているのでs_mut1を変更してもsが変更できんちゃうんって思うんですが……エラーになります。
fn main() {
let mut s = String::from("Hello");
let s2 = &s;
let s_mut1 = &mut s; // s2の所有権が消える
let s_mut2 = &mut s; // s_mut1の所有権が消える
println!("{}", s_mut2);
}
実際にこの場合は、新規で所有権が貸与される前までに貸与された所有権は、消えます。
コード上ではわかりづらいですが、賃貸契約と似ていますよね一つ前の契約は切れているので住むことができなくなりますよと考えると、あんまり難しいなぁ。
あとsをlet mut s
で宣言しましたが……それしてない場合例えば
fn main() {
let s = String::from("Hello");
let mut s2 = &s;
let s_mut1 = &mut s;
println!("{}", s_mut1);
}
の場合エラーになります。可変を持たない変数は不変と可変両方同時にすることはできないためです。