命名参数和默认参数
在函数调用过程中,您可以提供参数名称。
命名参数提高了代码的可读性。这对于参数列表很长且复杂的情况尤为重要 - 命名参数可以足够清晰,以至于读者可以在不查看文档的情况下理解函数调用。
在下面的示例中,所有的参数都是 Int
类型。命名参数可以澄清它们的含义:
// NamedAndDefaultArgs/NamedArguments.kt
package color1
import atomictest.eq
fun color(red: Int, green: Int, blue: Int) =
"($red, $green, $blue)"
fun main() {
color(1, 2, 3) eq "(1, 2, 3)" // [1]
color(
red = 76, // [2]
green = 89,
blue = 0
) eq "(76, 89, 0)"
color(52, 34, blue = 0) eq // [3]
"(52, 34, 0)"
}
- [1] 这并没有提供太多信息。您需要查看文档才能知道这些参数的含义。
- [2] 每个参数的含义都很清晰。
- [3] 您不需要为所有的参数命名。
命名参数使您可以更改颜色的顺序。在这里,我们首先指定了 blue
:
// NamedAndDefaultArgs/ArgumentOrder.kt
import color1.color
import atomictest.eq
fun main() {
color(blue = 0, red = 99, green = 52) eq
"(99, 52, 0)"
color(red = 255, 255, 0) eq
"(255, 255, 0)"
}
您可以混合使用命名参数和常规(位置)参数。如果更改参数的顺序,您应该在整个调用过程中使用命名参数 - 不仅仅是为了可读性,还因为编译器通常需要告诉它们参数的位置。
当与默认参数结合使用时,命名参数尤其有用。默认参数是函数定义中指定的参数的默认值:
// NamedAndDefaultArgs/Color2.kt
package color2
import atomictest.eq
fun color(
red: Int = 0,
green: Int = 0,
blue: Int = 0,
) = "($red, $green, $blue)"
fun main() {
color(139) eq "(139, 0, 0)"
color(blue = 139) eq "(0, 0, 139)"
color(255, 165) eq "(255, 165, 0)"
color(red = 128, blue = 128) eq
"(128, 0, 128)"
}
如果不提供任何参数,那么未提供的参数将采用其默认值,因此您只需要提供与默认值不同的参数。如果参数列表很长,这简化了生成的代码,使其更易于编写和阅读。
该示例还在 color()
的定义中使用了 尾随逗号。尾随逗号是最后一个参数(blue
)之后的额外逗号。当参数或值写在多行上时,这非常有用。有了尾随逗号,您可以添加新项目并更改它们的顺序,而无需添加或删除逗号。
命名参数和默认参数(以及尾随逗号)在构造函数中同样适用:
// NamedAndDefaultArgs/Color3.kt
package color3
import atomictest.eq
class Color(
val red: Int = 0,
val green: Int = 0,
val blue: Int = 0,
) {
override fun toString() =
"($red, $green, $blue)"
}
fun main() {
Color(red = 77).toString() eq "(77, 0, 0)"
}
joinToString()
是一个使用默认参数的标准库函数。它将可迭代对象(列表、集合或范围)的内容合并为一个 String
。您可以指定分隔符、前缀元素和后缀元素:
// NamedAndDefaultArgs/CreateString.kt
import atomictest.eq
fun main() {
val list = listOf(1, 2, 3,)
list.toString() eq "[1, 2, 3]"
list.joinToString() eq "1, 2, 3"
list.joinToString(prefix = "(",
postfix = ")") eq "(1, 2, 3)"
list.joinToString(separator = ":") eq
"1:2:3"
}
默认情况下,List
的默认 toString()
方法会返回方括号中的内容,这可能不是您想要的。joinToString()
的参数的默认值是用逗号作为 separator
,用空字符串作为 prefix
和 postfix
。在上面的示例中,我们使用命名参数和默认参数来指定我们想要更改的参数。
list
的初始化器包含一个尾随逗号。通常,只有在每个元素占据一行的情况下才会使用尾随逗号。
如果将对象用作默认参数,则会为每次调用创建该对象的新实例:
// NamedAndDefaultArgs/Evaluation.kt
package namedanddefault
class DefaultArg
fun h(d: DefaultArg = DefaultArg()) =
println(d)
fun main() {
h()
h()
}
/* Sample output:
DefaultArg@28d93b30
DefaultArg@1b6d3586
*/
h()
的两次调用的 DefaultArg
对象的地址不同,表明存在两个不同的对象。
当提高可读性时,请指定参数名称。比较以下两个对 joinToString()
的调用:
// NamedAndDefaultArgs/CreateString2.kt
import atomictest.eq
fun main() {
val list = listOf(1, 2, 3)
list.joinToString(". ", "", "!") eq
"1. 2. 3!"
list.joinToString(separator = ". ",
postfix = "!") eq "1. 2. 3!"
}
如果没有记住参数顺序的话,很难猜测 ". "
或 ""
是分隔符。
作为默认参数的另一个示例,trimMargin()
是一个标准库函数,用于格式化多行的 String
。它使用边距前缀 String
来确定每行的开头。trimMargin()
会从源 String
的每一行中去除前导空白字符和边距前缀。如果第一行和最后一行是空行,则它会删除它们:
// NamedAndDefaultArgs/TrimMargin.kt
import atomictest.eq
fun main() {
val poem = """
|->Last night I saw upon the stair
|->A little man who wasn't there
|->He wasn't there again today
|->Oh, how I wish he'd go away."""
poem.trimMargin() eq
"""->Last night I saw upon the stair
->A little man who wasn't there
->He wasn't there again today
->Oh, how I wish he'd go away."""
poem.trimMargin(marginPrefix = "|->") eq
"""Last night I saw upon the stair
A little man who wasn't there
He wasn't there again today
Oh, how I wish he'd go away."""
}
|
(“pipe”)是边距前缀的默认参数,您可以将其替换为所选的 String
。
练习和解答可以在 www.AtomicKotlin.com 上找到。