以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 

但是,当我尝试添加ignoreCaselimit参数,我得到一个问题:

 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参数传入此方法,而不必限制我的其他两个参数的参数名称ignoreCaselimit 编译器能否告诉其余参数不是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) {}