【问题标题】:How do I call extension methods from outside the class they are defined in?如何从定义它们的类外部调用扩展方法?
【发布时间】:2017-03-12 11:42:27
【问题描述】:

这是一个演示问题的最小示例:

abstract class Base {
    abstract fun String.extension(x: Char)
}

class Derived : Base() {
    override fun String.extension(x: Char) {
        // Calling lots of methods on String, hence extension method
        println("${first()} $length ${last()} ${firstOrNull { it == x }} ...")
    }
}

从 Java 调用扩展方法很简单:

Base o = new Derived();
o.extension("hello world", 'l');

但我不知道如何在纯 Kotlin 中做到这一点。 StringBase 似乎都没有 extension 方法。

【问题讨论】:

    标签: extension-methods kotlin


    【解决方案1】:

    首先,注意定义为成员的扩展函数需要两个接收者,一个是封闭类的实例(dispatch接收者,通常是封闭类的this),另一个是函数扩展的类型的实例(扩展接收器)。这记录在here

    因此,要从类外部调用这样的函数,您必须提供两个接收器。 Kotlin doesn't have any syntax 可以像 (x, "abc").stringExtension() 一样明确地执行此操作,但您可以使用 extension lambda 隐式提供调度接收器:

    class C(val name: String) {
        fun String.extended() = this + " extended by " + name
    }
    
    fun main(args: Array<String>) {
        val c = C("c")
        with(c) { println("abc".extended()) }
    }
    

    (runnable demo of this code)

    with(...) { ... } 块中,c 成为隐式接收器,因此允许您将其用作C 成员扩展中的调度接收器。这适用于任何其他将函数类型与接收器一起使用的函数:applyrunuse 等。

    在你的情况下,应该是with(o) { "hello world".extension('l') }

    正如@KirillRakhman 所指出的,C 的扩展函数的扩展接收器也可以隐式用作C 内部定义的扩展的调度接收器:

    fun C.someExtension() = "something".extended()
    

    【讨论】:

    • 我的意思是,不仅可以使用扩展lambdas,还可以使用扩展functions来提供隐式接收器。示例:fun C.inScope() = "".extended()
    【解决方案2】:

    要在使用它的类之外对扩展方法进行decale,您应该在类中实现它,您应该这样做:

    package com.sample.test
    
    import java.io.File
    
    fun File.folderLength() : Long {
        return 0L
    }
    

    所以在你的类中调用这个方法:

    package com.sample.util
    
    import com.sample.test.*
    import java.io.File
    
    class foo{
        fun getFolderSize(url: String) : Long{
            var file = new File("...")
            var length = file.folderLength()
            return length
        }
    }
    

    希望这对你有帮助。

    【讨论】:

      【解决方案3】:

      您的扩展函数仅在 Base/Derived 类中定义。见Declaring Extensions as Members

      abstract class Base {
          abstract fun String.extension(x: Char)
      }
      
      class Derived : Base() {
          override fun String.extension(x: Char) {
              // Calling lots of methods on String, hence extension method
              println("${first()} $length ${last()} ${firstOrNull { it == x }} ...")
          }
      
          fun callExtension(c: Char) {
              "hello".extension(c)
          }
      }
      
      fun main(args: Array<String>) {
          val base = Derived()
          base.callExtension('h')
      }
      

      【讨论】:

      • 实际上有一种方法可以从类外部调用 public 成员扩展:使用该类的隐式接收器实例。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-01-21
      • 1970-01-01
      • 2012-06-05
      • 2011-07-16
      • 2011-04-14
      • 1970-01-01
      • 2015-09-28
      相关资源
      最近更新 更多