【问题标题】:Strange behavior when passing Array<String> as varargs with spread operator使用扩展运算符将 Array<String> 作为可变参数传递时的奇怪行为
【发布时间】:2018-08-21 06:38:19
【问题描述】:

我刚刚开始使用 Kotlin,现在必须弄清楚需要 varargs 类型为 String 的函数。有问题的代码如下:

val optionStrArr = arrayOfNulls<String>(options.size)
for (i in options.indices) {
    optionStrArr[i] = options[i].value
}
App.instance?.analyticPollReceive(pollID!!, title!!, question!!, *optionStrArr)

...

fun analyticPollReceive(id: String, title: String, question: String, vararg options: String) {
    // function body
}

这只是 Android Studio 的 Java-Kotlin 转换器从 Java 转换而来的部分代码。

错误在函数调用中,如果我删除扩展运算符,编译器会说:

Type mismatch. Required: String; Found: Array&lt;String?&gt;

但是,当我把扩展运算符放入时,编译器会说:

Type mismatch. Required: Array&lt;out String&gt;; Found: Array&lt;String?&gt;

我应该将可变参数类型更改为vararg options: String?吗?

【问题讨论】:

  • 没有。你应该尽可能地避免空值。所以你的数组应该是字符串数组,而不是字符串?数组。
  • 视情况而定,options[i].value 可以为空吗?如果不是,那么optionStrArr 应该是Array&lt;String&gt; 类型。否则需要将可变参数类型改为Array&lt;String?&gt;
  • 其实options[i]本身就是一个Object,我只是把String?的值改成了String。但是当我将结果数组传递给 varargs 参数时,编译器仍然认为它是Array&lt;String?&gt;。虽然也许只是我需要删除原始 Java 文件。

标签: kotlin


【解决方案1】:

这是因为在 Java 中任何 String 变量也可以为空。在 Kotlin 中,不可为空 (String) 和可空 (String?) 变量有不同的类型。

在您的情况下,这取决于 options[i].value 是什么类型。如果它永远不可能是null,那么您可以将optionStrArr 的类型更改为Array&lt;String&gt;,代码就可以正常工作了。您可以通过这种方式创建 Strings 数组:

val optionStrArr = Array<String>(options.size) { options[it].value }

如果options[i].valueString? 类型,那么您可以更改analyticPollReceive() 的可变参数类型,前提是该函数接收可空数组有意义。否则你必须重新考虑为什么你有一个可以为空的数组,你想将它传递给一个不想要空值的函数。

【讨论】:

  • 好吧,既然我已经将options[i].value的String类型改为String而不是String?,我想我会选择第一个选项[val optionStrArr = Array&lt;String&gt;(options!!.size, {options[it].value}),如果这是正确的句法]。谢谢。顺便问一下,Kotlin 的 String 在 Java 中是指 @NonNull String 吗? String? 是指@Nullable String 吗?
  • @Gensoukyou1337 是的,它就是这样工作的。在继续将 Java 代码移植到 Kotlin 之前,您应该阅读一些有关 Kotlin 的基础知识,这样您将了解转换器将生成的所有奇怪语法,因为在 Java 中所有类型都可以为空。一旦你的大部分代码都在 Kotlin 中,并且只有在实际需要时才具有可为空的类型,你的代码就会看起来更干净。
【解决方案2】:

您看到的第二个错误是因为您使用arrayOfNulls&lt;String&gt; 初始化了数组。这将创建一个Array&lt;String?&gt;,因为它必须用空值填充。

要解决此问题,请研究创建数组的其他方法,例如 Collection#toTypedArrayArray#copyOf(取决于 options 的实际类型。
这些将生成一个与源相同类型的数组,而不是隐式使其可以为空。

【讨论】:

    【解决方案3】:

    数组的optionStrArr 类型是Array&lt;String?&gt;
    所以你需要做出这样的改变:

    fun analyticPollReceive(id: String, title: String, question: String, vararg options: String?) {
        // function body
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-03-23
      • 1970-01-01
      • 1970-01-01
      • 2017-04-14
      • 2015-08-06
      • 1970-01-01
      • 2011-03-13
      • 2017-11-18
      相关资源
      最近更新 更多