Kotlin成员和扩展同时进行

Kotlin成员和扩展同时进行,kotlin,kotlin-extension,Kotlin,Kotlin Extension,为了更好地了解Kotlin,并尝试使用它,我正在开发一个示例Android应用程序,在这里我可以尝试不同的东西 然而,即使在搜索了一段时间后,我仍然无法找到以下问题的正确答案: 让我们在视图类上声明一个(虚拟)扩展函数: fun View.isViewVisibility(v: Int): Boolean = visibility == v 现在,我如何从其他地方引用该函数,以便稍后对其调用invoke() 目前给了我: 错误:(57,35)类型不匹配:推断的类型为KFunction2,但(I

为了更好地了解Kotlin,并尝试使用它,我正在开发一个示例Android应用程序,在这里我可以尝试不同的东西

然而,即使在搜索了一段时间后,我仍然无法找到以下问题的正确答案:

让我们在视图类上声明一个(虚拟)扩展函数:

fun View.isViewVisibility(v: Int): Boolean = visibility == v
现在,我如何从其他地方引用该函数,以便稍后对其调用invoke()

目前给了我:

错误:(57,35)类型不匹配:推断的类型为KFunction2,但(Int)->Boolean为 expectedError:(57,41)'isViewVisibility'是一个成员和扩展名 同时,。不允许引用此类元素

有什么解决办法吗?
谢谢

作为一种解决方法,您可以创建一个单独的普通函数,并从内联扩展方法调用它:

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
val prop: (String, Int) -> Boolean = String::foo

fun bar() {
    prop("bar", 123)
}
// MyClass.kt

class MyClass {
  fun String.coolStringExtension() = "Cool $this"

  val bar = String::coolStringExtension
}

fun main() {
    print(MyClass().bar("foo"))
}

更适合的是扩展函数类型
View.(Int)->Boolean

val f: View.(Int) -> Boolean = View::isViewVisibility
但实际上,扩展类型大多与普通函数类型可互换(分配兼容),接收器是第一个参数:


View.(Int)->Boolean
(View,Int)->Boolean

使用带有两个参数的类型(第一个用于隐式接收器,正如@Bakawaii已经提到的)或扩展类型,这两种类型都应该在没有任何警告的情况下工作

我们以这个函数为例:

fun String.foo(f: Int) = true
可以使用“将其指定给具有以下两个参数函数类型的属性”:

val f: (View, Int) -> Boolean = View::isViewVisibility
val prop: (String, Int) -> Boolean = String::foo

fun bar() {
    prop("bar", 123)
}
// MyClass.kt

class MyClass {
  fun String.coolStringExtension() = "Cool $this"

  val bar = String::coolStringExtension
}

fun main() {
    print(MyClass().bar("foo"))
}
或者,您可以使用扩展函数类型,然后可以使用以下两种语法之一调用该类型:

val prop2: String.(Int) -> Boolean = String::foo

fun bar2() {
    prop2("bar2", 123)
    "bar2".prop2(123)
}

同样,上述操作应该在没有任何错误或警告的情况下运行。

当我在另一个类中声明扩展函数并尝试将该扩展函数作为参数传递时,我遇到了相同的问题

我找到了一种解决方法,通过传递与扩展具有相同签名的函数,该函数反过来又委托给实际的扩展函数

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”同时是成员和扩展名。不允许引用此类元素

这意味着该方法既是一个扩展函数,也是一个成员。您没有显示定义的整个上下文,但它可能看起来像这样:

val f: (View, Int) -> Boolean = View::isViewVisibility
val prop: (String, Int) -> Boolean = String::foo

fun bar() {
    prop("bar", 123)
}
// 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"))
}

我面临的问题不是View.isVisibility
的实现,而是如何引用它。因此,也许唯一的方法是另一种方法(一个普通的函数,我们可以引用,并且可以在视图中调用扩展函数)如果您对类型的看法是正确的,它解决了类型不匹配的问题。我仍然保留着“成员和扩展同时进行”,这似乎目前还不受支持。我会接受你的回答,我们会看看语言是否会在某个时候支持这一点。谢谢是的,如本文所述,似乎仍在考虑中。@NSimon顺便说一句,我刚刚忽略了您提到的这个错误。很抱歉,我只是认为您的扩展函数是顶级函数。您可以提供一个更具体的示例来演示此问题,例如,编写一个完整的类,并在该类中声明扩展函数,以查看是否有人可以在此问题之外为您提供额外的解释。对不起,我知道这是旧的,但为了人们搜索解决方案:事实上,问题是,您的函数不是顶级函数。无法引用定义为其他类的类成员的扩展。不知道为什么。只需将扩展定义为顶级函数,就可以了。嗯,很有趣。你们有什么Kotlin版本?我肯定应该在
1.1.50
上工作。更新:在的在线IDE中尝试此操作,在选中
1.1.4
的情况下不起作用,仅在
1.1.50
及更高版本时才起作用。也许这在当时的版本中是固定的。你是对的,这很奇怪。我正在AndroidStudio中运行1.1.51版。它在您提供的链接上运行良好,但在AS中不起作用。也许更新还没有完全进入插件?你的Kotlin插件也更新到1.1.51了吗?它也适用于我。我使用的是AS 3.0 Beta 7(顶级gradle文件的类路径为“org.jetbrains.kotlin:kotlin gradle plugin:$kotlin_version”)和(模块级gradle文件的实现为“org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version”)。Kotlin版本在顶级gradle文件中定义为ext.Kotlin_version='1.1.51'。所以我应该是最新的是的。