从函数返回匿名对象并在 Kotlin 中推断类型
Returning anonymous object from function and infering type in Kotlin
我来自 Java,是 Kotlin 的新手。我正在尝试为单元测试目的创建声明式 DSL。这是我尝试创建通用构建器方法以使用声明性语法构造任何模型对象。
fun <T> having(t: Class<T>) = object {
infix fun with(fn: T.() -> Unit) = t.newInstance().apply(fn)
}
fun test() {
having(Pizza::class.java) with {
size = Size.NORMAL
cheese = Cheese.MOZARELLA
}
}
但是,having
函数 returns Any
类型具有对 with
函数的未解析引用。我可以将匿名对象提取到它自己的 class 中以使其编译,但它会让人觉得多余。是否可以使用返回 object
个实例的函数进行类型推断?
此外,我不确定我在这里是否以惯用的方式使用泛型。
having
函数的 return 类型被推断为 Any
的原因在 中有解释。基本上,您必须使 having
private
才能推断出所需的 return 类型。显然,对于您单元测试 DSL 而言,这不是一个可行的解决方案,它将被其他文件中的代码使用。
你可以考虑去掉having
这个词,直接将with
声明为KClass
上的extension/infix函数。
扩展函数:
fun <T: Any> KClass<T>.with(fn: T.() -> Unit) = this.createInstance().apply(fn)
// ...
Pizza::class.with {
size = Size.NORMAL
cheese = Cheese.MOZZARELLA
}
中缀函数:
infix fun <T: Any> KClass<T>.with(fn: T.() -> Unit) = this.createInstance().apply(fn)
fun main() {
Pizza::class with {
size = Size.NORMAL
cheese = Cheese.MOZZARELLA
}
}
您可以 return 包装对象,而不是 return 未指定类型的 object
,它声明 with
函数并包含原始 class对象。
这样你可以获得类型安全,同时保留你的 having
风格的 DSL。
data class WrappedInstance<T>(val data: T) {
infix fun with(applyFn: T.() -> Unit): T = data.also(applyFn)
}
fun <T : Any> having(kClass: KClass<T>): WrappedInstance<T> =
WrappedInstance(kClass.createInstance())
使用它,看起来像这样:
data class Pizza(var size: Int = 1, var cheese: Int = 1)
fun test() {
val pizza: Pizza = having(Pizza::class) with {
size = 3
cheese = 5
}
println(pizza.size)
println(pizza.cheese)
}
请注意,这和您原来的方法都有一个警告。它们仅适用于 class 带有构造函数的 es,不需要任何参数。
参见 KClass<T>.createInstance()
的文档:
Creates a new instance of the class, calling a constructor which either has no parameters or all parameters of which are optional (see KParameter.isOptional). If there are no or many such constructors, an exception is thrown.
如果不需要 DSL 的 having
部分,请查看 。
我来自 Java,是 Kotlin 的新手。我正在尝试为单元测试目的创建声明式 DSL。这是我尝试创建通用构建器方法以使用声明性语法构造任何模型对象。
fun <T> having(t: Class<T>) = object {
infix fun with(fn: T.() -> Unit) = t.newInstance().apply(fn)
}
fun test() {
having(Pizza::class.java) with {
size = Size.NORMAL
cheese = Cheese.MOZARELLA
}
}
但是,having
函数 returns Any
类型具有对 with
函数的未解析引用。我可以将匿名对象提取到它自己的 class 中以使其编译,但它会让人觉得多余。是否可以使用返回 object
个实例的函数进行类型推断?
此外,我不确定我在这里是否以惯用的方式使用泛型。
having
函数的 return 类型被推断为 Any
的原因在 having
private
才能推断出所需的 return 类型。显然,对于您单元测试 DSL 而言,这不是一个可行的解决方案,它将被其他文件中的代码使用。
你可以考虑去掉having
这个词,直接将with
声明为KClass
上的extension/infix函数。
扩展函数:
fun <T: Any> KClass<T>.with(fn: T.() -> Unit) = this.createInstance().apply(fn)
// ...
Pizza::class.with {
size = Size.NORMAL
cheese = Cheese.MOZZARELLA
}
中缀函数:
infix fun <T: Any> KClass<T>.with(fn: T.() -> Unit) = this.createInstance().apply(fn)
fun main() {
Pizza::class with {
size = Size.NORMAL
cheese = Cheese.MOZZARELLA
}
}
您可以 return 包装对象,而不是 return 未指定类型的 object
,它声明 with
函数并包含原始 class对象。
这样你可以获得类型安全,同时保留你的 having
风格的 DSL。
data class WrappedInstance<T>(val data: T) {
infix fun with(applyFn: T.() -> Unit): T = data.also(applyFn)
}
fun <T : Any> having(kClass: KClass<T>): WrappedInstance<T> =
WrappedInstance(kClass.createInstance())
使用它,看起来像这样:
data class Pizza(var size: Int = 1, var cheese: Int = 1)
fun test() {
val pizza: Pizza = having(Pizza::class) with {
size = 3
cheese = 5
}
println(pizza.size)
println(pizza.cheese)
}
请注意,这和您原来的方法都有一个警告。它们仅适用于 class 带有构造函数的 es,不需要任何参数。
参见 KClass<T>.createInstance()
的文档:
Creates a new instance of the class, calling a constructor which either has no parameters or all parameters of which are optional (see KParameter.isOptional). If there are no or many such constructors, an exception is thrown.
如果不需要 DSL 的 having
部分,请查看