为了更多地了解Kotlin并使用它,我正在开发一个示例Android应用程序,我可以尝试不同的东西。
然而,即使在搜索了一段时间后,我也未能找到适合以下问题的答案:
让我们在View类上声明一个(虚拟)扩展函数:
fun View.isViewVisibility(v: Int): Boolean = visibility == v
现在我怎样才能从其他地方引用这个函数,以后再调用它上面的invoke()?
val f: (Int) -> Boolean = View::isViewVisibility
目前给我:
错误:(57,55)类型不匹配:推断类型是KFunction2但是(Int) - >布尔是 expectedError:(57,41)'isViewVisibility'是成员和扩展名 同时。不允许引用此类元素
有没有解决方法? 谢谢!
答案 0 :(得分:3)
扩展以静态方式解析,其中第一个参数接受接收方类型的实例。 isViewVisibility
实际上接受两个参数View
和Int
。所以,正确的类型应该是(View, Int) -> Boolean
,如下所示:
val f: (View, Int) -> Boolean = View::isViewVisibility
答案 1 :(得分:1)
错误消息指出:
'isViewVisibility'是成员和扩展名。不允许引用此类元素
这是说该方法既是扩展函数(也是您想要的),又是成员。您没有显示定义的整个上下文,但是可能看起来像这样:
// 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"))
}
答案 2 :(得分:0)
作为一种解决方法,您可以创建单独的普通函数,并从内联扩展方法调用它:
inline fun View.isVisibility(v: Int): Boolean = isViewVisibility(this, v)
fun isViewVisibility(v: View, k: Int): Boolean = (v.visibility == k)
您无法直接调用扩展方法,因为您没有可用的隐式this
对象。
答案 3 :(得分:0)
更合适的是扩展函数类型View.(Int) -> Boolean
:
val f: View.(Int) -> Boolean = View::isViewVisibility
但实际上扩展类型与正常的函数类型大多是可互换的(赋值兼容),接收者是第一个参数:
View.(Int) -> Boolean
↔(View, Int) -> Boolean
答案 4 :(得分:0)
使用具有两个参数的类型(第一个用于隐式接收器,如@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)
}
同样,上述内容应该全部运行,没有任何错误或警告。
答案 5 :(得分:0)
当我在另一个类中声明扩展函数并尝试将该扩展函数作为参数传递时,我遇到了相同的问题。
我找到了一种解决方法,方法是传递具有与扩展名相同签名的功能,然后将该功能委托给实际的扩展功能。
MyUtils.kt:
object MyUtils {
//extension to MyClass, signature: (Int)->Unit
fun MyClass.extend(val:Int) {
}
}
AnyClass.kt:
//importing extension from MyUtils
import MyUtils.extend
fun someMethodWithLambda(func: (Int)->Unit) {}
class AnyClass {
fun someMethod() {
//error
someMethodWithLambda(MyClass::extend) //member and extension at the same time
//workaround
val myClassInstance = MyClass()
someMethodWithLambda { val ->
myClassInstance.extend(val)
}
}
}