同时为 Kotlin 成员和扩展
Kotlin member and extension at the same time
为了更多地了解 Kotlin 并尝试使用它,我正在开发一个示例 Android 应用程序,我可以在其中尝试不同的东西。
然而,即使在这个主题上搜索了一段时间后,我也未能找到以下问题的正确答案:
让我们在视图上声明一个(虚拟的)扩展函数 class :
fun View.isViewVisibility(v: Int): Boolean = visibility == v
现在我如何从其他地方引用这个函数以便稍后调用它的 invoke()?
val f: (Int) -> Boolean = View::isViewVisibility
目前给我:
Error:(57, 35) Type mismatch: inferred type is KFunction2 but (Int) -> Boolean was
expectedError:(57, 41) 'isViewVisibility' is a member and an extension
at the same time. References to such elements are not allowed
有什么解决办法吗?
谢谢!
作为解决方法,您可以创建一个单独的 普通 函数并从内联扩展方法中调用它:
inline fun View.isVisibility(v: Int): Boolean = isViewVisibility(this, v)
fun isViewVisibility(v: View, k: Int): Boolean = (v.visibility == k)
您不能直接调用扩展方法,因为您没有可用的隐式 this
对象。
扩展是静态解析的,其中第一个参数接受接收者类型的实例。 isViewVisibility
实际上接受两个参数,View
和Int
。所以,它的正确类型应该是 (View, Int) -> Boolean
,像这样:
val f: (View, Int) -> Boolean = View::isViewVisibility
更合适的是扩展函数类型 View.(Int) -> Boolean
:
val f: View.(Int) -> Boolean = View::isViewVisibility
但实际上扩展类型大部分是可互换的(赋值兼容)与普通函数类型以接收者为第一个参数:
View.(Int) -> Boolean
↔ (View, Int) -> Boolean
使用带有两个参数的类型(第一个用于隐式接收者,正如@Bakawaii 已经提到的)或扩展类型都应该在没有任何警告的情况下工作。
我们以这个函数为例:
fun String.foo(f: Int) = true
您可以将其分配给具有两个参数函数类型的 属性,如下所示:
val prop: (String, Int) -> Boolean = String::foo
fun bar() {
prop("bar", 123)
}
或者,您可以使用扩展函数类型,然后您可以使用以下两种语法之一调用它:
val prop2: String.(Int) -> Boolean = String::foo
fun bar2() {
prop2("bar2", 123)
"bar2".prop2(123)
}
同样,以上内容应该 运行 没有任何错误或警告。
当我在另一个 class 中声明扩展函数并尝试将该扩展函数作为参数传递时,我遇到了同样的问题。
我通过传递与扩展具有相同签名的函数找到了一个变通方法,该函数又委托给实际的扩展函数。
MyUtils.kt:
object MyUtils {
//extension to MyClass, signature: (Int)->Unit
fun MyClass.extend(val:Int) {
}
}
AnyClass.kt:
//importing extension from MyUtils
import MyUtils.extend
// Assume you want to pass your extension function as parameter
fun someMethodWithLambda(func: (Int)->Unit) {}
class AnyClass {
fun someMethod() {
//this line throws error
someMethodWithLambda(MyClass::extend) //member and extension at the same time
//workaround
val myClassInstance = MyClass()
// you pass a proxy lambda which will call your extension function
someMethodWithLambda { someIntegerValue ->
myClassInstance.extend(someIntegerValue)
}
}
}
错误消息指出:
'isViewVisibility' is a member and an extension at the same time. References to such elements are not allowed
它是说该方法既是一个扩展函数,这正是您想要的,也是一个成员。您没有显示定义的整个上下文,但它可能看起来像这样:
// MyClass.kt
class MyClass {
fun String.coolStringExtension() = "Cool $this"
val bar = String::coolStringExtension
}
fun main() {
print(MyClass().bar("foo"))
}
如您所见,coolStringExtension
被定义为 MyClass
的成员。这就是错误所指的内容。 Kotlin 不允许您引用也是成员的扩展函数,因此会出现错误。
您可以通过在顶层而不是成员定义扩展函数来解决这个问题。例如:
// MyClass.kt
class MyClass {
val bar = String::coolStringExtension
}
fun String.coolStringExtension() = "Cool $this"
fun main() {
print(MyClass().bar("foo"))
}
为了更多地了解 Kotlin 并尝试使用它,我正在开发一个示例 Android 应用程序,我可以在其中尝试不同的东西。
然而,即使在这个主题上搜索了一段时间后,我也未能找到以下问题的正确答案:
让我们在视图上声明一个(虚拟的)扩展函数 class :
fun View.isViewVisibility(v: Int): Boolean = visibility == v
现在我如何从其他地方引用这个函数以便稍后调用它的 invoke()?
val f: (Int) -> Boolean = View::isViewVisibility
目前给我:
Error:(57, 35) Type mismatch: inferred type is KFunction2 but (Int) -> Boolean was expectedError:(57, 41) 'isViewVisibility' is a member and an extension at the same time. References to such elements are not allowed
有什么解决办法吗? 谢谢!
作为解决方法,您可以创建一个单独的 普通 函数并从内联扩展方法中调用它:
inline fun View.isVisibility(v: Int): Boolean = isViewVisibility(this, v)
fun isViewVisibility(v: View, k: Int): Boolean = (v.visibility == k)
您不能直接调用扩展方法,因为您没有可用的隐式 this
对象。
扩展是静态解析的,其中第一个参数接受接收者类型的实例。 isViewVisibility
实际上接受两个参数,View
和Int
。所以,它的正确类型应该是 (View, Int) -> Boolean
,像这样:
val f: (View, Int) -> Boolean = View::isViewVisibility
更合适的是扩展函数类型 View.(Int) -> Boolean
:
val f: View.(Int) -> Boolean = View::isViewVisibility
但实际上扩展类型大部分是可互换的(赋值兼容)与普通函数类型以接收者为第一个参数:
View.(Int) -> Boolean
↔ (View, Int) -> Boolean
使用带有两个参数的类型(第一个用于隐式接收者,正如@Bakawaii 已经提到的)或扩展类型都应该在没有任何警告的情况下工作。
我们以这个函数为例:
fun String.foo(f: Int) = true
您可以将其分配给具有两个参数函数类型的 属性,如下所示:
val prop: (String, Int) -> Boolean = String::foo
fun bar() {
prop("bar", 123)
}
或者,您可以使用扩展函数类型,然后您可以使用以下两种语法之一调用它:
val prop2: String.(Int) -> Boolean = String::foo
fun bar2() {
prop2("bar2", 123)
"bar2".prop2(123)
}
同样,以上内容应该 运行 没有任何错误或警告。
当我在另一个 class 中声明扩展函数并尝试将该扩展函数作为参数传递时,我遇到了同样的问题。
我通过传递与扩展具有相同签名的函数找到了一个变通方法,该函数又委托给实际的扩展函数。
MyUtils.kt:
object MyUtils {
//extension to MyClass, signature: (Int)->Unit
fun MyClass.extend(val:Int) {
}
}
AnyClass.kt:
//importing extension from MyUtils
import MyUtils.extend
// Assume you want to pass your extension function as parameter
fun someMethodWithLambda(func: (Int)->Unit) {}
class AnyClass {
fun someMethod() {
//this line throws error
someMethodWithLambda(MyClass::extend) //member and extension at the same time
//workaround
val myClassInstance = MyClass()
// you pass a proxy lambda which will call your extension function
someMethodWithLambda { someIntegerValue ->
myClassInstance.extend(someIntegerValue)
}
}
}
错误消息指出:
'isViewVisibility' is a member and an extension at the same time. References to such elements are not allowed
它是说该方法既是一个扩展函数,这正是您想要的,也是一个成员。您没有显示定义的整个上下文,但它可能看起来像这样:
// MyClass.kt
class MyClass {
fun String.coolStringExtension() = "Cool $this"
val bar = String::coolStringExtension
}
fun main() {
print(MyClass().bar("foo"))
}
如您所见,coolStringExtension
被定义为 MyClass
的成员。这就是错误所指的内容。 Kotlin 不允许您引用也是成员的扩展函数,因此会出现错误。
您可以通过在顶层而不是成员定义扩展函数来解决这个问题。例如:
// MyClass.kt
class MyClass {
val bar = String::coolStringExtension
}
fun String.coolStringExtension() = "Cool $this"
fun main() {
print(MyClass().bar("foo"))
}