Open7

Rustを学ぶ

ぴ

Cargo の使い方

開発

  • cargo new を使ってプロジェクトを作成できる
  • cargo build を使ってプロジェクトをビルドできる
  • cargo run を使うとプロジェクトのビルドと実行を 1 ステップで行える
  • cargo check を使うとバイナリを生成せずにプロジェクトをビルドして、エラーがないか確認できる

ビルド成果はtarget/debugに出力される

リリース

cargo build --releasetarget/releaseに最適化したバイナリが出力される

ぴ

Hello World

関数の定義

fu 関数名() {}で関数定義する
Rust はmainが最初に実行される

fn main() {
  println!("Hello, world!");
}
Hidden comment
ぴ

変数と可変性

変数はデフォルトで不変になる。

fn main() {
    let x = 5;
    println!("The value of x is: {}", x);
    x = 6;
    println!("The value of x is: {}", x);
}

これはエラーになるので、let mut x =... とする。

定数と変数の違い

const MAX_POINTS: u32 = 100_000;

不変変数と何が違うの?

  • constで定義して、常に型注釈が必要。
  • グローバルスコープ含めてどこでも定義できる
  • 定数は定数式にしかセットできない。関数の実行結果のような実行時に評価される値には使えない。

シャドーイング

letで変数名を再定義することで覆い隠すように使える。

fn main() {
    let x = 5;

    let x = x + 1;

    {
        let x = x * 2;
        println!("The value of x in the inner scope is: {}", x);
    }

    println!("The value of x is: {}", x);
}

mutableにしてないので、スコープ内で不変な変数にできる。

特に力を発揮するのが型を変えたい場面です。
ユーザーから数字を入力して欲しいような場面で、stdinを使うと文字列の数字が入ってくる。
これをシャドーイングで、数値型で覆い隠してあげれば、無駄に変数を用意しないでいいから良き。

let mut guess = String::new();

io::stdin()
    .read_line(&mut guess)
    .expect("Failed to load line");

let guess: u32 = guess.trim().parse().expect("Please type a number!");
ぴ

データ型

普通は変数の使い方から、コンパイラが型を推論してくれる。.parseメソッド見たいな、複数の型を取りうる使い方をした場合は、型注釈を必ず書かないとダメ。むしろ、型注釈に沿って挙動が変わるのおもろい。

let guess = "42".parse().expect("Not a number!");
$ cargo build
   Compiling no_type_annotations v0.1.0 (file:///projects/no_type_annotations)
error[E0282]: type annotations needed
              (型注釈が必要です)
 --> src/main.rs:2:9
  |
2 |     let guess = "42".parse().expect("Not a number!");
  |         ^^^^^ consider giving `guess` a type
  |               (`guess`に型を与えることを検討してください)

For more information about this error, try `rustc --explain E0282`.
error: could not compile `no_type_annotations` due to previous error

スカラー型

整数、浮動小数点数、論理値、文字列の四つのスカラー型がある。
整数のu64とか浮動小数点数のf64とかこの辺はCと似てる感じ。

複合型

タプルと配列がある。

タプル

位置で型がつく。

fn main() {
    let tup: (i32, f64, u8) = (500, 6.4, 1);
}

パターンマッチングで分配して取り出せる。

fn main() {
    let tup = (500, 6.4, 1);

    let (x, y, z) = tup;

    println!("The value of y is: {}", y);
}

x.0みたいに、.で繋げてインデックスでアクセスできる。

fn main() {
    let x: (i32, f64, u8) = (500, 6.4, 1);

    let five_hundred = x.0;

    let six_point_four = x.1;

    let one = x.2;
}

配列

型の指定

let a: [i32; 5] = [1, 2, 3, 4, 5];

初期値の指定とインデックスアクセス。

let a = [3; 5];
// let a = [3, 3, 3, 3, 3] これと同義

let first = a[0];

配列の範囲外アクセスをしようとした時、実行時エラーでパニくる。
JS書いてると当たり前だと思うけど、低レベル言語だと、意図せず範囲外アクセスで変なメモリを読んでしまったりするので安心。

use std::io;

fn main() {
    let a = [1, 2, 3, 4, 5];

    println!("Please enter an array index.");
           // 配列の何番目の要素にアクセスするか指定してください

    let mut index = String::new();

    io::stdin()
        .read_line(&mut index)
        .expect("Failed to read line");
              // 値の読み込みに失敗しました

    let index: usize = index
        .trim()
        .parse()
        .expect("Index entered was not a number");
           // 入力された値は数字ではありません

    let element = a[index];

    println!(
        "The value of the element at index {} is: {}",
        // {}番目の要素の値は{}です
        index, element
    );
}
ぴ

所有権

とりあえずメモする前に読み切っていくぅ

Rust好きになってきた