Moveの場合は所有権が移ってしまい、以降はその変数が使えなくなります。しかし、時には代入後も所有権を渡したくない時もありますよね。
今回は変数の所有権を渡さない方法である借用についてです。
※注意
借用はとても複雑です。
そのため、今回は基本的な部分のみ説明します。
変数の代入時、所有権を渡さすないようにするには「借用」という方法を使います。
借用は英語で「borrow」と言います。これはコンパイルエラーの時によく出てくる言葉なので覚えておいてください。
以下が借用の例になります。
fn main() {
let value1 = 100;
let value2 : &i32;
value2 = &value1;
println!("value1 is {}", value1);
println!("value2 is {}", value2);
}
value1 is 100 value2 is 100
5行目で変数value1に「&」をつけてvalue2に代入しています。
&を付けて代入をすることを「参照」といいます。
「参照」とは実体を受け取るのではなく、メモリの位置を教えてもらうことです。今回の場合、100という数をvalue2にコピーするのではなく、100という数字がメモリ上のどこにあるのかという情報(アドレス)をvalue2に入れる、ということです。
参照を使った場合、「基本的に」所有権の移動は行われません。このように参照を使って所有権を移動させない仕組みを「借用」と言います。
参照を受けるには、変数の型を参照型にしないといけません。
それを行っているのが3行目です。
let value : &i32;
各変数の型の前に「&」をつけることで参照型にすることができます。
次に、以下の例文のようにvalue1を複数の変数に借用をすることはできるのでしょうか。
fn main() {
let value1 = 100;
let value2 : &i32;
let value3 : &i32;
value2 = &value1;
value3 = &value1;
println!("value1 is {}", value1);
println!("value2 is {}", value2);
println!("value3 is {}", value3);
}
これは問題なくできます。
結果は以下の通りです。
value1 is 100 value2 is 100 value3 is 100
また、以下の例文のように参照を代入することも可能です。
fn main() {
let value1 = 100;
let value2 : &i32;
let value3 : &i32;
value2 = &value1;
value3 = value2;
println!("value1 is {}", value1);
println!("value2 is {}", value2);
println!("value3 is {}", value3);
}
この場合、value2はvalue1の所有権を持っていないので、当然ながらvalue3に所有権が移ることはありません。
ミューダブル、イミューダブルのところでお話しましたが、変数にmutを付けると書き換え可能な変数になります。
しかし、例えmutがついた変数であっても、借用中は値の書き換えができません。
fn main() {
let mut value1 = 100;
let value2 : &i32;
//↓まだ借用していないので代入可能
value1 = 50;
value2 = &value1;
//↓借用中なので書き換え不可
// コンパイルエラーになる
value1 = 150;
println!("value1 is {}", value1);
println!("value2 is {}", value2);
}
参照から変数の値を書き換えるには以下のようにします。
fn main() {
let mut value1 = 100;
let value2 : &mut i32;
value2 = &mut value1;
(*value2) = 150;
println!("value1 is {}", value1);
println!("value2 is {}", value2);
}
value2を「書き換え可能な参照型」として宣言します。(3行目)
そして、参照を渡す時にmutを付け、書き換え可能な参照と明示して渡します。(5行目)
最後に「*」をつけて値を代入します。(7行目)
value2 = &mut value1;
参照経由で変数の値を書き換える時は「*」を付けて代入します。
「*」はアドレスの中身を書き換えるという意味になります。
(*value2) = 150;
ここで注意点です。
Rustは所有権を持っていないと値の書き換えができません。
そのため、書き換え可能な参照を渡す場合は所有権が移動してしまいます。
上記の例文の場合、5行目の時点で所有権はvalue2になります。
value2 = &mut value1;
そして、以降、value1は使えなくなります。
結果、10行目のprintln!の時点でコンパイルエラーになります。
参照は、mutを付ける位置で動作が違うので注意が必要です。
参照型の宣言の仕方は以下の3種類があります。
mutの位置に着目してください。
1. let value : &mut i32; 2. let mut value : &i32; 3. let mut value : &mut i32;
| 値の書き換え | 参照先の変更 | 所有権の移動 | |
|---|---|---|---|
| 1. | 可能 | 不可 | 無し |
| 2. | 不可 | 可能 | 有り |
| 3. | 可能 | 可能 | 有り |
「:」の後の型指定にmutを付けると書き換え可能な参照型になります。(3行目)
fn main() {
let mut value1 = 100;
let value2 : &mut i32;
let mut value3 = 200;
value2 = &mut value1;
(*value2) = 150;
println!("value2 is {}", value2);
//↓コンパイルエラーになる
value2 = &mut value3;
println!("value2 is {}", value1);
しかし、value2はmutがついていないので、参照先、つまりアドレスを書き換えることはできません。(12行目)
letの後ろにmutがあると参照経由で値の書き換えはできません。(3行目)
fn main() {
let mut value1 = 100;
let mut value2 : &i32;
let mut value3 = 200;
value2 = &mut value1;
//↓コンパイルエラーになる
(*value2) = 150;
println!("value2 is {}", value2);
//↓これは大丈夫
value2 = &mut value3;
println!("value2 is {}", value2);
}
しかし、アドレスの書き換えはできるようになります。(13行目)
letの後ろにmutを付け、さらに型の部分にもmutを付けると参照経由で値の書き換えができる上に、アドレスの書き換えもできるようになります。
fn main() {
let mut value1 = 100;
let mut value2 : &mut i32;
let mut value3 = 200;
value2 = &mut value1;
//↓これは大丈夫
(*value2) = 150;
println!("value2 is {}", value2);
//↓これも大丈夫
value2 = &mut value3;
println!("value2 is {}", value2);
}
「書き換え可能な参照型」と「参照型」は全く別物という認識を持つと理解しやすいと思います。
借用は直近の関数が終わると終了します。
fn main() {
let value1 = 100;
let value2 : &i32;
//↓ここから借用開始
value2 = &value1;
println!("value1 is {}", value1);
println!("value2 is {}", value2);
//ここで借用終了
}
今回はそれと関係のある変数の所有権についてです。
変数の所有権はRustの大きな特徴の一つです。
所有権とは何なのか?
以下の例文を見てください。
fn main() {
let name = String::from("hello");
let name2 = name;
println!("name is {}", name);
println!("name2 is {}", name2);
}
何気ない例文になりますが、5行目のprintlnでコンパイルエラーになってしまいます。
理由は、nameに”hello”という文字列の所有権が無いためです。
Rustの変数には所有権という考え方があります。
所有権とは変数の値を書き換えたり参照したりする権利です。
例文では、2行目でnameを宣言して”hello”という文字列を代入した時点では、文字列の所有権はnameにあります。
しかし、3行目でnameをname2に代入した時点で文字列の所有権はname2に移ってしまい、nameは”hello”という文字列にアクセスすることができなくなります。
この変数にアクセスする権利が所有権です。
そして、3行目のように所有権を移動させることを「Move」と言います。
一般的なコンピューター言語では、変数を他の変数に代入すると値がそのままコピーされま。
しかし、Rustは「特定の型の変数以外は」、代入をすると所有権もなくなり、以降はその変数を使うことができなくなります。
所有権により、変数の書き換えや利用を限定することができます。これにより予想外の場所で値が書き換えられたり使われたりすることを防ぐことができます。
先程、代入をすると特定の型以外は所有権が移行すると言いましたが、所有権が移行しない特定の型とは何なのでしょうか?
それはプリミティブ型とタプル型です。
(タプル型については後ほどやるのでここでは省きます。
)
プリミティブ型というのは、i32とかu8などのよく使う変数の型です。
詳しくはこちらをご覧ください。
【Rust入門】基本データ型(プリミティブ型)について
これらプリミティブ型の代入では、値がコピーされるだけで、所有権の移行は行なわれません。他の言語の代入と同じです。
このように、所有権の移動がなく、値がコピーされる動作を「Copy」と言います。
fn main() {
let value : i32 = 150;
let value2 : i32 = value;
println!("name is {}", value);
println!("name2 is {}", value2);
}
この例では、valueとvalue2はプリミティブ型なので代入しても所有権の移動は行なわれません。
そのため、どちらの変数でもprintlnで値を出力することができます。
少し難しいのは文字列の場合です。
文字列はstr型とString型があります。
str型はプリミティブ型なので所有権は移行しません。
反対にString型は所有権が移行します。
[str型]
fn main() {
let text : &str = "hello";
//所有権は移動しない
let text2 : &str = text;
//textもtext2も使える
println!("name is {}", text);
println!("name2 is {}", text2);
}
[String型]
fn main() {
let text : String = String::from("hello");
//所有権が移動
let text2 : String = text;
//textは使えない
println!("name is {}", text);
println!("name2 is {}", text2);
}
普通のプログラム言語なら変数は自由に書き換えることができますが、Rustでは変数の書き換えが基本的にできません。
実は、今までのサンプルも基本的に変数の書き換えはしていませんでした。
では、試しに変数の値を書き換えをしてみます。
以下の例をご覧下さい。
fn main() {
let value = 100;
value = 50;
println!("value is {}", value);
}
これまでも何回も使っていますが、変数は「let」というキーワードで宣言します。
そして、3行目で変数の値を100から50に書き換えています。
結果はどうなるのかというと、書き換えた部分がコンパイルエラーになります
このようにRustは基本的に値を書き換えることができません。このように変数を書き換えられないことをイミュータブル(immutable)な変数と言います。
ちなみにimmutableとは「不変」という意味です。
変数の値を書き換えられないと言っても全て書き換えられないというわけではありません。
Rustの変数は、デフォルトが書き換え不可になっているだけで、キーワードのmutをつけると、書き換え可能な変数になります。
さきほどの例文は以下のようにするとコンパイルエラーが無くなり実行することができます。
fn main() {
let mut value = 100;
value = 50;
println!("value is {}", value);
}
2行目の「mut」が書き換え可能な変数にするキーワードになります。
mutはmutableの略です。
読み方はミューダブル、日本語では「可変」という意味になります。
mutを付けると書き換え可能な変数になりますが、何でもmutをつけるのは良くありません。
設計上、書き換えをしない方が安全に動かせるという理由で、デフォルトがイミューダブルになっていることになります。そのため、可能な限りmutは付けずにコーディングするのが良いでしょう。
変数の値を書き換える方法はもう一つあります。
それはシャドーイングという方法です。
以下のコードを見てください。
fn main() {
let value = 100;
println!("value is {}", value);
let value = 50;
println!("value is {}", value);
}
これはC言語だと4行目で複数回に渡る変数の宣言で、コンパイルエラーになります。
しかし、Rustではコンパイルエラーになりません。
動作としては、4行目のletで新しく同名の変数が作られることになります。
Rustではデフォルトでは変数の値を書き換えることができないので、letで再定義されるまでは変数の値が変わらないことが保証されます。
これにより変数の値の変化が明確になりデバッグが容易になるということです。
今回は文字列についてです。
※少し長めの内容です。
細かいことは知らなくて良いというなら、最後のまとめだけご覧ください。
Rustは文字列を表す型としてstr型とString型があります。
まずはそれぞれの使い方をご紹介します。
fn main() {
let s1 : &str = "this is str";
let s2 : String = String::from("this is String");
println!("{}", s1);
println!("{}", s2);
}
s1がstr型、s2がString型です。
どちらも同じように文字を出力することができます。
イメージとしてはstr型は直接文字列を代入できる。
String型は文字列の初期化が何やら面倒そう…という感じです。
ではそれぞれの違いをご紹介します。
str型とString型、違いは色々ありますが、簡単に言うと、strは変更できない文字列、Stringは変更できる文字列といういとです。
まずはstrについてです。
strはプリミティブ型の一種です。
プリミティブ型を忘れたならこちら。
【Rust入門】基本データ型(プリミティブ型)について
簡単に言うと、i8とかi32みたいによく使う一般的な型ということです。strもこれの一種になります。
そして、変数を明示的にstr型として指定する時は「&」を付けて宣言します。
以下が例です。
fn main() {
let text : &str = "hello";
println!("{}", text);
}
2行目の型指定で「&str」として宣言しています。
この「&」は参照型という意味になります。
strの前に「&」が必要なのは、文字列”hello”の参照を受けているからです。
上の例では、2行目の”hello”という文字列はリテラルになります。
リテラルというのはプログラム上に直接書かれた文字や数字のことです。
この文字列リテラルは「&’static str」という型になります。
これは、メモリのどこかに”hello”という文字分のメモリを確保し、そのメモリの位置を参照するということです。
そして、参照を受けるというのは、メモリ上の位置(アドレス)を教えてもらうということになります。
つまり、例文の変数textは、”hello”という文字が存在するメモリ上の位置を指しているだけということです。
さらにそのメモリは”hello”という文字が入る大きさしか割り当てられていません。
そのため変更できないということですね。
ここまでで、なぜ「&」が必要なのかということですが、textは文字列”hello”の参照になります。参照をするには、変数の型も参照型にしないといけません。
そして、参照型にするには、変数の型の前に「&」を付ける必要があります。
そのため、strは「&」が必要ということです。
ちなみに、文字列リテラルは&’static str型なので、
fn main() {
let text : &'static str = "rust";
println!("{}", text);
}
このように&strではなく、&’static strとしても文字列を出力することができます。
次にStringについてです。
Stringはstrと違い、プリミティブ型ではありません。
そして、strとは違い、文字列を追加したり変更したりすることができます。
fn main() {
let mut s : String = String::from("hello");
s += " world";
println!("{}", s);
}
上は文字列”hello”に” world”を追加して出力する例です。
まずString::fromを使ってString型の文字列を作成します。
ここで大事なのは、let mut として変数を作成することです。
この「mut」は変更可能という意味になります。
詳しくは次でお話します。
このようにして変更可能な変数にすると += を使って&str型の文字列を追加することができます。
こちらの例も見てください。
fn main() {
let mut s1 : String = String::from("hello");
let mut s2 : String = String::from(" world");
s1 += s2;
println!("{}", s1);
}
先ほどと同じに感じますが、こちらはコンパイルエラーになります。
String型を加えることはできません。
この場合、加えるときにs2に「&」をつけて参照を渡すようにしないといけません。
fn main() {
let mut s1 : String = String::from("hello");
let mut s2 : String = String::from(" world");
s1 += &s2;
println!("{}", s1);
}
こうすると無事に文字列を加えることができます。
これだけ見ても分かるように文字列の扱いはかなり複雑です…
最初はなかなかコンパイルが通らなくてかなり苦戦すると思います。
そこで良い方法をご紹介します。
それは、format!を使う方法です。
fn main() {
let mut s1 : String = String::from("hello");
let mut s2 : String = String::from(" world");
s1 = format!("{}{}", s1, s2);
println!("{}", s1);
}
このようにformat!を使えば、簡単に合成することができます。さらにformat!は&str型でもString型でも関係なく合成することができます。
format!の戻り値はString型になります。
Rustでは、文字はchar型の変数にいれます。
char型は4バイトの変数です。
C言語だと1バイトですが、Rustでは様々な言語や絵文字に対応するために4バイトになっています。
文字列から一文字を取得するには以下のようにします。
fn main() {
let mut text : String = String::from("hello");
let v : Vec::<char> = text.chars().collect();
println!("{}", v[0]);
}
一文字取るにもここまで複雑に書かなくてはいけません。
おまけに方法は一つではなく他にもたくさんあります。
最初のうちは意味を考えず定型文として覚えてしまうのも一つの手だと思います。
色々と話しましたが、とりあえずこれだけは覚えておいてください。
]]>Rustは基本的に型が違う変数に値を入れることができません。
しかし、プログラムでは時として変数の値を違う型の変数に渡したい時があります。
そのような時はキャストを使います。
以下がキャストの方法です。
fn main() {
let value1 : u32 = 100;
let value2 : u8;
value2 = value1 as u8;
println!("value2 = {}", value2);
}
実行結果は以下の通りです。
5行目がキャストになります。
強制的に型変換をする時は「as」を使い、後ろに変換する型を書きます。
このようにすればu32型をu8型の値を入れることができます。
キャストをする時は変数の上限値に注意が必要です。
以下のようにu32型をu8型にキャストすると、u8型の上限値を超えてしまう可能性があります。
fn main() {
let value1 : u32 = 300;
let value2 : u8;
value2 = value1 as u8;
println!("value2 = {}", value2);
}
実行結果は以下の通りです。
u8型は1バイト(8ビット)の変数なので上限値は 0 ~ 255 までしか表現できません。
u32型は300を表現できますが、u8型にキャストしてしまうと上限値を超えてしまいます。
そのため、望む結果にならない可能性があります。
上の例の場合、8bitを超えた分は切り捨てられます。
具体的には二進数で表すとわかると思います。
u32 : 0001 0010 1100 → 300 u8 : 0010 1100 → 44
u32と比べて4bit分が消えるので結果は44になります。
整数を小数に入れることができるのは想像できると思いますが、小数から整数にキャストして代入するとどうなるでしょうか?
例えばこのように書きます。
fn main() {
let value1 : f64 = 35.0058;
let value2 : u8;
value2 = value1 as u8;
println!("value2 = {}", value2);
}
結果はこのようになります。
小数点以下が消えてしまいました。
このように小数から整数にキャストする時は注意が必要です。
特定の桁の小数を保持したままキャストをしたい時は、掛け算を使って保持するという方法があります。
fn main() {
let value1 : f64 = 35.0058;
let value2 : u32;
value2 = (value1 * 10_000.0f64) as u32;
println!("value2 = {}", value2);
}
例えば、小数点第4位までを保持するとこうなります。
「*」が掛け算の記号なのですが、このように掛け算をした後にキャストすると擬似的に小数点を保持することができます。
後ほど小数に戻す時は、f64型にキャストして、さらに指定の数値で割れば元に戻ります。
割り算は「/」を使って行います。
fn main() {
let value1 : f64 = 35.0058;
let value2 : u32;
value2 = (value1 * 10_000.0f64) as u32;
println!("value2 = {}", (value2 as f64) / 10_000.0f64 );
}
実行結果は以下の通りです。
ただし、小数点第4位より下の情報は全て消えてしまうので注意してください。
]]>前回は基本データ型(プリミティブ型)について紹介しています。
基本データ型(プリミティブ型)について
数字の書き方なんて覚えるまでもないと思うかもしれませんが、Rustでは色々な数字の表し方があるのでご紹介させていただきます。
例えは、10000000のように桁の多い数字はパッと見ただけでは分かりにくいですよね。
普段の生活では、10,000,000にしてカンマで区切ることはよくありますが、Rustではカンマの代わりに「_」を使って数字を区切ることができます。
| 例 | |
|---|---|
| 100000000 | 100_000_000 |
| 0.000001 | 0.00_0001 |
私達が普段使っている数字は10進数ですが、Rustでは他にも、2進数、8進数、16進数を使うことができます。
| 例:15を表現する | |
|---|---|
| 2進数 | 0b00001111 |
| 8進数 | 0o17 |
| 16進数 | 0x0f |
C言語は2進数の表記ができませんが、Rustでは2進数の表記も対応しています。
そのため、ビット単位の計算をより簡潔に書くことができます。
ちなみに、これらの数の頭に付けた文字「0b」、「0o」、「0x」をプリフィックス(接頭辞)と言います。
Rustでは同じ型の値しか変数へ代入することができません。
例えば
fn main() {
let value : i16 = 30;
}
この例のように変数を宣言して代入をすると、30はi16型として代入されます。
このように数字を代入すると、可能な範囲で変数の型に合わせて自動で型変換をしてくれます。
変換できないこともあるので注意してください。
例えば、整数の型に小数を入れるとコンパイルエラーになります。
fn main() {
let value : i16 = 0.05;// ← 小数は代入できない。コンパイルエラーになる。
}
他には、変数ではなく、代入する数字の方で型を指定する方法があります。
例えば
fn main() {
let value = 30;
}
このように変数を宣言すると、valueはi32型になります。
これをもしu8型として代入したいときは、
fn main() {
let value = 30u8;
}
このように、数字の末尾に型を付けて代入をすることでvalueをu8型として認識させることができます。
Rustでは数字の末尾にに型名を入れることで型を指定することができます。この末尾に入れる文字をサフィックス(接尾辞)と言います。
fn main() {
let value1 = 30u8; // ← u8型
let value2 = 30i32; // ← i32型
let value3 = 30.0f64; // ← f64型
}
このようにすれば、数字で変数の型を指定することができます。
]]>前回はPrint文の書き方をご紹介しました。
気になる方はこちらをご覧ください。
文字列を出力する(Print!、Println!、format!)
Rustでは二種類のコメントの書き方があります。
1行のコメントは「//」を使います。
「//」を見つけるとその後ろが改行までコメントになります。
fn main() {
// 文字列を出力します
println!("Hello World");// ← Hello World と出力します。
}
範囲のコメントは「/* */」を使います。
「/*」から「*/」までがコメントになります。
複数行をコメント化することもできます。
fn main() {
/* ここはコメント
ここがコメントです。
*/ ここはコメントではない
println!("Hello World"/*コメント*/);
}
オレンジの部分がコメントになります。
命令文の中にコメントを埋め込むこともできます。
コメントはプログラムの補足の説明文を書くときに使います。
あとは、一時的に昔のプログラムを残しておく時に使います。
例えば
fn main() {
println!("Hello World");
/*
println!("Hello Rust");
*/
}
こんな感じでコメント化して一時的にプログラムを残すことはよく行います。
]]>前回はコメントの書き方をご紹介しています。
コメントの書き方
Rustは色々なデータ型が使えます。
主要な物は基本データ型(プリミティブ型)と言われています。
以下がプリミティブ型になります。
| プリミティブ型の種類 | |
|---|---|
| ■ 符号あり | |
| i8 | 1バイト |
| i16 | 2バイト |
| i32 | 4バイト |
| i64 | 8バイト |
| i128 | 16バイト |
| isize | サイズ不定型 |
| ■ 符号なし | |
| u8 | 1バイト |
| u16 | 2バイト |
| u32 | 4バイト |
| u64 | 8バイト |
| u128 | 16バイト |
| usize | サイズ不定型 |
| ■ 浮動小数点 | |
| u8 | 4バイト/td> |
| u16 | 8バイト |
| ■ 真理 | |
| bool | 1バイト |
Rustで変数を宣言して使うには以下のようにします。
変数の宣言は「let」というキーワードを書き、その後ろに変数名を書きます。
書き方は2種類あります。
1が型を指定しない書き方、2が明示的に指定する書き方です。
型を明示的に指定しなかった場合、整数ならi32型となり小数ならf64型になります。
fn main() {
let a = 10; // ← i32型になる
let b = 0.005;// ← f64型になる
}
次に型を指定して変数を作成する方法です。
fn main() {
let a : i32 = 10;
let b : f64 = 0.005;
let c : u8;
}
変数名の後ろに「:」を付けてその後ろに型を書きます。
変数の型にisize、usizeというものがありますが、これは使っている環境に合わせて大きさが変わる型になります。
例えば32bitのPCを使っている時はi32、64bitならi64になります。
【図解】Rustをインストールしてみる
【[図解】RustでVisualStudioCodeをエディタ、デバッガとして使う方法
今回からはRustを使ってプログラムを書いていきます。
まずはプログラムの実行結果を表示するのに必須な文字列の出力から行ってみます。
Rustで文字列を出力するには、Print!やPrintln!というマクロを使います。
違いは以下の通りです。
| 関数名 | 動作 |
|---|---|
| Print! | 改行しない |
| Println! | 改行する |
C言語を引き合いに出すと、printfという関数がありますが、使い方はそれとほぼ一緒です。Rustの場合、関数ではなくてマクロで文字列を出力するんですね。
プロジェクトを作ると、すでにHello Worldと出力するようにプログラムされています。
まずはそれを少し変更します。
「Hello, Rust!」と出力してみます。
fn main() {
print!("Hello, Rust!");
}
Println!をPrint!に変えて文字列を変えただけです。
文字列はダブルクォートで括ります。
実行結果は
となります。
同じようにPrintを2つ書いてみます。
fn main() {
print!("Hello, Rust!");
print!("How are you?")
}
実行結果は以下の通りです。
改行が無いですよね。
改行をしたい時は、改行する場所に「¥n」を入れます。
(「¥」はVisual Studio Code上ではバックスラッシュで表示されます)
fn main() {
print!("Hello, Rust!\n");
print!("How are you?")
}
実行結果は以下の通りです。
Printの出力ごとに改行したい時はPrintln!を使います。
fn main() {
println!("My name is Rust!");
println!("I'm 20 years old?");
}
実行結果は
となります。
次に、プレースホルダーを使って文字列の出力をしてみます。
プレースホルダーというのは、指定位置の文字を任意の数値や文字列に置き換えることです。
I am {} years old
プレースホルダーの記号は「{}」になります。
{}を文字列の中に入れておくと、そこの部分を置き換えします。
置き換えは数字でも文字列でも大丈夫です。
fn main() {
println!("My name is {}!", "Rust");
println!("I'm {} years old?", 20);
}
複数の置き換えをしたい時は、プレースホルダーを複数個配置し、置き換えする文字や数字をカンマで区切って並べます。
fn main() {
println!("My name is {}! I'm {} years old?", "Rust", 20);
}
文字列の先頭から{}が見つかった順番に置き換えしてくれます。
実行結果は以下の通りです。
数字の場合、フォーマット方法を指定して桁数を揃えて出力することもできます。
例えば、{:5}とすると5桁に揃えて出力してくれます。
以下がプレースホルダーのフォーマットの例です。
| 15を変換して出力する時 | |
|---|---|
| ※ スペースは「_」で表記しています | |
| {:5} | ___15 |
| {:05} | 00015 |
| {:b} | 1111 |
| {:8b} | ____1111 |
| {:08b} | 00001111 |
| {:o} | 17 |
| {:8o} | ______17 |
| {:08o} | 00000017 |
| {:.3} | 15.000 |
| {:x} | f |
| {:8x} | _______f |
| {:08x} | 0000000f |
使うのはこれくらいだと思います。
注意点として、{:.3}の書き方は小数の場合のみ適用されます。
例えば、15を8桁の16進数で表記する例は以下の通りです。
fn main() {
print!("0x{:08x}", 15);
}
もう一つ、8桁の2進数で表記してみます。
fn main() {
println!("0b{:08b}", 15);
}
Print!、Peintln!は文字列をターミナルに出力しますが、時として、出力せず文字列として変数に保存だけしたいこともあります。
そんな時はFormat!を利用します。
使い方はPrintと同じです。
fn main() {
let s = format!("I'm {} years old", 20 );
print!("{}", s);
}
マクロの実行結果を変数で受け取ります。
文字列を扱う時は、Print!、Peintln!、Format!はとてもよく使うのでぜひ覚えておいてください。
]]>その時、ソースファイルをメモ帳で開いたのですが、メモ帳だと編集能力に欠けるので、Visual StudioCodeを使って編集ができるようにしていきます。
まずはVisual Studio Code をインストールします。
こちらのサイトからダウンロードができます。
インストール後、必要であれば日本語化します。
日本語化をするには、「上部メニュー」→「View」→「Command Palette」を開きます。
入力画面に「configure display language」と入力します。
「install additional language」を選択します。
左側にビューが開いてインストールする言語が選択できるので「日本語」を選びます。
そして「install」をクリックしてインストールします。
右下にポップアップで「in order to use VS Code in Japanese, VS Code needs to restart.」と出るので、「Restart Now」をクリックする。
再起動したら日本語化が完了です。
Visual Studio CodeはRust専用のエディタではありません。そのため、Rustの編集とデバッグをするには、拡張機能を追加しないといけません。
色々な拡張機能がありますが、ここでは以下の2つの拡張機能を使います。
まずは、画面左の四角がたくさん書かれたアイコンをクリックしてください。
すると拡張機能を追加するビューが開きます。
上部にある検索ボックスの中に「Rust」と入力します。
そこで出てくる「Rust for Visual Studio Code」を追加します。
下図のアイコン(茶色い歯車にRが付いた絵)を目印にしてください。
これはRustの文法に合わせて入力補完などをしてくれる拡張機能です。
アイコンのそばにある緑の「install」をクリックしてインストールします。
次にデバッガを追加します。
検索で「LLDB」と入力して「Code LLDB」という拡張機能を検索します。
かっこいい龍のアイコンが目印です。
Code LLDBはPythonが無いと動かないようです。
Pythonがインストールされていない場合、要求されたバージョンのPythonをインストールしてください。
Pythonはこちらのサイトからインストールすることができます。
Visual Studio Codeの設定したらデバッグしてみましょう。以下の手順でデバッグの設定をします。
まず、画面左の一番上のアイコン(ファイルのアイコン)をクリックして、ワークスペースのビューを開きます。
適当なところで右クリックをし、メニューから「ワークスペースにフォルダーを追加」を選びます。
作成したプロジェクト「helloworld」のフォルダを選択して「追加」を押します。
これでフォルダをワークスペースに追加できました。
追加したらデバッグ用のコンフィグ設定を行います。
画面左の再生ボタンと虫のアイコンをクリックします。
上のコンボボックスから「構成(helloworld)の追加」を選びます。
選ぶと、コンフィグファイルを作るか聞かれるので「Yes」を選びます。
これで完成です。
それではブレークポイントを配置してデバッグ実行してみます。
ワークスペースの画面に戻り、main.rs を開きます。
そして、2行目にカーソルを合わせてF9キーを押下します。
すると赤い丸がつくと思います。
これでブレークポイントを設定できました。
では実行をしてみます。
実行は画面左のデバッグアイコンからデバッグビューを開き、上部にある再生ボタンを押します。
もしくはショートカットで「F5」キーが設定されているので、F5を押しても実行できます。
再生したら2行目でプログラムが止まります。
行が黄色になっていればそこでプログラムが止まっているということになります。
プログラムをステップ実行をする方法は以下の通りです。
| ショートカット | 動作 |
|---|---|
| F10 | 一行ずつ実行 |
| F11 | 1行ずつ実行 (関数があればその中に入る) |
| F5 | 再実行 |
となっています。
今回はF5キーで再実行をしてプログラムを終了させます。
実行結果は、ターミナルで見ることができます。
デフォルトでは恐らくターミナルが画面下部に表示されていると思います。
もし表示されていないなら
「上部メニュー」→「表示」→ 「ターミナル」
でターミナルウィンドウを開きます。
ここに実行結果が表示されます。
今回の場合、「Hello World」と出力されれば成功です。
ターミナルに文字が表示されない時は表示がコマンドプロンプトに設定されていない可能性があります。
ターミナル画面右上にあるコンボボックスから「既定のシェルの選択」を選びます。
そして、「Command Prompt」を選択してください。
これで Visual Studio Code の設定は完了です。
次回からRustの文法をやっていきます。