[Rust]Rustlingsで学ぼう(Functions)

Rustlings

Rustlingsとは

RustlingsはRustコードに慣れるための演習が詰まったパッケージです。
概要その他については以下を参照してください。

今回の演習

今回はFunctions(関数)です。
The Bookでは「3.3. Functions(3.3. 関数)」になり、関数の概念とルールが記述されています。

functions

それではfunctionsの5問です。

functions1

  Compiling of exercises/functions/functions1.rs failed! Please try again. Here's the output:
error[E0425]: cannot find function `call_me` in this scope
 --> exercises/functions/functions1.rs:9:5
  |
9 |     call_me();
  |     ^^^^^^^ not found in this scope

error: aborting due to 1 previous error

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

宣言されていない関数呼び出しはできないよ、と言われています。

なので関数宣言を追加しましょう。

fn call_me() {}

ここでRustにおける関数のルールをいくつか

  • Rustの命名規則では、関数、変数ともにスネークケースが慣例です。スネークケースとは、小文字とアンダースコア(単語区切り)を使うことです。
  • 関数名の前にfnキーワードで宣言します。
  • 関数名の後に引数を含む丸括弧を記述します。
  • 丸括弧の後に、矢印(->)と戻り値の型を定義します。戻り値がない場合は不要です。
  • これらの後に波括弧と共に関数の内容を記述します。
  • 関数を呼び出す際は、関数名に丸括弧の組を続けることで呼び出せます。
  • 関数宣言自体は呼び出しの前後いずれでも可能です。

functions2

⚠️  Compiling of exercises/functions/functions2.rs failed! Please try again. Here's the output:
error: expected type, found `)`
  --> exercises/functions/functions2.rs:12:16
   |
12 | fn call_me(num:) {
   |                ^ expected type

error[E0425]: cannot find value `num` in this scope
  --> exercises/functions/functions2.rs:13:17
   |
13 |     for i in 0..num {
   |                 ^^^ not found in this scope
   |
help: you might have meant to write `.` instead of `..`
   |
13 -     for i in 0..num {
13 +     for i in 0.num {
   |

error: aborting due to 2 previous errors

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

次は関数の引数に関するエラーです。関数宣言における引数は型宣言が必須です。そのため、今回のようなnum:はエラーとなります。

なので型宣言を追加しましょう。

fn call_me(num: i32) {

ここでは関数の引数に関するルールをいくつか(「3.3. functions」の記述のみで)

  • 引数には型宣言が必須です。
  • 複数の引数をもたせる場合はカンマで区切ります。

functions3

⚠️  Compiling of exercises/functions/functions3.rs failed! Please try again. Here's the output:
error[E0061]: this function takes 1 argument but 0 arguments were supplied
  --> exercises/functions/functions3.rs:9:5
   |
9  |     call_me();
   |     ^^^^^^^-- an argument of type `u32` is missing
   |
note: function defined here
  --> exercises/functions/functions3.rs:12:4
   |
12 | fn call_me(num: u32) {
   |    ^^^^^^^ --------
help: provide the argument
   |
9  |     call_me(/* u32 */);
   |            ~~~~~~~~~~~

error: aborting due to 1 previous error

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

これはとても単純でしょう。引数を定義している関数なのに引数を与えずに呼び出しているのでエラーとなっています。

なのでu32な引数を与えましょう。(あまり大きい数値を入れないように!なぜなら数値分だけ出力されます)

fn main() {
    call_me(10);
}

functions4

  Compiling of exercises/functions/functions4.rs failed! Please try again. Here's the output:
error: expected type, found `{`
  --> exercises/functions/functions4.rs:18:30
   |
18 | fn sale_price(price: i32) -> {
   |                              ^ expected type

error: aborting due to 1 previous error

関数宣言で矢印(->)を入力したのに型を定義していないのでエラーとなっています。

なので型を記述しましょう。

fn sale_price(price: i32) -> i32 {

ところで、この課題に含まれる関数は着目すべき点があります。それは戻り値の記述方法です。

price - 10

num % 2 == 0

Rustの関数は最後に評価された式(Expressions)を戻り値とします。このことを正確に理解するためには、文(Statements)と式(Expressions)の違いを知る必要があります。

  • 文(Statements)とは何らかの動作をして値を返さない命令です。
  • 式(Expressions)とは評価の結果を返します。

日本語版の説明を一度は読んだ方が良いので目を通してみてください。

functions5

⚠️  Compiling of exercises/functions/functions5.rs failed! Please try again. Here's the output:
error[E0308]: mismatched types
  --> exercises/functions/functions5.rs:13:24
   |
13 | fn square(num: i32) -> i32 {
   |    ------              ^^^ expected `i32`, found `()`
   |    |
   |    implicitly returns `()` as its body has no tail or `return` expression
14 |     num * num;
   |              - help: remove this semicolon to return this value

error: aborting due to 1 previous error

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

functions4でも触れました、式と文の違いによりエラーが出ています。関数squareの本体はnum * num;ですが、この記述はセミコロンがあるため、文になります。文は値を返さないため、関数は値を返せませんが、返り値の型定義と異なるためにエラーになっている、というものです。

なのでセミコロンを削除しましょう。

fn square(num: i32) -> i32 {
    num * num
}

rustc --explain

エラーコードです。

E0425 -- function1, function2

An unresolved name was used.

Erroneous code examples:

something_that_doesnt_exist::foo;
// error: unresolved name `something_that_doesnt_exist::foo`

// or:

trait Foo {
    fn bar() {
        Self; // error: unresolved name `Self`
    }
}

// or:

let x = unknown_variable;  // error: unresolved name `unknown_variable`

Please verify that the name wasn't misspelled and ensure that the identifier being referred to is valid
for the given situation. Example:

enum something_that_does_exist {
    Foo,
}

Or:

mod something_that_does_exist {
    pub static foo : i32 = 0i32;
}

something_that_does_exist::foo; // ok!

Or:

let unknown_variable = 12u32;
let x = unknown_variable; // ok!

If the item is not defined in the current module, it must be imported using a use statement, like so:

use foo::bar;
bar();

If the item you are importing is not defined in some super-module of the current module, then it must
also be declared as public (e.g., pub fn).

variableでも説明したので割愛しますね。

E0061 -- functions3

An invalid number of arguments was passed when calling a function.

Erroneous code example:

fn f(u: i32) {}

f(); // error!

The number of arguments passed to a function must match the number of arguments specified in the
function signature.

For example, a function like:

fn f(a: u16, b: &str) {}

Must always be called with exactly two arguments, e.g., f(2, "test").

Note that Rust does not have a notion of optional function arguments or variadic functions (except for its C-FFI).

関数呼び出し時の引数の数に関するエラーです。functions3に関するエラーとしてはとても適切ですね。

注意するところは最後の行でしょうか。Rustの関数にはオプション引数や可変長引数の概念はありません。(もちろん、他言語利用のためFFIは違いますが。)他言語を使用している場合は意識しておく必要があります。

E0308 -- functions5

Expected type did not match the received type.

Erroneous code examples:

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

plus_one("Not a number");
//       ^^^^^^^^^^^^^^ expected `i32`, found `&str`

if "Not a bool" {
// ^^^^^^^^^^^^ expected `bool`, found `&str`
}

let x: f32 = "Not a float";
//     ---   ^^^^^^^^^^^^^ expected `f32`, found `&str`
//     |
//     expected due to this

This error occurs when an expression was used in a place where the compiler expected an expression of a
different type. It can occur in several cases, the most common being when calling a function and passing an argument which has a different type than the matching type in the function declaration.

Rustは型厳し目でして、他言語にあるような暗黙的型変換は行われません。(型強制、参照外しやカプセル化などの変換はありますが、よくある文字列、数値、真偽値の暗黙的変換などはないです。)

つまり、型マッチしていない実引数を指定しているということを示すエラーがこのエラーコードです。

最後に

このfunctionsでは、式(Expressions)と文(Statements)の違いが特に重要です。他の言語ではあまり意識しませんが、Rustは式指向言語のため、至るところで式を便利?に使用するのでしっかり理解しておきましょう。

タイトルとURLをコピーしました