我定义了以下类型:
trait Context
trait Attribute[C <: Context]
trait AttributeDefinition[A[_ <: Context] <: Attribute[C] forSome { type C <: Context }] {
def read[C <: Context]: A[C]
}
我希望AttributeDefinition
返回由上下文参数化的Attribute
。每个定义仅适用于Attribute
的一种类型。可以想像:
class ConstantValueAttribute[C <: Context] extends Attribute[C]
object ConstantValueAttributeDefinition extends AttributeDefinition[ConstantValueAttribute] {
override def read[C <: Context]: ConstantValueAttribute[C] = ???
}
这完全编译好,但是我无法制作接受无界AttributeDefinition
的方法签名。以及创建AttributeDefinition
s的集合。以下所有都失败了:
def def1(attribute: AttributeDefinition): Unit = ???
def def2(attribute: AttributeDefinition[_]): Unit = ???
def def3(attribute: AttributeDefinition[_ <: Attribute[C] forSome { type C <: Context }]): Unit = ???
def def4(attribute: AttributeDefinition[A[_]] forSome { type A <: Attribute[C]; type C <: Context })
修改:
我正在尝试找到一个像上面那样编译的方法声明。我还想弄清楚如何声明AttributeDefinition
s的集合。
val val1 = new mutable.ArrayBuffer[AttributeDefinition]
如果这是不可能的,我想知道如何简化上面的特征仍然可以捕获简单的读取方法声明。
答案 0 :(得分:3)
基本上,你想要的defN
- 声明和Seq
- AttributeDeclaration
的集合是Attribute
的更高的kinded存在类型,用作参数AttributeDeclaration
。所以,理想情况下,您希望:
def def1(attrDef: AttributeDeclaration[A] forSome {
type A[C <: Context] <: Attribute[C] }): Unit = ???
但是,这个does not work,这是一个unresolved issue since 2015,所以很有可能它会在dotty之前修复。
我没有尝试强制编译器使用更高的kinded存在,以便你可以丢弃不必要的类型参数,我建议你不要首先添加恼人的类型参数。考虑这些定义(用2.12.4编译):
trait Context
trait Attribute[C <: Context]
trait AttributeDefinition {
type A[C <: Context] <: Attribute[C]
def read[C <: Context]: A[C]
}
class ConstantValueAttribute[C <: Context] extends Attribute[C]
object ConstantValueAttributeDefinition extends AttributeDefinition {
type A[C <: Context] = ConstantValueAttribute[C]
def read[C <: Context]: ConstantValueAttribute[C] = ???
}
def def1(attrDef: AttributeDefinition): Unit = ???
val collDefs: Seq[AttributeDefinition] = List(ConstantValueAttributeDefinition)
这些定义具有以下属性:
Context
和Attribute
保持不变A
成为AttributeDefinition
的类型成员,因此不必被以后的存在主义强行删除read
- 签名完全不变,它与原始代码中的字符相同,字符为def1
声明无需更改即可立即生效(基本上也是从您的代码1:1复制而来)AttributeDefinition
s的集合的声明和定义也同样顺利。回想一下,如果从类型参数移动到类型成员,您甚至不会丢失任何内容,因为您始终可以按名称引用类型成员(例如,当您想对该类型成员施加额外限制时)。以下最小示例应该演示如何对类型成员施加额外限制(与您的代码模糊相关,使用Context
):
trait Foo {
type Member
}
def restrictiveFoo(x: Foo { type Member <: Context }): Unit = ???
在这里,您可以强制参与者Foo
拥有源自Context
的类型成员。它同样适用于type Member = Context
。我想通过它来证明:如果你引入它们,它不像类型成员永远隐藏在特征中。你可以使用类型参数几乎所有相同的东西。总结一下:
因此,我建议使用类型成员。
A
更改为+A
使其编译的另一个快速解决方法:
trait Context
trait Attribute[C <: Context]
trait AttributeDefinition[+A[X <: Context] <: Attribute[X]] {
def read[C <: Context]: A[C]
}
class ConstantValueAttribute[C <: Context] extends Attribute[C]
object ConstantValueAttributeDefinition
extends AttributeDefinition[ConstantValueAttribute] {
override def read[C <: Context]: ConstantValueAttribute[C] = ???
}
class FooValueAttribute[C <: Context] extends Attribute[C]
object FooValueAttributeDefinition
extends AttributeDefinition[FooValueAttribute] {
override def read[C <: Context]: FooValueAttribute[C] = ???
}
def def1(attrDef: AttributeDefinition[Attribute]): Unit = {}
def1(ConstantValueAttributeDefinition)
val listOfDefs: List[AttributeDefinition[Attribute]] = List(
ConstantValueAttributeDefinition,
FooValueAttributeDefinition
)
受到this question答案的启发。奇怪的是,它似乎几乎完全相同的星座。但是,它并没有解决更高的kinded存在问题,相反,A
的方差已更改为+A
,因此可以使用Attribute
作为所有具体的最小上限{ {1}}秒。
答案 1 :(得分:1)
正确的签名是
def `def`[A[_ <: Context] <: Attribute[C] forSome { type C <: Context }](attribute: AttributeDefinition[A]) = ???
您需要为您的函数使用一个类型参数,该参数应该(至少)具有与您的类型相同的约束。
注意:在我看来,这就是为什么你应该避免对你的类型的类型参数设置类型约束的原因,它们应该只放在函数/操作上。
答案 2 :(得分:0)
trait Context
trait Attribute[+Context]
trait AttributeDefinition[Attribute] {
def read[Context]: Attribute
}
class ConstantValueAttribute extends Attribute[Context]
object ConstantValueAttributeDefinition extends AttributeDefinition[ConstantValueAttribute] {
def read[Context]: ConstantValueAttribute = ???
}
def def1[C](attribute: AttributeDefinition[C]) : Unit = ???
作为简化的暗示。