如何在构造函数中实现参数和路径相关的类型参数化?
How to achieve argument and path dependent type parametrization in constructor?
(使用 scala 2.11.12)
为什么编译?
sealed trait Inner
sealed trait Outer {
sealed trait I extends Inner
}
case object OuterA extends Outer {
case object Inner1 extends I
case object Inner2 extends I
}
case object OuterB extends Outer {
case object Inner1 extends I
}
class Data[O <: Outer](outer: O, inner: O#I)
// I expected this not to compile but it actually does
val data = new Data(OuterA, OuterB.Inner1)
为什么不能编译?
sealed trait Inner
sealed trait Outer {
type I <: Inner
}
case object OuterA extends Outer {
sealed trait OuterAInner extends Inner
override type I = OuterAInner
case object Inner1 extends OuterAInner
case object Inner2 extends OuterAInner
}
case object OuterB extends Outer {
sealed trait OuterBInner extends Inner
override type I = OuterBInner
case object Inner1 extends OuterBInner
}
class Data[O <: Outer](outer: O, inner: O#I)
// I expected this to compile but it actually does not
val data = new Data(OuterA, OuterA.Inner1)
// type mismatch;
// found : com.transparencyrights.ermine.model.V1.OuterA.Inner1.type
// required: ?#I
// Note that Inner1 extends Any, not AnyRef.
// Such types can participate in value classes, but instances
// cannot appear in singleton types or in reference comparisons.
// val data = new Data(OuterA, OuterA.Inner1)
我想要实现的是一个独特的 Data
构造函数,它接受两个参数,一个 Outer
和一个 Inner
,Inner
类型限制为 Inner
子类型依赖于给定的 Outer
实例。
在这两种情况下,问题是 O#I
没有按照您的意愿去做。
它实际上不是指您拥有的特定 O
内的 I
,而是指 Outer
.
内的通用
您可以使用路径相关类型和广义类型约束。
修复这两个片段
案例一
sealed trait Inner
sealed trait Outer {
sealed trait I extends Inner
}
final case object OuterA extends Outer {
final case object Inner1 extends I
final case object Inner2 extends I
}
final case object OuterB extends Outer {
final case object Inner1 extends I
}
final class Data[O <: Outer, I <: O#I] private (outer: O, inner: I)
object Data {
final def apply[O <: Outer, I <: O#I](outer: O, inner: I)(implicit ev: I <:< outer.I): Data[O, I] =
new Data(outer, inner)
}
val data = Data(OuterA, OuterB.Inner1) // Does not compile.
val data = Data(OuterA, OuterA.Inner1) // Does compile.
案例二
sealed trait Inner
sealed trait Outer {
type I <: Inner
}
final case object OuterA extends Outer {
override final type I = OuterAInner
sealed trait OuterAInner extends Inner
final case object Inner1 extends OuterAInner
final case object Inner2 extends OuterAInner
}
final case object OuterB extends Outer {
override final type I = OuterBInner
sealed trait OuterBInner extends Inner
final case object Inner1 extends OuterBInner
}
final class Data[O <: Outer, I <: O#I] private (outer: O, inner: I)
object Data {
final def apply[O <: Outer, I <: O#I](outer: O, inner: I)(implicit ev: I <:< outer.I): Data[O, I] =
new Data(outer, inner)
}
val data = new Data(OuterA, OuterA.Inner1) // Does compile.
val data = new Data(OuterA, OuterB.Inner1) // Does not compile.
现在,由于示例没有显示您想如何使用 Data class 和 outer & 内个字段,这可能还不够,希望对你有帮助。
如果您有任何疑问,请随时在评论中提问。
(使用 scala 2.11.12)
为什么编译?
sealed trait Inner
sealed trait Outer {
sealed trait I extends Inner
}
case object OuterA extends Outer {
case object Inner1 extends I
case object Inner2 extends I
}
case object OuterB extends Outer {
case object Inner1 extends I
}
class Data[O <: Outer](outer: O, inner: O#I)
// I expected this not to compile but it actually does
val data = new Data(OuterA, OuterB.Inner1)
为什么不能编译?
sealed trait Inner
sealed trait Outer {
type I <: Inner
}
case object OuterA extends Outer {
sealed trait OuterAInner extends Inner
override type I = OuterAInner
case object Inner1 extends OuterAInner
case object Inner2 extends OuterAInner
}
case object OuterB extends Outer {
sealed trait OuterBInner extends Inner
override type I = OuterBInner
case object Inner1 extends OuterBInner
}
class Data[O <: Outer](outer: O, inner: O#I)
// I expected this to compile but it actually does not
val data = new Data(OuterA, OuterA.Inner1)
// type mismatch;
// found : com.transparencyrights.ermine.model.V1.OuterA.Inner1.type
// required: ?#I
// Note that Inner1 extends Any, not AnyRef.
// Such types can participate in value classes, but instances
// cannot appear in singleton types or in reference comparisons.
// val data = new Data(OuterA, OuterA.Inner1)
我想要实现的是一个独特的 Data
构造函数,它接受两个参数,一个 Outer
和一个 Inner
,Inner
类型限制为 Inner
子类型依赖于给定的 Outer
实例。
在这两种情况下,问题是 O#I
没有按照您的意愿去做。
它实际上不是指您拥有的特定 O
内的 I
,而是指 Outer
.
您可以使用路径相关类型和广义类型约束。
修复这两个片段案例一
sealed trait Inner
sealed trait Outer {
sealed trait I extends Inner
}
final case object OuterA extends Outer {
final case object Inner1 extends I
final case object Inner2 extends I
}
final case object OuterB extends Outer {
final case object Inner1 extends I
}
final class Data[O <: Outer, I <: O#I] private (outer: O, inner: I)
object Data {
final def apply[O <: Outer, I <: O#I](outer: O, inner: I)(implicit ev: I <:< outer.I): Data[O, I] =
new Data(outer, inner)
}
val data = Data(OuterA, OuterB.Inner1) // Does not compile.
val data = Data(OuterA, OuterA.Inner1) // Does compile.
案例二
sealed trait Inner
sealed trait Outer {
type I <: Inner
}
final case object OuterA extends Outer {
override final type I = OuterAInner
sealed trait OuterAInner extends Inner
final case object Inner1 extends OuterAInner
final case object Inner2 extends OuterAInner
}
final case object OuterB extends Outer {
override final type I = OuterBInner
sealed trait OuterBInner extends Inner
final case object Inner1 extends OuterBInner
}
final class Data[O <: Outer, I <: O#I] private (outer: O, inner: I)
object Data {
final def apply[O <: Outer, I <: O#I](outer: O, inner: I)(implicit ev: I <:< outer.I): Data[O, I] =
new Data(outer, inner)
}
val data = new Data(OuterA, OuterA.Inner1) // Does compile.
val data = new Data(OuterA, OuterB.Inner1) // Does not compile.
现在,由于示例没有显示您想如何使用 Data class 和 outer & 内个字段,这可能还不够,希望对你有帮助。
如果您有任何疑问,请随时在评论中提问。