我有以下abstrac基类
lapply(mget(paste0("model",1:10)),deviance)
例如,由abstract class Vec2t<T : Number>(open var x: T, open var y: T) {
companion object {
val SIZE = 2 * when (/** T instance type */) {
is Byte, is Ubyte -> 1
is Short, is Ushort -> 2
is Int, is Uint, is Float -> 4
is Long, is Ulong, is Double -> 8
else -> throw ArithmeticException("Type undefined")
}
}
}
Vec2
我想知道是否可以在data class Vec2(override var x: Float, override var y: Float) : Vec2t<Float>(x, y)
中定义SIZE
并调用其中一个实现,例如Vec2t
答案 0 :(得分:4)
您可以在运行时检查x
和/或y
的类型,并懒惰地初始化size
属性:
abstract class Vec2t<T : Number>(open var x: T, open var y: T) {
val size by lazy {
2 * when (x) {
is Byte -> 1
is Short -> 2
is Int, is Float -> 4
is Long, is Double -> 8
else -> throw ArithmeticException("Type undefined")
}
}
}
如果x
和/或y
为final
,那么您还可以跳过延迟初始化并直接初始化它:
abstract class Vec2t<T : Number>(var x: T, var y: T) {
val size = 2 * when (x) {
is Byte -> 1
is Short -> 2
is Int, is Float -> 4
is Long, is Double -> 8
else -> throw ArithmeticException("Type undefined")
}
}
答案 1 :(得分:2)
我喜欢建议的解决方案@mfulton26,它很适合这个用例。以下答案仅适用于您不能依赖值的类型的情况(例如T
是Any
,并且您想要确切知道它是什么,但{{1}的所有实例1}}传递给你的班级恰好是T
s)。
首先,String
中的val
不能为您的类的不同实例设置不同的值,因为首先,伴随对象与实例无关,它是一个单独的对象并获取其属性不会(也不能)涉及其封闭类的实例。似乎companion object
应该是会员财产。
但是即使对于成员属性和函数,检查类型参数size
也不能直接完成,因为Kotlin中的泛型与Java中的泛型类似,并且type erasure也是如此,因此在运行时你不能使用实际类型参数进行操作。
为此,您可以在T
中存储KClass<T>
(或Class<T>
)对象,并根据它实现您的逻辑:
Vec2t<T>
这将要求子类将参数添加到其超类构造函数调用中:
abstract class Vec2t<T : Number>(open var x: T,
open var y: T,
private val type: KClass<T>) {
val size: Int by lazy {
2 * when (type) {
Byte::class -> 1
Short::class -> 2
Int::class, Float::class -> 4
Long::class, Double::class -> 8
else -> throw ArithmeticException("Type undefined")
}
}
}
如果您选择此方法,Kotlin还可以向您reified generics寻求帮助,以便您可以避免在使用网站上明确指定class Vec2(override var x: Float, override var y: Float) : Vec2t<Float>(x, y, Float::class)
。例如,如果您的SomeType::class
不是抽象的,则可以使用此工厂函数构建它:
Vec2t<T>
使用内联函数,可以只访问实际类型参数,因为函数是在调用站点内联的,因此它的类型参数在编译时始终是已知的。不幸的是,构造函数不能有任何类型参数。
使用方法:
inline fun <reified T: Number> vec2t(x: T, y: T) = Vec2t(x, y, T::class)
答案 2 :(得分:2)
虽然您不能“拥有对于通用类的不同实例化具有不同值的静态字段”(如@yole commented),但您可以定义每个实现及其伴随对象的属性。 e.g:
abstract class Vec2t<T : Number> {
abstract var x: T
abstract var y: T
abstract val size: Int
}
class Vec2f(override var x: Float, override var y: Float) : Vec2t<Float>() {
companion object {
const val SIZE = 2 * 4
}
override val size: Int
get() = SIZE
}
class Vec2d(override var x: Double, override var y: Double) : Vec2t<Double>() {
companion object {
const val SIZE = 2 * 8
}
override val size: Int
get() = SIZE
}
这允许您在想知道特定实现的大小时引用Vec2f.SIZE
,Vec2d.SIZE
等,并在有实例时引用vec2t.size
(可能是未知的实现)输入并获得它的大小。