我有几个我不控制的类,我已经在几个常见的属性上创建了几个同名的扩展方法。相同名称的扩展函数总是返回相同的值类型,尽管对于每种类型的接收器都以不同的方式进行计算。这是基于内置类型的简化示例,仅用于一个属性:
// * *不编译** //我无法控制的三个样本类扩展名为.len inline val String.len get()= length inline val< T> List< T> .len get()= size inline val< T> Sequence< T> .len get()= count() //需要使用.len class Calc< T>(val obj:T){ //这里是问题... val dbl get()= obj?.len * 2 //将double //以及其他使用.len和其他方法的其他方法并行扩展 fun main(a:Array< String>){ val s =abc val l = listOf(5,6,7 ) val q =(10..20步骤2).asSequence() val cs = Calc(s) val cl = Calc(l) val cq = Calc (q) println(Lens:$ {cs.dbl},$ {cl.dbl},$ {cq.dbl})}想象几个其他常见属性,在某些我不能控制的类中以与.len相同的方式扩展。如果我不想在每个类中重复自己,我应该如何构造一个可以在.len(以及其他类属性)上对这三个类进行操作的正确类型的类?
我研究了以下但未找到可行的解决方案:
下面是一个用密封类和一个扩展属性将任何东西转换为可以给你 len 或 double 。不知道它是否具有更好的可读性。
val任何?.calc get()= when(this){是字符串 - > Calc.CalcString(this)是List< *> - > Calc.CalcList(this)是序列< *> - > Calc.CalcSequense(this) else - > Calc.None } / *或者没有默认回退* / val String.calc get()= Calc.CalcString(this) val列表* * calcal get()= Calc.CalcList(this) val Sequence * .calc get()= Calc.CalcSequense(this) / *密封扩展类* / 密封类Calc { abstract val len:Int? val dbl:Int?通过lazy(LazyThreadSafetyMode.NONE){len?.let {it * 2}} 类CalcString(val s:String):Calc(){ override val len:Int? get()= s.length } class CalcList< out T>(val l:List< T>):Calc(){ override val len:Int? get()= l.size } class CalcSequense< out T>(val s:Sequence< T>):Calc(){ override val len:Int? get()= s.count()} 对象无:Calc(){覆盖val len:Int? get()= null } } fun main(args:Array< String>){ val s =abc.calc val l = listOf(5,6,7).calc val q =(10..20 step 2).asSequence()。calc println(Lens :$ {s.dbl},$ {l.dbl},$ {q.dbl})}
I have a several classes I don't control, upon which I've already created several identically-named extension methods across several common "attributes". The identically-named extension functions always return the same value type, though calculated in different ways for each type of receiver. Here is a simplified example based on built-in types for just one attribute:
// **DOES NOT COMPILE** // three sample classes I don't control extended for .len inline val String.len get() = length inline val <T> List<T>.len get() = size inline val <T> Sequence<T>.len get() = count() // another class which needs to act on things with .len class Calc<T>(val obj:T) { // HERE IS THE PROBLEM... val dbl get() = obj?.len * 2 // dummy property that doubles len // ... and other methods that use .len and other parallel extensions } fun main(a:Array<String>) { val s = "abc" val l = listOf(5,6,7) val q = (10..20 step 2).asSequence() val cs = Calc(s) val cl = Calc(l) val cq = Calc(q) println("Lens: ${cs.dbl}, ${cl.dbl}, ${cq.dbl}") }Imagine several other "common" properties extended in the same manner as .len in some classes I don't control. If I don't want to repeat myself in every class, how do I construct a properly typed class that can operate on .len (and other such properties) generically for these three classes?
I've researched the following but not found workable solutions yet:
- generics, in the example above, but can't get the syntax right.
- sealed classes, but I don't have control of these classes.
- union types, which I've found aren't supported in Kotlin.
- wrapper classes, but couldn't get the syntax right.
- passing lambdas a la this blog explanation, but didn't get it right, and it seemed boptimalsu to pass multiple lambdas around for every method.
There must be a better way, right?
解决方案Here's a example with sealed classes and a single extension property to convert anything to something which can give you len or double. Not sure if it has better readability thogh.
val Any?.calc get() = when(this) { is String -> Calc.CalcString(this) is List<*> -> Calc.CalcList(this) is Sequence<*> -> Calc.CalcSequense(this) else -> Calc.None } /* or alternatively without default fallback */ val String.calc get() = Calc.CalcString(this) val List<*>.calc get() = Calc.CalcList(this) val Sequence<*>.calc get() = Calc.CalcSequense(this) /* sealed extension classes */ sealed class Calc { abstract val len: Int? val dbl: Int? by lazy(LazyThreadSafetyMode.NONE) { len?.let { it * 2 } } class CalcString(val s: String): Calc() { override val len: Int? get() = s.length } class CalcList<out T>(val l: List<T>): Calc() { override val len: Int? get() = l.size } class CalcSequense<out T>(val s: Sequence<T>): Calc() { override val len: Int? get() = s.count() } object None: Calc() { override val len: Int? get() = null } } fun main(args: Array<String>) { val s = "abc".calc val l = listOf(5,6,7).calc val q = (10..20 step 2).asSequence().calc println("Lens: ${s.dbl}, ${l.dbl}, ${q.dbl}") }
更多推荐
Kotlin中扩展函数的多态性
发布评论