Two Fer

Two Fer

初級

はじめに

英語のいくつかの訛りでは、"two for"を素早く言うと"two fer"のように聞こえます。Two-for-oneとは、1つ買うともう1つ無料で手に入るという意味の言い方です。そのため、"two-fer"という言葉は、しばしば2つで1つのお得な提供を意味します。

クッキーを2枚、1枚分の値段で買える休日のキャンペーンをやっているパン屋を想像してみましょう("two-fer one!")。キャンペーンを利用して、(とても太っ腹にも)余分なクッキーを列に並んでいる別の人にあげることにします。

説明

余ったクッキーをあげるときに、何と言うかを決めるのが今回の課題です。

相手の名前がわかっているとき(たとえば、名前がDo-yunの場合)は、次のように言います:

One for Do-yun, one for me.

相手の名前がわからないときは、代わりに you と言います。

One for you, one for me.

例をいくつか挙げます:

名前 セリフ
Alice One for Alice, one for me.
Bohdan One for Bohdan, one for me.
One for you, one for me.
Zaphod One for Zaphod, one for me.

Odin固有の説明

Odinはデフォルト引数をサポートしています。 デフォルト引数は便利な機能で、関連しているけれど少しずつ異なるAPIが必要な場面で、さまざまな引数の組み合わせでプロシージャを呼び出せるようにします。

デフォルト引数がなければ、APIに必要なプロシージャの数が爆発的に増えてしまうことがあります。 Javaのようにデフォルト引数をサポートしていない言語では、同じことを実現するためにメソッドのオーバーロードに頼るか(その分、コードは増えます)、そうでなければ非常に多くの引数を持つプロシージャを用意しなければなりません。

ここで、greetingプロシージャを例に考えてみましょう。このプロシージャでは、言語、名前を大文字にするかどうか、そして挨拶の最後に感嘆符を付けるかどうかを指定できるようにしたいとします。 少し分析してみたところ、最も多いユーザーは言語に英語を指定し、名前を大文字にせず、最後に感嘆符を付けません。2番目に多いユーザーは、挨拶の最後に感嘆符を付けます。

すべての引数を持つプロシージャを1つ用意することもできます。

greeting :: proc(name: string, language: Language, do_uppercase: bool, add_exclamation: bool) {
	...
}

しかし、これではすべてのユーザーがすべての引数のドキュメントを読み、常にすべての引数を指定しなければならなくなります。

デフォルト引数がなければ、異なる引数の組み合わせを持つ複数のプロシージャを定義する方法もあります。

greeting_common :: proc(name: string) {...}

greeting_with_exclamation :: proc(name: string) {...}

greeting_general :: proc(name: string, language: Language, do_uppercase: bool, add_exclamation: bool) {...}

// Odin supports overloading but it has to be explicitly defined
greeting :: proc {
	greeting_common,
	greeting_with_exclamation,
	greeting_general,
}

Odinのようにデフォルト引数をサポートしている言語なら、あまり使われない引数に適切なデフォルト値を用意するだけで済みます。 呼び出し側はデフォルト引数を省略してそのデフォルト値を使うことも、上書きすることもできます。

greeting :: proc(name: string, language: Language = Language.English, do_uppercase : bool = false, add_exclamation: bool = false) {...}

// Note: because Odin supports type inference, we can simplify the interface.
greeting :: proc(name: string, language:= Language.English, do_uppercase := false, add_exclamation:= false) {...}

すべての引数を省略してプロシージャを呼び出すこともできます。

greeting("John Doe")

呼び出し側にとって重要な引数は上書きできます。

greeting("John Doe", Language.Spanish)

必要な引数が上の例のように位置の順序どおりであれば、引数に名前を付ける必要はありません。ただし、いくつかの引数を飛ばしたいときは、飛ばした最初の引数より後ろの引数には名前を付ける必要があります。

greeting("John Doe", add_exclamation=true)

メモリ管理

この演習では、戻り値の文字列を確保することを意図したプロシージャを実装します。その文字列の解放は、プロシージャの呼び出し側の責任です。

// The procedure will be called like that:
str := two_fer("Alice")
// ...
// and eventually the caller will delete the string
delete(str)

Odinの公式ドキュメントにあるデフォルト引数やOdinの名前付き引数も、あわせて参考になるかもしれません。


出典

この演習の出典を見てみましょう。

GitHubで編集する リンクは新しいウィンドウまたはタブで開きます
Odin Exercism

Two Ferを始める準備はできましたか?

Exercismに登録すれば、73個の演習、そして本物の人間によるメンタリングとともに、Odinを学んでマスターできます。すべて無料です。