轨道
/
Odin
Odin
/
练习
/
Two Fer
Two Fer

Two Fer

简单

简介

在某些英语口音里,如果把“two for”说得快一些,听起来就像“two fer”。Two-for-one 是一种说法,意思是买一个还能免费再得一个。所以“two-fer”这个说法往往暗示着买一送一的优惠。

想象有一家面包店,在节日期间推出了这样的优惠:花一份钱就能买到两块饼干(“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过程为例:我们希望可以指定语言、名字是否转为大写,以及问候语末尾是否加感叹号。经过分析,我们发现最大的用户群体指定英语为语言、不把名字转成大写,也不希望在末尾加感叹号;第二大的用户群体则希望在问候语末尾加感叹号。

我们可以写一个包含所有实参的单一过程:

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,全部免费。