プロシージャ
何かの仕事を行うプログラムの一部分をまとめて、繰り返し利用できるようにしたり、コードの構造を整理したりするために、プロシージャを用います。 プロシージャとは手続きという意味です。 別の言語では、サブルーチン、関数、メソッドなど、異なる呼び名がつけられています。 Pascal言語などのように、値を返すかどうかによって関数とプロシージャに呼び分けれている場合もありますが、Odinではどちらもプロシージャと呼びます。
基本
すでにひとつプロシージャが登場しています。 mainプロシージャです。
main :: proc() {
// ...
}
mainプロシージャはプログラムの開始地点となる特別なプロシージャです。
このmainプロシージャは引数を取らず戻り値がありません。 自分のプロシージャを書くときは、自由に名前をつけてパラメーターと戻り値を設定することができます。
次の例は、パラメーターが一つのプロシージャです。
greet :: proc(name: string) {
fmt.println("Hello, ", name, "!")
}
次の例は、パラメーターが2つで戻り値があるプロシージャです。
add :: proc(a, b: int) -> int {
return a + b
}
連続するパラメーターの型が同一ならば、まとめて指定できる点に注目してください。
上の例では、a、bと続いて両方ともintなので、bの後ろにintとだけ指定するだけでOKです。
(a: int, b: int)
とすることもできますが、通常はまとめてしまった方が良いでしょう。
名前付き戻り値
戻り値に名前をつけることができます。
add :: proc(a, b: int) -> (result: int) {
result = a + b
}
複数の値を返す
プロシージャは複数の値を返すことができます。
translated :: proc(x, y: int, dx, dy: int) -> (int, int) {
return x + dx, y + dy
}
main :: proc() {
x, y := translated(100, 200, 10, 20)
assert(x == 110 && y == 220)
}
名前付き引数
引数を名前で渡すことができます。
greet :: proc(message, name: string) {
fmt.println(message, name)
}
main :: proc() {
greet("Hello", name = "Monkey")
}
名前引数はすべての位置引数より後ろで指定しなければなりません。 次の呼び出しはコンパイルされません。
greet(name = "Monkey", "Hello") // コンパイルエラー!
パラメーターのデフォルト値
パラメーターのデフォルト値を設定することができます。
Rect :: struct {
x, y: int,
width, height: int,
}
make_square :: proc(x, y: int, size := 100) -> Rect {
// sizeのデフォルト値を100とします。
// 100という数値に特に意味はありません。
return Rect{x = x, y = y, width = size, height = size}
}
main :: proc() {
r := make_square(10, 20)
assert(r.x == 10 && r.y == 20 && r.width == 100 && r.height == 100)
}
オーバーロード
プロシージャのオーバーロード、すなわちパラメーターが異なる同じ名前のプロシージャを複数定義することが可能です。 ただし、C++などのように、単に同じ名前のプロシージャを定義すれば良いだけではなく、明示的にオーバーロードすることを記述しなければなりません。 1ステップ追加の作業が必要になります。
Vector2i :: struct {
x, y: int
}
Vector3i :: struct {
x, y, z: int
}
dot2 :: proc(a, b: Vector2i) -> int {
return a.x * b.x + a.y * b.y
}
dot3 :: proc(a, b: Vector3i) -> int {
return a.x * b.x + a.y * b.y + a.z * b.z
}
// 明示的なプロシージャのオーバーロード
dot :: proc{dot2, dot3}
main :: proc() {
a := Vector2i{x = 1, y = 1}
b := Vector2i{x = 10, y = 10}
assert(dot(a, b) == 20)
c := Vector3i{x = 1, y = 1, z = 1}
d := Vector3i{x = 10, y = 20, z = 30}
assert(dot(c, d) == 60)
}