可变参数列表
vararg
关键字生成一个具有灵活大小的参数列表。
在 列表 中,我们介绍了 listOf()
,它接受任意数量的参数并生成一个 List
:
// Varargs/ListOf.kt
import atomictest.eq
fun main() {
listOf(1) eq "[1]"
listOf("a", "b") eq "[a, b]"
}
使用 vararg
关键字,您可以定义一个函数,该函数接受任意数量的参数,就像 listOf()
一样。vararg
是 variable argument list(可变参数列表)的缩写:
// Varargs/VariableArgList.kt
package varargs
fun v(s: String, vararg d: Double) {}
fun main() {
v("abc", 1.0, 2.0)
v("def", 1.0, 2.0, 3.0, 4.0)
v("ghi", 1.0, 2.0, 3.0, 4.0, 5.0, 6.0)
}
函数定义可以只指定一个参数为 vararg
。虽然在参数列表中的任何项目都可以指定为 vararg
,但通常最简单的做法是对最后一个参数进行这样的操作。
vararg
允许您传递任意数量(包括零个)的参数。所有参数都必须是指定类型的。使用参数名称访问 vararg
参数,参数名称将成为一个 Array
:
// Varargs/VarargSum.kt
package varargs
import atomictest.eq
fun sum(vararg numbers: Int): Int {
var total = 0
for (n in numbers) {
total += n
}
return total
}
fun main() {
sum(13, 27, 44) eq 84
sum(1, 3, 5, 7, 9, 11) eq 36
sum() eq 0
}
尽管 Array
和 List
看起来相似,但它们的实现方式不同 —— List
是一个常规库类,而 Array
具有特殊的低级支持。Array
来自 Kotlin 与其他语言(尤其是 Java)兼容的要求。
在日常编程中,当您需要一个简单的序列时,请使用 List
。仅在第三方 API 需要一个 Array
或者当您处理 vararg
时才使用 Array
。
在大多数情况下,您可以忽略 vararg
生成 Array
的事实,并将其视为 List
:
// Varargs/VarargLikeList.kt
package varargs
import atomictest.eq
fun evaluate(vararg ints: Int) =
"Size: ${ints.size}\n" +
"Sum: ${ints.sum()}\n" +
"Average: ${ints.average()}"
fun main() {
evaluate(10, -3, 8, 1, 9) eq """
Size: 5
Sum: 25
Average: 5.0
"""
}
您可以在接受 vararg
的地方传递元素的 Array
。要创建 Array
,请使用与使用 listOf()
相同的方式使用 arrayOf()
。注意,Array
总是可变的。要将 Array
转换为参数序列(不仅仅是类型为 Array
的单个元素),请使用 spread operator(扩展操作符),*
:
// Varargs/SpreadOperator.kt
import varargs.sum
import atomictest.eq
fun main() {
val array = intArrayOf(4, 5)
sum(1, 2, 3, *array, 6) eq 21 // [1]
// 不编译:
// sum(1, 2, 3, array, 6)
val list = listOf(9, 10, 11)
sum(*list.toIntArray()) eq 30 // [2]
}
如果您传递一个原始类型(如 Int
、Double
或 Boolean
)的 Array
,则 Array
创建函数必须具有特定的类型。如果在 [1]
行使用 arrayOf(4, 5)
而不是 intArrayOf(4, 5)
,将会产生一个错误,提示 inferred type is Array<Int>
but IntArray was expected。
扩展操作符仅适用于数组。如果您有一个要作为参数序列传递的 List
,请首先将其转换为 Array
,然后应用扩展操作符,如 [2]。由于结果是原始类型的 Array
,我们必须再次使用特定的转换函数 toIntArray()
。
当您必须将 vararg
参数传递给另一个函数,而该函数也期望 vararg
参数时,扩展操作符尤其有用:
// Varargs/TwoFunctionsWithVarargs.kt
package varargs
import atomictest.eq
fun first(vararg numbers: Int): String {
var result = ""
for (i in numbers) {
result += "[$i]"
}
return result
}
fun second(vararg numbers: Int) =
first(*numbers)
fun main() {
second(7, 9, 32) eq "[7][9][32]"
}
命令行参数
在命令行上调用程序时,您可以向其传递可变数量的参数。要捕获命令行参数,必须为 main()
提供一个特定的参数:
// Varargs/MainArgs.kt
fun main(args: Array<String>) {
for (a in args) {
println(a)
}
}
参数传统上称为 args
(尽管您可以称其为任何名称),而 args
的类型只能是 Array<String>
(String
的数组)。
如果您使用 IntelliJ IDEA,您可以通过编辑相应的“运行配置”来传递程序参数,就像本课程的最后一个练习中所示。
您还可以使用 kotlinc
编译器来生成命令行程序。如果您的计算机上没有安装 kotlinc
,请按照 Kotlin 官方网站 上的说明操作。一旦您输入并保存了 MainArgs.kt
的代码,可以在命令提示符中键入以下内容:
kotlinc MainArgs.kt
在程序调用后,您可以提供命令行参数,如下所示:
kotlin MainArgsKt hamster 42 3.14159
您将看到以下输出:
hamster
42
3.14159
如果您希望将 String
参数转换为特定类型,Kotlin 提供了转换函数,例如用于转换为 Int
的 toInt()
,以及用于转换为 Float
的 toFloat()
。使用这些函数时,假定命令行参数按照特定顺序出现。在这里,程序期望一个 String
,后跟可转换为 Int
的内容,后跟可转换为 Float
的内容:
// Varargs/MainArgConversion.kt
fun main(args: Array<String>) {
if (args.size < 3) return
val first = args[0]
val second = args[1].toInt()
val third = args[2].toFloat()
println("$first $second $third")
}
main()
中的第一行在没有足够的参数时退出程序。如果您未提供可转换为 Int
和 Float
的内容作为第二个和第三个命令行参数,您将看到运行时错误(可以尝试以查看错误)。
使用与之前相同的命令行参数编译并运行 MainArgConversion.kt
,您将看到:
hamster 42 3.14159
练习和解答可以在 www.AtomicKotlin.com 找到。