使用Vararg作为第一参数的Kotlin方法

时间:2017-09-27 19:55:28

标签: kotlin parameter-passing

注意我已经查看了以下问题/答案,以便在没有任何运气的情况下解决问题。 Call Java Varargs Method from Kotlin - 这个参数列表末尾有一个varargs参数,但我的问题是在参数列表的开头处理varargs。 Kotlin: Convert List to Java Varargs - 同样的。其他搜索产生相同的结果。这些是我能找到的最接近的。

我使用单个字符分隔符调用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

我得到的错误是......

  

使用提供的参数不能调用以下任何函数:

     

public fun CharSequence.split(vararg delimiters:String,ignoreCase:Boolean = ...,limit:Int = ...):kotlin.text中定义的列表

     

public fun CharSequence.split(vararg delimiters: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

我已经尝试了the spread operator以及其他一些方法,其中没有一个可行:

    //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参数,所以它更接近我正在寻找的内容。

3 个答案:

答案 0 :(得分:3)

您的观察结果是正确的。只能通过使用命名参数传递vararg参数之后的参数,否则会遇到模糊问题(对于一个简单的例子,假设所有参数都是Any类型)

我现在能找到的最佳来源是book

  

vararg参数通常是最后一个参数,但并不总是如此。如果在vararg之后还有其他参数,则必须使用命名参数传递参数

编辑:@Les找到了一个很好的来源,请参阅their answer

答案 1 :(得分:3)

感谢zsmb13,我能够在Kotlin Specification中找到以下段落(&#34;函数和Lambda&#34;

  

只有一个参数可以标记为vararg。如果是vararg参数   不是列表中的最后一个,以下参数的值可以   使用命名参数语法传递,或者,如果参数具有   函数类型,通过在括号外传递lambda。

我冒昧地补充说,#34;可以通过&#34;应改为&#34;必须通过&#34;因为编译器不会允许,否则。

注意 lambda部分很有意思,因为规范通常只允许lambda在 last 参数时移动到括号外。规范的措辞暗示lambda可以在vararg参数之后的任何地方,但是实验表明它是canont,即它必须是最后一个参数才能有资格移出括号。

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) {} 

答案 2 :(得分:2)

可以使用扩展运算符在命名表单中传递可变数量的参数(vararg):

fun foo(vararg strings: String) { /* ... */ }

foo(strings = *arrayOf("a", "b", "c"))
foo(strings = "a") // Not required for a single value

请注意,调用Java函数时不能使用命名参数语法,因为Java字节码并不总是保留函数参数的名称。