前回からだいぶ間が空いてしまいましたが、Rustの勉強を続けていきたいと思います。ちなみに言い訳をしておきますが、9月前半が予定が立て込んでであまり更新できなかっただけで別に飽きたわけではないです。

…飽きたわけではないです。大事なことなので2回。

前置き

この記事はまだRustをよく知らない人が勉強しながら書いているので、もしかしたら間違ったことが書いてあるかもしれません。ご了承ください。

参考文献

The Rust Programming Language 日本語版

関数

fn show_message() {
  println!("Hello World!");
}

fn main() {
  show_message();
}
Hello World!

基本的にはC++と同じ。Rustの命名規則では、関数と変数はスネークケース(show_messageやload_dataなど)を使うのが慣例だそうです。ちなみに、

fn main() {
  show_message();
}

fn show_message() {
  println!("Hello World!");
}

このように、呼び出す関数が後ろに定義されていてもOK。C++は呼び出す前に関数を定義しなければならなかったので便利ですね。

引数を使う

当然ながら関数に引数を使うこともできます。

fn show_figures(x: i32, y: i32) {
  println!("x={}, y={}", x, y);
}

fn main() {
  show_figures(100, 200);
}
x=100, y=200

show_figuresのxとyを仮引数といいますが、仮引数を宣言する際は型宣言が必要だそうです。つまり、整数であればx: i32x: i64などと仮引数の型を明確に定義しなければなりません。

値を返す

Rustでは、何らかの値を返す関数を式、何の値も返さない関数を文と分類します。さきほどのshow_messageshow_figureは文です。
今度は値を返す関数である式を作成してみます。

fn kakeru_100(x: i32) -> i32 {
  x * 100
}

fn main() {
  let x = kakeru_100(123);
  println!("x={}", x);
}
x=12300

kakeru_100は仮引数に対し100を掛けた値を返す関数です。-> i32によって返り値の型を指定しています。main関数では、xに引数を123としたkakeru_100の値を代入します。ここで重要なのは、Rustではセミコロン;がない式が返り値として識別されるという点です。

フロー制御

フロー制御とは何かというと、if文とかループとかですね。与えられた変数の条件によって{}の中身を実行するか否かが変化する、条件分岐を伴う処理のことです。

if文

Rustのif文はC++みたいに()でくくる必要はありません。なんだかHSP3を思い出します。

fn main() {
  let x = 100;
	
  if x == 50 {
    println!("x is 50");
  } else {
    println!("x is not 50");
  }
}
x is not 50

let文内のif文

if文は式であるため、こんな使い方もできます。

fn main() {
  let a = true;
  let num = if a {
    1
  } else {
    0
  };

  println!("num == {}", num);
}
num == 1

上記のプログラムでは、変数numと数値を束縛する際に、aがtrueなら1、falseなら0を束縛します。

繰り返し

繰り返し処理には3種類も存在するらしいです。loopforwhileです。

loop

forwhileは想像がつきますが、loopは何かというと、要は無限ループです。

fn main() {
  loop {
    println!("無限ループって怖くね?");
  }
}
無限ループって怖くね?
無限ループって怖くね?
無限ループって怖くね?
無限ループって怖くね?
︙

上記のプログラムではControl+Cで中断させない限り永遠に表示され続けます。breakを使えば中断させることができますが、それだったらwhileでよくね?って気もします。

while

おなじみ条件付きループ。使い方も今まで触ってきた言語と変わってなくて安心します。

fn main() {
  let mut count = 5;

  while count >= 0 {
    println!("{}", count);
    count -= 1;
  }
  println!("done.");
}
5
4
3
2
1
0
done.

for

こちらもおなじみ。変数宣言もfor文内で行えます。Range型を使うと、a..bでaからb-1までカウントしてくれます。

fn main() {
  for i in 1..11 {
    println!("{}", i);
  }

  println!("done.");
}
1
2
3
4
5
6
7
8
9
10
done.

a..=bとすれば、aからbまでの間をカウントしてくれます。

fn main() {
  for i in 1..=11 {
    println!("{}", i);
  }

  println!("done.");
}
1
2
3
4
5
6
7
8
9
10
11
done.

逆順にするにはrevを使います。

fn main() {
  for i in (1..=11).rev() {
    println!("{}", i);
  }

  println!("done.");
}
11
10
9
8
7
6
5
4
3
2
1
done.

C++やPythonと同様に配列を順に参照することもできます。

fn main() {
  let array = [3, 6, 9, 12];
  for element in array {
    println!("{}", element);
  }

  println!("done.");
}
3
6
9
12
done.

FizzBuzz

せっかくなのでRustでFizzBuzzを作ってみました。プログラミングの入門書によく出てくる、3の倍数なら「Fizz」5の倍数なら「Buzz」と出力するアレです。
関数fizz_buzzを作成し、1から引数に指定した数までカウントアップさせています。

fn fizz_buzz(x: i32) {
  for i in 1..=x {
    if i % 15 == 0 {
      print!("FizzBuzz");
    } else if i % 3 == 0 {
      print!("Fizz");
    } else if i % 5 == 0 {
      print!("Buzz");
    } else {
      print!("{} ", i);
    }

    println!();
  }
}

fn main() {
  fizz_buzz(20);
}
1 
2 
Fizz
4 
Buzz
Fizz
7 
8 
Fizz
Buzz
11 
Fizz
13 
14 
FizzBuzz
16 
17 
Fizz
19 
Buzz

終わりに

所有権や可変性のように独特な縛りは多いものの、今までの言語で「あったらいいな」と思っていたものが実装されていたり、少しづつRustの魅力が理解できるようになってきた気がします。
基本的にThe Rust Programming Languageに沿って進めています。今回は簡単な内容でしたが、どうやら次回は難しそうです。近日中に進めたいと思います。