【问题标题】:Reference constructor of type excluding optional parameters不包括可选参数的类型的引用构造函数
【发布时间】:2018-07-14 00:08:47
【问题描述】:

我有 A 类型的类,它有构造函数,需要参数 x 并有一些可选参数:

class A(x: String, y: String = "default_y")

现在我想用必需的参数来引用构造函数:

var function: (String) -> A = ::A

现在我遇到了类型不兼容的问题,因为该构造函数的签名是 2 个字符串,而不仅仅是一个。

当我添加这个构造函数重载时,编译器停止抱怨:

class A(x: String, y: String = "default_y") {

constructor(x: String): this(x, "default_y")
}
//added just so you can see full code
var function: (String) -> A = ::A

我现在得到了一点冗余。我当然可以对此做一些事情(将"default_y" 提取为常量或从主构造函数中删除默认参数)以消除冗余,但这只是糖代码,并没有真正做任何事情。只是允许我参考它而不抱怨。 有没有办法将构造函数(也可能是函数)作为只有必需参数的函数来引用?

【问题讨论】:

    标签: lambda constructor kotlin


    【解决方案1】:

    herehere 所述,您不能通过反射使用默认参数。

    方法参数的默认值是一个任意表达式,只能表示为一段字节码;没有其他表示可以在反射中使用。 Parameter Info通过解析源码获取默认参数值。

    作为一种解决方法,您可以让编译器为您的构造函数生成 JVM 重载,然后使用 Java 反射来调用采用单个 String 参数的构造函数:

    class A @JvmOverloads constructor(x: String, val y: String = "default_y")
    
    val con: Constructor<A> = A::class.java.constructors
            .filterIsInstance<Constructor<A>>()
            .find { it.parameterCount == 1 } ?: throw IllegalStateException("Not found!")
    val newInstance: A = con.newInstance("myArg")
    println(newInstance.y) // Prints 'default_y'
    

    编辑:

    使用callBy,您还可以使用 Kotlin 反射调用构造函数:

    val con = MyClass::class.constructors.first()
    val newInst =
        con.callBy(mapOf(con.parameters.first() to "myArg"))
    

    【讨论】:

    • 严格来说,我并不是在谈论反射。我的代码是平台无关的(使用新的多平台功能),所以我不能使用@JvmOverloads,它也不能在 javascript 中工作。但是感谢您的回答,它清除了一些。
    • 我不确定它在这里是否相关,但实际上您可以通过 Kotlin 反射使用默认参数:使用callBy,您可以省略映射中参数的条目以使用默认值。这似乎也适用于 Kotlin/JS。
    【解决方案2】:

    虽然无法获取从签名中删除默认参数的函数引用,但您可以使用 lambda 代替函数引用并调用仅提供所需参数的构造函数:

    val function: (String) -> A = { A(it) } // uses the default for `y`
    

    【讨论】:

      猜你喜欢
      • 2021-03-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-02-26
      • 2011-02-22
      • 2021-08-06
      • 1970-01-01
      • 2017-09-14
      相关资源
      最近更新 更多