Charaken 技術系ブログ

技術系に関して学んだことや、気になったことを記事にしていく。

【Rust】がばがばRust独学 - 2. 関数

f:id:charaken:20191223210559p:plain

Rustの公式ドキュメントを通して、Rustを独学していく記事になります。(がば要素あり)

doc.rust-lang.org

今回は、関数について学びつつ、気になった点をコード確認した結果を記事にしています。

  • versions
$ rustc --version
rustc 1.40.0 (73528e339 2019-12-16)


関数

example

fn plus_one(x: i32) -> i32 {
    x + 1
}

fn main() {
    let x = plus_one(3);
    println!("x -> {}", x);
}
x -> 4

基本形

fn から始まり、関数名(下記では hogera )によって関数を定義し、hogera() により関数を呼び出します。

fn main() {
    println!("Hello World!");
    hogera();
}

fn hogera() {
    println!("Another funciton!");
}
Hello World!
Another funciton!

また、関数の順序はなさそうです。

fn hogera() {
    println!("Another funciton!");
}

fn main() {
    println!("Hello World!");
    hogera();
}
Hello World!
Another funciton!

引数

x: i32 のように、引数名と型を定義することによって、引数を利用できます。

fn main() {
    println!("Hello World!");
    hogera(256);
}

fn hogera(x: i32) {
    println!("Number -> {}", x);
}

もし、型がない場合は、型をつけろよと怒られます。

if this was a parameter name, give it a type

fn main() {
    println!("Hello World!");
    hogera(256);
}

fn hogera(x) {
    println!("Number -> {}", x);
}
error: expected one of `:`, `@`, or `|`, found `)`
 --> demo.rs:6:12
  |
6 | fn hogera(x) {
  |            ^ expected one of `:`, `@`, or `|` here
  |
  = note: anonymous parameters are removed in the 2018 edition (see RFC 1685)
help: if this was a parameter name, give it a type
  |
6 | fn hogera(x: TypeName) {
  |           ^^^^^^^^^^^
help: if this is a type, explicitly ignore the parameter name
  |
6 | fn hogera(_: x) {
  |           ^^^^

error: aborting due to previous error

複数渡す場合は、 , 区切りによって定義可能です。

fn main() {
    println!("Hello World!");
    hogera(256, 512);
}

fn hogera(x: i32, y: i32) {
    println!("x -> {}", x);
    println!("y -> {}", y);
}
Hello World!
x -> 256
y -> 512

Expension、ブロック( {}

Rustは式ベースの言語です。

Rust is an expression-based language

新しいスコープを生成するためにブロック({})を使用します。 下記の場合、 x に対するスコープの違いにより、main 関数における x と、y のブロック(式)によるスコープの違いにより、y5 + 10 となります。

fn main() {
    let x = 3;
    let y = {
        let x = 5;
        x + 10
    };
    println!("x -> {}, y -> {}", x, y);
}
x -> 3, y -> 15

また、 ブロック内でxの定義 let x をしない場合は、ブロック外の変数をスコープして使用します。

fn main() {
    let x = 3;
    let y = { x + 10 };
    println!("x -> {}, y -> {}", x, y);
}
x -> 3, y -> 13

返り値

返り値の型は、下記例では i32 のように、関数にアロー( -> )を利用して記載することが可能です。また、返り値には文末のセミコロンが不要です。

fn two() -> i32 {
    2
}

fn main() {
    let x = two();
    println!("x -> {}", x);
}
x -> 2

返り値の型を宣言しない場合は、 型が違うと言われます。

fn two() {
    2
}

fn main() {
    let x = two();
    println!("x -> {}", x);
}
error[E0308]: mismatched types
 --> demo.rs:2:2
  |
1 | fn two() {
  |          - possibly return type missing here?
2 |     2
  |     ^ expected (), found integer
  |
  = note: expected type `()`
             found type `{integer}`

文末にセミコロンを使用した場合は、返り値の型が違うぞと言われます。

fn two() -> i32 {
    2;
}

fn main() {
    let x = two();
    println!("x -> {}", x);
}
error[E0308]: mismatched types
 --> demo.rs:1:13
  |
1 | fn two() -> i32 {
  |    ---      ^^^ expected i32, found ()
  |    |
  |    implicitly returns `()` as its body has no tail or `return` expression
2 |     2;
  |      - help: consider removing this semicolon
  |
  = note: expected type `i32`
             found type `()`

セミコロンに関しては、 return の糖衣構文であるため、 return をつけて上げると、実行可能です。 個人的には、 return が無いほうがシンプルに書けるので、つけない方向で書いていきたいが、 return を使わなければならないパターンがあるのだろうか・・・

fn two() -> i32 {
    return 2;
}

fn main() {
    let x = two();
    println!("x -> {}", x);
}
x -> 2