(言語基礎(1)— 概要・関数・変数)= # 言語基礎(1)— 概要・関数・変数 ## この章で学ぶこと - Mojo の基本的な考え方 - 関数の書き方と読み方 - 変数とスコープの基本 この章では、[Mojo Manual](https://docs.modular.com/mojo/manual/) の [Language basics](https://docs.modular.com/mojo/manual/basics/) にあたる内容のうち、全体像・関数・変数を整理します。 公式の同じ見出しを開きながら読むと、流れを追いやすいです。 本章のコード例は **Mojo 0.26 系** で確認しています。 `def ... raises -> T` が使える版です。 **0.24 系など古い版** では、`raises` の扱いが異なることがあります。 その場合は次を確認してください。 - [Mojo Manual — Functions](https://docs.modular.com/mojo/manual/functions/) - [Mojo changelog](https://docs.modular.com/mojo/changelog/) ## Language basics まず大事なのは、**Mojo は Python に似た書き方をしつつ、別の言語として設計されている**ことです。 ポイントは次の通りです。 - 構文は Python に近い - ただし **静的型** で動く - **メモリ安全** を重視している - CPU や GPU を意識した、次世代コンパイラ基盤の上で使われる ここで大事なのは、**見た目が Python でも、中身の考え方はかなり違う**ことです。 ### 最初に押さえること - エントリポイントは **`def main()`** - ブロックは **`:` とインデント**で表す - 変数は **`var`** または暗黙宣言で作る - いったん決まった型は、あとで別の型に変えられない - 関数は **`def`** で定義する - 型やメソッドのまとまりは **`struct`** で表す - Python モジュールを使う入口もある たとえば、NumPy などの Python 資産を使えるのは Mojo の大きな特徴です。 ただし、この章では入口だけ押さえれば十分です。 ### 最小の例 次の例では、エントリポイント、型注釈付きの `var`、型推論、`String`、`List` をまとめて確認できます。 ```{literalinclude} ../../../src/part2/ch05/language_basics_minimal.mojo :language: mojo ```
リスト-1: language_basics_minimal.mojo
### コードの読み方 - `xs`: `List[Int]` を型注釈つきで宣言し、リストリテラルで初期化する書き方です。 - `doubled`: 右辺から型が決まる暗黙宣言で、一度決まった型は変えられません。 - `print`: `String(...)` を混ぜて表示用の文字列を型をそろえて渡しています。 **`struct`** や **`trait`** の詳しい話は、後の章で扱います。 詳細: [Mojo language basics](https://docs.modular.com/mojo/manual/basics/) 出典: [Mojo Manual — basics](https://docs.modular.com/mojo/manual/basics/) > **補足:** 全体像をつかんだあとで、公式の Get started を一度通すと理解しやすいです。 ## Functions この章での要点は、**Mojo の関数は Python に似て見えても、型とシグネチャをかなり大事にする**ことです。 ### 基本 - 関数は **`def`** で定義する - `()` は実行時に渡す引数 - `[]` はコンパイル時に決まる parameter - 戻り値は `->` で書く - 同じ名前でも、引数型が違えば別の関数として定義できる ### まず覚えたいこと #### `def` を使う 現在の Mojo では、関数定義は **`def`** が基本です。 `fn` は非推奨になっています。(以前は fn で定義していました) #### `()` と `[]` は役割が違う - `()` は実行時の値を渡す - `[]` はコンパイル時に決まる値を渡す たとえば `repeat[count]` のような形では、`count` は実行中に変わる値ではありません。 **コンパイル時に決まる値**として扱われます。 つまり、コンパイラはその値に合わせて特化したコードを作れます。 #### オーバーロードがある 同じ関数名でも、**引数の型が違えば別の関数**として定義できます。 これがオーバーロードです。 #### デフォルト引数も使える 引数を省略したときだけ、既定値が使われます。 この感覚は Python にかなり近いです。 #### `raises` が必要なことがある エラーを投げる関数では、**この関数はエラーを外に出す可能性がある**とシグネチャに書きます。 それが `raises` です。 たとえば次のような形です。 - `def pick_nonzero(...) raises -> Int:` ここで大事なのは、**エラー処理も関数の型情報の一部として見る**ことです。 この点は Python より厳密です。 ### 例 ```{literalinclude} ../../../src/part2/ch05/functions_overload_params.mojo :language: mojo ```リスト-3: functions_overload_params.mojo
この例では、上から順に次を確認できます。 - オーバーロード - compile-time parameter - デフォルト引数 - `raise` と `try/except` `pick_nonzero` は、条件によってエラーを投げる関数です。 そのため、呼び出し側では `try/except` で受ける流れになります。 詳細: [Functions](https://docs.modular.com/mojo/manual/functions/) 出典: [Mojo Manual — functions](https://docs.modular.com/mojo/manual/functions/) > **補足:** `out` 引数や、オーバーロード解決の細かい規則は、必要になった時点で公式を読むので十分です。 ## Variables この章で特に大事なのは、**Mojo では変数の型とスコープをかなりはっきり意識する**ことです。 ### 基本 - 変数は **`var`** で宣言できる - 右辺から型を決める **暗黙宣言** もある - ただし型は途中で変えられない - スコープの違いを理解することが大切 ### `var` と暗黙宣言の違い #### `var` はブロックスコープ `var` で作った変数は、**そのブロックの中だけ**で有効です。 たとえば `if` の中で作った変数は、外では使えません。 ```{literalinclude} ../../../src/part2/ch05/variables_block_var.mojo :language: mojo ```リスト-4: variables_block_var.mojo
#### 暗黙宣言は関数スコープ 一方で、暗黙宣言で導入した名前は、**関数全体で見える**形になります。 Python に近く感じるのはこの部分です。 ```{literalinclude} ../../../src/part2/ch05/variables_implicit_scope.mojo :language: mojo ```リスト-5: variables_implicit_scope.mojo
`if` の内側で `y` に再代入しても、その `y` は関数の後ろでも見えます。 **`var` か暗黙宣言かでスコープの規則が変わる**と押さえておくとよいです。 ### 所有権の移動 Mojo では、値を渡すときに **所有権** を意識する場面があります。 `^` は、**この値を相手に渡し切る**ことを表す記号です。 たとえば `msg^` を渡すと、そのあと元の `msg` はそのまま読めなくなります。 これは、値が相手側へ移ったと捉えるとよいでしょう。 受け取る側は、現在の書き方では次のように書きます。 - `def take(var s: String):` ただし古い版では書き方が違うことがあります。 0.24 系では、`owned` を使う形が見られます。 ```{literalinclude} ../../../src/part2/ch05/variables_ownership_transfer.mojo :language: mojo ```リスト-6: variables_ownership_transfer.mojo
`ref` やコピー規則の細かい話は、{numref}`値・所有権・ライフサイクル`({ref}`値・所有権・ライフサイクル`)で詳しく見れば十分です。 詳細: [Variables](https://docs.modular.com/mojo/manual/variables/) 出典: [Mojo Manual — variables](https://docs.modular.com/mojo/manual/variables/) > **補足:** Python に慣れていると、`var` のブロックスコープは引っかかりやすいです。ここは早めに意識しておくと、後で読みやすくなります。 ## この章を一文で言うと **Mojo の基本は Python に似て見えるが、型・スコープ・所有権をよりはっきり意識して書く言語だ、ということです。** ## まとめ - Mojo は Python に似た見た目を持つが、静的型の言語である - 関数では、引数や戻り値、`raises` などのシグネチャが大事になる - `()` と `[]` では役割が違う - 変数では、`var` と暗黙宣言でスコープが異なる - `^` が出てきたら、所有権の移動を意識する 次の章でも、同じように **「Python に似ている部分」と「Mojo 独自の考え方」** を切り分けながら読むと理解しやすいです。