【问题标题】:How call static method with params using :: in kotlin如何在 kotlin 中使用 :: 调用带参数的静态方法
【发布时间】:2021-01-31 08:06:27
【问题描述】:

想象一下,当我们需要在 kotlin 中使用 :: 来调用带有参数的静态方法时。实际上我只能使用没有参数的函数来做到这一点,例如

Base64::hashCode

但是当我尝试使用时

Base64::encodeToString

然后我收到一个警告

重载分辨率不明确。所有这些功能都匹配。 public open fun encodeToString(input: ByteArray!, flags: Int): String!在 android.util.Base64 中定义 public open fun encodeToString(input: ByteArray!, offset: Int, len: Int, flags: Int): String!在android.util.Base64中定义

编译器也不接受这种形式

(Base64::encodeToString)( byteArrayOf(2), Base64.DEFAULT)

我想使用 here 描述的 mockito 的新功能来模拟此方法

感谢您提供任何信息!

【问题讨论】:

  • 您是在尝试调用该方法,还是获取对它的引用?在 Kotlin 中,:: 运算符仅用于后者(以便您可以将引用传递给将使用它的 else 对象)。如果你想 call 方法,你可以像在 Java 中那样做,例如Base64.encodeToString(…)。或者,如果您想要参考,我希望上下文允许它被消除歧义——如果不是,也许您可​​以发布周围的代码?
  • 是的,我需要该方法的参考,但是对于具有多个参数的方法,我不能这样做。

标签: kotlin reference static


【解决方案1】:

您可以显式指定类型,因此它知道您想要引用哪个函数:

import kotlin.reflect.KFunction2

val encode: KFunction2<ByteArray, Int, ByteArray> = Base64::encode

其中KFunction2 表示它是一个 2 参数函数,ByteArrayInt 是参数 - 最后一个 ByteArray 是返回类型。

::encode是一个静态函数,所以它只是处理调用过程中传入的参数。相比之下,hashcode() 是一个实例方法,因此即使 调用本身 不带参数,该函数也会带一个 Base64 实例(你调用 hashCode() ):

val hashCode: KFunction1<Base64, Int> = Base64::hashCode

(实例类型,返回类型)

所以它基本上是这样工作的 - 你可以定义 encode 函数引用 val 并像往常一样调用它,参数提示会告诉你它知道它是哪个函数。

不能保证它对你正在做的任何事情都有效!

【讨论】:

    【解决方案2】:

    一般来说,可调用引用语法不能与重载方法一起使用,因为编译器不知道您希望他选择什么变体(在这种情况下使用24 参数)。 但这不是这里唯一的问题。

    以这种方式获得的实例的类型是KFunction,在有参数的情况下,它的处理方式与function types不同(这是众所周知的,但仍不固定的编译器bug)。

    因此,我认为您需要使用以下语法模拟 encodeToString 方法的两个重载变体(如果您想使用其中任何一个):

    Mockito.mockStatic(Base64::class.java).use { theMock ->
        theMock.`when`<Any> { Base64.encodeToString(any(), any()) }.thenReturn("MyMockString")
        theMock.`when`<Any> { Base64.encodeToString(any(), any(), any(), any()) }.thenReturn("MyMockString")
        assertEquals("MyMockString", Base64.encodeToString(byteArrayOf(), 111))
        assertEquals("MyMockString", Base64.encodeToString(byteArrayOf(), 111, 111, 111))
    }
    

    另请注意,Mockito javadocs 说:

    我们建议不要在标准库中模拟类的静态方法

    【讨论】:

      【解决方案3】:

      :: 语法非常有限,因为它不允许泛型类型参数和具有多个参数的方法。然而,没有什么能阻止你像这样传递 lambda 引用:

      { param ->
          param.encodeToString()
      }
      

      【讨论】:

      • 感谢亚当!但是你提到的限制的描述在哪里?我试图找到这些信息,但没有成功。至于使用 lambda,您能解释一下在我的情况下如何传递 lambda 吗?谢谢。
      猜你喜欢
      • 2018-10-18
      • 2015-11-02
      • 2012-10-02
      • 1970-01-01
      • 2020-06-21
      • 2011-09-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多