やってみる

アウトプットすべく己を導くためのブログ。その試行錯誤すらたれ流す。

Rustの関数

 文だけでなく式で終わることもできるのが最大のポイントか。

成果物

コード

0. 宣言

main.rs

fn main() {
    sub_fn();
}
fn sub_fn() {
    println!("Hello Rust !!");
}
$ rustc main.rs
$ ./main
Hello Rust !!
  • 宣言にはfnが必要
  • 宣言する位置はmainの下でもOK
  • 名前はスネークケース(すべて小文字で_を単語区切文字とする)

1. 引数

main.rs

fn main() {
    show_age(66);
}
fn show_age(age: i32) {
    println!("My age is {}.", age);
}

 もし関数の引数に型を指定しなければ、以下エラー。

error: expected one of `:` or `@`, found `)`
 --> main.rs:8:16
  |
8 | fn show_age(age) {
  |                ^ expected one of `:` or `@` here

1-1. 複数

fn main() {
    show_coordinate(12, 34);
}
fn show_coordinate(x:i32, y:i32) {
    println!("({}, {})", x, y);
}

 複数の引数があるときはカンマ,で区切る。

2. 式

 Rustの関数は、最後が文で終わるものだけでなく、式で終わるものも作れる。(Pythonでいうlambda式のように式で終わるものも作れる)

2-0. 文と式

対象 終端
返さない ;
返す ;なし

 終端に;を付与すると文になる。たとえば1 + 1は式だが、1 + 1;は文になる。罠になりそう。

fn main() {
    let x = 1;
    let y = (let z = 2); // error: expected expression, found statement (`let`)
}
error: expected expression, found statement (`let`)
 --> main.rs:7:14
  |
7 |     let y = (let z = 2);
  |              ^^^ expected expression
  |
  = note: variable declaration using `let` is a statement

error: aborting due to previous error

 式を期待していたが、文が見つかったときのエラー。左辺は値が返ってくることを期待しているが、右辺が文であり、文は値を返さないため、エラーになる。

2-0-1. 関数の最後が式

 以下のようにすると成功する。

fn main() {
    let x = 1;
    let y = { x + 1 };
    println!("{} {}", x, y); // 1 2
}

 x + 1の終端に;がないことに注目。これは式である。そしてブロック{}で新たなスコープを作っている。{}も式。ちなみに関数呼出も式。

2-0-2. 関数の最後が文

 もし式x + 1の終端に;をつけて文にすると?

fn main() {
    let x = 1;
    let y = { x + 1; };
    println!("{} {}", x, y); // 1 2
}
$ rustc main.rs
error[E0277]: `()` doesn't implement `std::fmt::Display`
 --> main.rs:9:26
  |
9 |     println!("{} {}", x, y);
  |                          ^ `()` cannot be formatted with the default formatter
  |
  = help: the trait `std::fmt::Display` is not implemented for `()`
  = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
  = note: required by `std::fmt::Display::fmt`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0277`.

 フォーマットを変更すると、警告は出るものの実行できた。

fn main() {
    let x = 1;
    let y = { x + 1; };
    println!("{} {:?}", x, y);
}
$ rustc main.rs
warning: unused arithmetic operation that must be used
 --> main.rs:8:15
  |
8 |     let y = { x + 1; };
  |               ^^^^^
  |
  = note: #[warn(unused_must_use)] on by default
$ ./main
1 ()

 ()って何? 要素数がゼロのタプル? わからん。

3. 戻り値

fn main() {
    let x = five(); // `let = 5;`と同義
    println!("{}", x);
}
fn five() -> i32 {
    5
}

 five()関数の最後に;がないので式である。式は値を返す。関数で値を返すには戻り値を宣言する必要がある。fn 関数名() -> i32i32がそれ。名前はつけず型を指定する。

 代入せず直接わたすこともできる。

fn main() {
    println!("{}", five());
}
fn five() -> i32 {
    5
}

4. 引数と戻り値

fn main() {
    let x = add_one(9);
    println!("{}", x);
}
fn add_one(x: i32) -> i32 {
    x + 1
}
$ rustc main.rs
$ ./main
10

 add_one関数の最後であるx + 1の終端に;をつけて文にすると、以下エラー。

$ rustc main.rs
error[E0308]: mismatched types
  --> main.rs:9:23
   |
9  | fn add_one(x: i32) -> i32 {
   |    -------            ^^^ expected i32, found ()
   |    |
   |    this function's body doesn't return
10 |     x + 1;
   |          - help: consider removing this semicolon
   |
   = note: expected type `i32`
              found type `()`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0308`.

 「戻り値としてi32を期待していたのに()が見つかった」と怒られる。

 だが、文だとしてもreturnすれば成功した。

fn add_one(x: i32) -> i32 {
    return x + 1;
}

 これはC/C++言語でおなじみ。

参考

対象環境

$ uname -a
Linux raspberrypi 4.19.42-v7+ #1219 SMP Tue May 14 21:20:58 BST 2019 armv7l GNU/Linux

前回まで