类型参数化、方差与继承基础的使用 class
Usage of Type parameterization, variance vs Inheritance base class
我有一个问题,关于在 Scala 中定义 method/class 时何时使用类型参数化与基本 class 类型,尤其是当允许的类型位于同一层次结构中时 - 使用类型绑定进行约束。
例如:
trait TypeA
case class SubTypeA1(in: String) extends TypeA
case class SubTypeA2(in: String) extends TypeA
case class NewType[T <: TypeA](inTypeA: T)
case class NewTypeV2(inTypeA: TypeA)
def testMethod1(in: String): NewType[TypeA] = NewType(SubTypeA1(in))
def testMethod2(in: NewType[TypeA]): Unit = print("Some functionality")
def testMethod3(in: String): NewTypeV2 = NewTypeV2(SubTypeA1(in))
def testMethod4(in: NewTypeV2): Unit = print("Some functionality")
在上面的 case/in 中,当将允许的类型限制在某个上限时,NewType
比 NewTypeV2
有什么优势,反之亦然?他们看起来都和我一样。
据我所知,如果我要添加一些隐式条件检查,例如 NewType[T: Addable]
,它存在于不同层次结构的类型中,那么类型参数化就有意义了,除此之外我更喜欢类型参数化的原因是什么超过使用接口类型或基础 class 类型,例如 NewTypeV2
案例 class.
的 inTypeA
成员的类型
像 NewType[T] 这样定义类型参数化的方式是否被认为比其他方式更“函数式”风格?
其次,关于方差与类型界限的问题。在上面的代码块中,NewType 在类型 T 上是不变的,所以 NewType[SubTypeA1] 不是 NewType[TypeA] 的子类型,它们是不相关的,对吗?
如果我对类型不变性的理解如上所述是正确的,那么 testMethod1 是如何编译的?因为我明确地传递了 SubTypeA1 但它仍然被转换为 NewType[TypeA] 并且它也可以毫无问题地传递给 testMethod2 。我在这里误解了什么?
scala> testMethod1("test")
res0: NewType[TypeA] = NewType(SubTypeA1(test))
scala> testMethod2(testMethod1("test"))
Some functionality
scala> NewType(SubTypeA1("tst"))
res3: NewType[SubTypeA1] = NewType(SubTypeA1(tst))
case class NewType[T <: TypeA](inTypeA: T)
case class NewTypeV2(inTypeA: TypeA)
这两者的区别在于inTypeA
的类型:
在NewType
中,inTypeA
的类型是类型参数T
,它可以是TypeA
的任何子类型。编译器知道实际的子类型是什么。
在NewTypeV2
中inTypeA
的类型是TypeA
。该值将是 TypeA
的子类型,但编译器只知道它是 TypeA
如果您的方法需要 TypeA
的特定子类型,这很重要:
def subtypeMethod(in: SubTypeA1) = ???
val a1 = SubTypeA1("string")
val n = NewType(a1)
subtypeMethod(n.inTypeA) // Yes, inTypeA is type SubTypeA1
val n2 = NewTypeV2(a1)
subtypeMethod(n2.inTypeA) //No, inTypeA is type TypeA
我有一个问题,关于在 Scala 中定义 method/class 时何时使用类型参数化与基本 class 类型,尤其是当允许的类型位于同一层次结构中时 - 使用类型绑定进行约束。
例如:
trait TypeA
case class SubTypeA1(in: String) extends TypeA
case class SubTypeA2(in: String) extends TypeA
case class NewType[T <: TypeA](inTypeA: T)
case class NewTypeV2(inTypeA: TypeA)
def testMethod1(in: String): NewType[TypeA] = NewType(SubTypeA1(in))
def testMethod2(in: NewType[TypeA]): Unit = print("Some functionality")
def testMethod3(in: String): NewTypeV2 = NewTypeV2(SubTypeA1(in))
def testMethod4(in: NewTypeV2): Unit = print("Some functionality")
在上面的 case/in 中,当将允许的类型限制在某个上限时,NewType
比 NewTypeV2
有什么优势,反之亦然?他们看起来都和我一样。
据我所知,如果我要添加一些隐式条件检查,例如 NewType[T: Addable]
,它存在于不同层次结构的类型中,那么类型参数化就有意义了,除此之外我更喜欢类型参数化的原因是什么超过使用接口类型或基础 class 类型,例如 NewTypeV2
案例 class.
inTypeA
成员的类型
像 NewType[T] 这样定义类型参数化的方式是否被认为比其他方式更“函数式”风格?
其次,关于方差与类型界限的问题。在上面的代码块中,NewType 在类型 T 上是不变的,所以 NewType[SubTypeA1] 不是 NewType[TypeA] 的子类型,它们是不相关的,对吗?
如果我对类型不变性的理解如上所述是正确的,那么 testMethod1 是如何编译的?因为我明确地传递了 SubTypeA1 但它仍然被转换为 NewType[TypeA] 并且它也可以毫无问题地传递给 testMethod2 。我在这里误解了什么?
scala> testMethod1("test")
res0: NewType[TypeA] = NewType(SubTypeA1(test))
scala> testMethod2(testMethod1("test"))
Some functionality
scala> NewType(SubTypeA1("tst"))
res3: NewType[SubTypeA1] = NewType(SubTypeA1(tst))
case class NewType[T <: TypeA](inTypeA: T)
case class NewTypeV2(inTypeA: TypeA)
这两者的区别在于inTypeA
的类型:
在NewType
中,inTypeA
的类型是类型参数T
,它可以是TypeA
的任何子类型。编译器知道实际的子类型是什么。
在NewTypeV2
中inTypeA
的类型是TypeA
。该值将是 TypeA
的子类型,但编译器只知道它是 TypeA
如果您的方法需要 TypeA
的特定子类型,这很重要:
def subtypeMethod(in: SubTypeA1) = ???
val a1 = SubTypeA1("string")
val n = NewType(a1)
subtypeMethod(n.inTypeA) // Yes, inTypeA is type SubTypeA1
val n2 = NewTypeV2(a1)
subtypeMethod(n2.inTypeA) //No, inTypeA is type TypeA