以Vararg为第一参数的Kotlin方法
注意我已经看了下面的问题/答案,没有任何运气来解决问题。 从Kotlin调用Java Varargs方法 – 这个在参数列表的末尾有可变参数,但是我的问题是在参数列表的开头处理可变参数。 Kotlin:将列表转换为Java可变参数 – 相同。 其他搜索产生相同的东西。 这些是我能找到的最接近的。
我使用单个字符分隔符来调用Kotlin String.split
方法。 这是一个vararg
参数方法,其中参数vararg
是多个参数中的第一个参数。 该方法是这样定义的:
public fun CharSequence.split(vararg delimiters: Char, ignoreCase: Boolean = false, limit: Int = 0): List<String>
当我调用下面的方法,它编译罚款:
fun String.splitRuleSymbol() : String = this.split(':') //ok
但是,当我尝试添加ignoreCase
和limit
参数,我得到一个问题:
fun String.splitRuleSymbol() : String = this.split(':', true, 2) //compiler error
我得到的错误是…
提供的参数不能调用以下函数:
公共乐趣CharSequence.split(可变分隔符:String,ignoreCase:Boolean = …,limit:Int = …):在kotlin.text中定义的列表
public fun CharSequence.split(可变分隔符:Char,ignoreCase:Boolean = …,limit:Int = …):在kotlin.text中定义的列表
对我来说,有一个vararg
参数后跟其他参数是有点奇怪,但这是在旁边。 如果我把它称为如下,它工作正常:
// both of the following compile fun String.splitRuleSymbol() : String = this.split(delimiters = ':', ignoreCase = true, limit = 2) fun String.splitRuleSymbol2() : String = this.split(';', ignoreCase = true, limit = 2)
有没有办法将vararg Char
参数传入此方法,而不必限制我的其他两个参数的参数名称ignoreCase
和limit
? 编译器能否告诉其余参数不是Char
?
我已经尝试了下面的传播运算符和其他一些方法,但其中的任何一个都不起作用:
//compiler errors on all these this.split(*':', true, 2) //using the "spread" operator this.split(*charArrayOf(':'), true, 2) this.split(*mutableListOf(':'), true, 2) this.split(*Array<Char>(1) { ':' }, true, 2)
是的,我知道其中有些看起来很荒谬。 但是,有没有办法避免冗长的选择?
PS当我正在制定我的问题时,我发现另一个表达式编译。
this.split(':', limit = 2)
这是不太冗长的,因为我不需要改变默认的ignoreCase
参数,它更接近我在找什么。
你的观察是正确的。 vararg
参数后面的参数只能通过使用命名参数传入,否则会遇到模糊问题(对于一个简单的例子,假设所有参数的类型都是Any
)。
我现在可以找到的最好的来源是这本书 。
可变参数通常是最后一个参数,但并不总是必须的。 如果在可变参数之后还有其他参数,则必须使用命名参数传递参数
编辑:@Les找到了一个很好的来源,看到他们的答案 。
可变数量的参数(vararg)可以通过使用扩展运算符以命名形式传递:
fun foo(vararg strings: String) { /* ... */ } foo(strings = *arrayOf("a", "b", "c")) foo(strings = "a") // Not required for a single value
请注意,调用Java函数时不能使用命名的参数语法,因为Java字节码并不总是保留函数参数的名称。
感谢zsmb13,我能够在Kotlin规范 (在“Functions and Lambdas”下)找到以下段落
只有一个参数可能被标记为可变参数。 如果vararg参数不是列表中的最后一个参数,则可以使用命名的参数语法传递以下参数的值,或者如果该参数具有函数类型,则可以通过将圆括号之外的lambda传递给参数。
我会冒险添加“可以通过”应改为“必须通过”,因为编译器将不允许以其他方式。
注意 lambda部分是有趣的,因为规范通常只允许在最后一个参数时将lambda移到括号之外。 规范的措辞意味着lambda可以在vararg
参数之后的任何地方,但是实验表明它不能,也就是说,它必须是最后一个参数才有资格移动到括号之外。
fun main(args: Array<String>) { test("hello", limit = 1, ic = false, delims = ';') { } //ok //test2("world", limit = 1, ic = false, delims = ';') { } //error test2("world", f = {}, limit = 1, ic = false, delims = ';') //ok test("hello world", ';', limit = 1, ic = false) {} //ok } fun test(vararg delims: Char, ic: Boolean, limit: Int, f: () -> Unit) {} fun test2(vararg delims: Char, f: () -> Unit, ic: Boolean, limit: Int) {}