从 Kotlin 中的另一个扩展方法调用扩展方法的编译错误
Compile error calling an extension method from another extension method in Kotlin
当我尝试从另一个扩展方法调用扩展方法(重载该方法)时,它无法在 IntelliJ 14.1.5 和 Kotlin 0.14.449 中编译
由于我是这门语言的新手,而且参考资料中也没有禁止这样做,我想知道:
- 是否可以从另一个扩展方法调用扩展方法?
- 我使用的语法是否正确(因此这是一个错误)?
- 如果不是,正确的语法是什么?
这是无法编译的代码:
fun String.replace (prefix: String, suffix: String, vararg parameters: Pair<String, String>) =
parameters.fold(this, { result, pair -> result.replace (prefix + pair.first + suffix, pair.second) })
fun String.replace (vararg parameters: Pair<String, String>) =
this.replace ("", "", parameters)
提前致谢!
您的问题是第一个 String.replace 正在递归调用自身,并且永远不会到达主要的 String.replace。此外,第二个中的可变参数作为 Array> 传递给第一个,因此调用第二个函数永远不会匹配第一个。
fun String.replace(vararg parameters: Pair<String, String>) =
this.replace("", "", parameters)
fun String.replace(prefix: String, suffix: String, parameters: Array<out Pair<String, String>>) =
parameters.fold(this, { result, pair -> result.replace(prefix + pair.first + suffix, pair.second) })
虽然我认为这是一个错误,但我搜索了 Kotlin 问题跟踪器并发现了这个:https://youtrack.jetbrains.com/issue/KT-2079
将 vararg
参数传递给另一个函数的正确语法是使用星号“*”:
fun String.filter (prefix: String, suffix: String, vararg parameters: Pair<String, String>) =
parameters.fold(this, { result, pair -> result.replace (prefix + pair.first + suffix, pair.second) })
fun String.filter (vararg parameters: Pair<String, String>) =
this.filter("", "", *parameters)
还有其他答案,但这里有更多关于正在发生的事情的注释,随后是类似的解决方案,它保留方法命名,避免递归,并为两个方法签名保留 varargs
:
将一个可变参数传递给另一个时,您需要使用 spread operator 因为可变参数是作为数组接收的,您希望将它们转换回参数列表,展开运算符可以就是这样。
fold()
lambda 内部的调用不小心调用了自身。由于您使用 2 个参数调用 string.replace()
,因此哪个版本获胜?版本 string.replace(String, String, vararg Pair<String,String>)
还是 string.replace(String, String, Boolean[defaulted to false])
?当仅使用 2 个参数调用时,它们看起来都一样。本地的赢了,因此你有递归。要强制调用 stdlib 替换函数,第三个参数默认为 false
因此专门传递该值以便找到正确的方法签名。
工作代码:
fun String.replace(prefix: String, suffix: String, vararg parameters: Pair<String, String>) {
parameters.fold(this) { result, pair ->
// add a last parameter to differentiate what version I want called, the one with optional
// boolean parameter last (ignoreCase: Boolean = false). Otherwise this recurses on accident.
result.replace(prefix + pair.first + suffix, pair.second, false)
}
}
fun String.replace(vararg parameters: Pair<String, String>) {
this.replace ("", "", *parameters) // add * spread operator
}
当我尝试从另一个扩展方法调用扩展方法(重载该方法)时,它无法在 IntelliJ 14.1.5 和 Kotlin 0.14.449 中编译
由于我是这门语言的新手,而且参考资料中也没有禁止这样做,我想知道:
- 是否可以从另一个扩展方法调用扩展方法?
- 我使用的语法是否正确(因此这是一个错误)?
- 如果不是,正确的语法是什么?
这是无法编译的代码:
fun String.replace (prefix: String, suffix: String, vararg parameters: Pair<String, String>) =
parameters.fold(this, { result, pair -> result.replace (prefix + pair.first + suffix, pair.second) })
fun String.replace (vararg parameters: Pair<String, String>) =
this.replace ("", "", parameters)
提前致谢!
您的问题是第一个 String.replace 正在递归调用自身,并且永远不会到达主要的 String.replace。此外,第二个中的可变参数作为 Array> 传递给第一个,因此调用第二个函数永远不会匹配第一个。
fun String.replace(vararg parameters: Pair<String, String>) =
this.replace("", "", parameters)
fun String.replace(prefix: String, suffix: String, parameters: Array<out Pair<String, String>>) =
parameters.fold(this, { result, pair -> result.replace(prefix + pair.first + suffix, pair.second) })
虽然我认为这是一个错误,但我搜索了 Kotlin 问题跟踪器并发现了这个:https://youtrack.jetbrains.com/issue/KT-2079
将 vararg
参数传递给另一个函数的正确语法是使用星号“*”:
fun String.filter (prefix: String, suffix: String, vararg parameters: Pair<String, String>) =
parameters.fold(this, { result, pair -> result.replace (prefix + pair.first + suffix, pair.second) })
fun String.filter (vararg parameters: Pair<String, String>) =
this.filter("", "", *parameters)
还有其他答案,但这里有更多关于正在发生的事情的注释,随后是类似的解决方案,它保留方法命名,避免递归,并为两个方法签名保留 varargs
:
将一个可变参数传递给另一个时,您需要使用 spread operator 因为可变参数是作为数组接收的,您希望将它们转换回参数列表,展开运算符可以就是这样。
fold()
lambda 内部的调用不小心调用了自身。由于您使用 2 个参数调用string.replace()
,因此哪个版本获胜?版本string.replace(String, String, vararg Pair<String,String>)
还是string.replace(String, String, Boolean[defaulted to false])
?当仅使用 2 个参数调用时,它们看起来都一样。本地的赢了,因此你有递归。要强制调用 stdlib 替换函数,第三个参数默认为false
因此专门传递该值以便找到正确的方法签名。
工作代码:
fun String.replace(prefix: String, suffix: String, vararg parameters: Pair<String, String>) {
parameters.fold(this) { result, pair ->
// add a last parameter to differentiate what version I want called, the one with optional
// boolean parameter last (ignoreCase: Boolean = false). Otherwise this recurses on accident.
result.replace(prefix + pair.first + suffix, pair.second, false)
}
}
fun String.replace(vararg parameters: Pair<String, String>) {
this.replace ("", "", *parameters) // add * spread operator
}