Generics Scala:抽象类型与泛型
我在看书。什么时候使用抽象类型更好 比如说,Generics Scala:抽象类型与泛型,generics,scala,abstract-type,Generics,Scala,Abstract Type,我在看书。什么时候使用抽象类型更好 比如说, abstract class Buffer { type T val element: T } abstract class Buffer[T] { val element: T } 比如说泛型 abstract class Buffer { type T val element: T } abstract class Buffer[T] { val element: T } 当我读到有关Scala的文章时,我也有同样
abstract class Buffer {
type T
val element: T
}
abstract class Buffer[T] {
val element: T
}
比如说泛型
abstract class Buffer {
type T
val element: T
}
abstract class Buffer[T] {
val element: T
}
当我读到有关Scala的文章时,我也有同样的问题 使用泛型的优点是您正在创建一个类型族。没有人需要子类化
Buffer
——他们可以使用Buffer[Any]
,Buffer[String]
等
如果您使用抽象类型,那么人们将被迫创建一个子类。人们需要像AnyBuffer
,StringBuffer
等类
你需要决定哪一个更适合你的特殊需要。你在这个问题上有很好的观点:
与马丁·奥德斯基的对话,第三部分
比尔·维纳斯和弗兰克·索默斯(2009年5月18日) 更新(2009年10月):Bill Venners的这篇新文章实际上说明了以下内容:
(见最后的总结)
(以下是2009年5月第一次采访的相关摘录,重点) 一般原则 抽象的概念一直有两种:
- 参数化和
- 抽象成员李>
在Java中,有抽象方法,但不能将方法作为参数传递。
您没有抽象字段,但可以将值作为参数传递。
同样,您没有抽象类型成员,但可以指定类型作为参数。
所以在Java中,您也有这三个方面,但是对于什么样的事物可以使用什么样的抽象原则是有区别的。你可以说这种区别是相当武断的 斯卡拉路 我们决定对所有三种类型的成员采用相同的构造原则 因此,您可以有抽象字段和值参数。
您可以将方法(或“函数”)作为参数传递,也可以对其进行抽象。
您可以将类型指定为参数,也可以对其进行抽象。
我们从概念上得到的是,我们可以根据另一个对一个进行建模。至少在原则上,我们可以将各种参数化表示为一种面向对象的抽象形式。所以在某种意义上,你可以说Scala是一种更加正交和完整的语言 为什么? 特别是,抽象类型为您提供的是一种很好的处理协方差问题的方法。
一个长期存在的标准问题是动物和食物问题。
难题是要有一个类
动物
,它有一个方法,吃
,吃一些食物。问题是,如果我们把动物分为一个亚类,并且有一个类,比如牛,那么它们只吃草,而不吃任意的食物。例如,牛不能吃鱼。
你想说的是,牛有一种只吃草而不吃其他东西的吃法。
实际上,在Java中不能这样做,因为事实证明,可以构造不合理的情况,比如我前面提到的将水果分配给Apple变量的问题 答案是将抽象类型添加到动物类中
你说,我的新动物课有一种我不知道的
适宜食物
所以它是一种抽象类型。您没有给出该类型的实现。然后你就有了一个只吃适合的食物的eat
方法
然后在奶牛
类中,我会说,好吧,我有一头奶牛,它扩展了类动物
,对于奶牛类型,适宜的食物等于草
因此,抽象类型在我不知道的超类中提供了类型的概念,然后我用我知道的东西在子类中填充它
参数化也一样吗?
你确实可以。你可以用动物吃的食物种类来参数化动物类。
但是在实践中,当您对许多不同的事物执行此操作时,会导致参数爆炸,而且通常情况下,在参数范围内
在1998年的ECOOP上,Kim Bruce、Phil Wadler和我发表了一篇论文,其中我们展示了当你增加你不知道的事情的数量时,典型的程序将以二次方式增长
所以有很好的理由不使用参数,而是使用这些抽象成员,因为它们不会给你这个二次放大
在评论中询问:
你是否认为以下是一个公正的总结:
- 抽象类型用于“has-a”或“uses-a”关系(例如a
奶牛吃草
)
- 其中as泛型通常是“of”关系(例如,
int列表
)
我不确定使用抽象类型和泛型之间的关系有多大不同。
不同之处在于:
- 如何使用,以及
- 如何管理参数边界
理解马丁在谈到“参数爆炸”时所说的,并且通常,在<强>参数范围< /强>中,当抽象类型使用泛型建模时,它随后的二次增长,可以考虑……写的“<强> < /强>”。马丁·奥德斯基(Martin Odersky)和马蒂亚斯·曾格(Matthias Zenger)在《2005年OOPSLA》(2007年完成)中引用
相关摘录
定义
抽象类型成员提供了一种灵活的方法来抽象具体类型的组件。
抽象类型可以隐藏有关组件内部的信息,类似于它们在签名中的使用。在一个面向对象的框架中,类可以通过继承进行扩展,它们也可以作为一种灵活的参数化方法(通常称为族多态性,参见本文和作者的论文)
(注:Fami
// Type member version
class MySuite extends FixtureSuite3 with MyHandyFixture {
// ...
}
// Type parameter version
class MySuite extends FixtureSuite[StringBuilder] with StringBuilderFixture {
// ...
}
// Type member version
class MySuite extends FixtureSuite with StringBuilderFixture {
type FixtureParam = StringBuilder
// ...
}
trait AA[B,C]
trait BB[C,A]
trait CC[A,B]
trait AA[B<:BB[C,AA[B,C]],C<:CC[AA[B,C],B]]
trait BB[C<:CC[A,BB[C,A]],A<:AA[BB[C,A],C]]
trait CC[A<:AA[B,CC[A,B]],B<:BB[CC[A,B],A]]
trait AA[+B<:BB[C,AA[B,C]],+C<:CC[AA[B,C],B]]
trait BB[+C<:CC[A,BB[C,A]],+A<:AA[BB[C,A],C]]
trait CC[+A<:AA[B,CC[A,B]],+B<:BB[CC[A,B],A]]
trait AA[+B<:BB[C,AA[B,C]],+C<:CC[AA[B,C],B]] {
def forth(x:B):C
def back(x:C):B
}
trait BB[+C<:CC[A,BB[C,A]],+A<:AA[BB[C,A],C]] {
def forth(x:C):A
def back(x:A):C
}
trait CC[+A<:AA[B,CC[A,B]],+B<:BB[CC[A,B],A]] {
def forth(x:A):B
def back(x:B):A
}
//one trait to rule them all
trait OO[O <: OO[O]] { this : O =>
type A <: AA[O]
type B <: BB[O]
type C <: CC[O]
}
trait AA[O <: OO[O]] { this : O#A =>
type A = O#A
type B = O#B
type C = O#C
def left(l:B):C
def right(r:C):B = r.left(this)
def join(l:B, r:C):A
def double(l:B, r:C):A = this.join( l.join(r,this), r.join(this,l) )
}
trait BB[O <: OO[O]] { this : O#B =>
type A = O#A
type B = O#B
type C = O#C
def left(l:C):A
def right(r:A):C = r.left(this)
def join(l:C, r:A):B
def double(l:C, r:A):B = this.join( l.join(r,this), r.join(this,l) )
}
trait CC[O <: OO[O]] { this : O#C =>
type A = O#A
type B = O#B
type C = O#C
def left(l:A):B
def right(r:B):A = r.left(this)
def join(l:A, r:B):C
def double(l:A, r:B):C = this.join( l.join(r,this), r.join(this,l) )
}
class ReprO extends OO[ReprO] {
override type A = ReprA
override type B = ReprB
override type C = ReprC
}
case class ReprA(data : Int) extends AA[ReprO] {
override def left(l:B):C = ReprC(data - l.data)
override def join(l:B, r:C) = ReprA(l.data + r.data)
}
case class ReprB(data : Int) extends BB[ReprO] {
override def left(l:C):A = ReprA(data - l.data)
override def join(l:C, r:A):B = ReprB(l.data + r.data)
}
case class ReprC(data : Int) extends CC[ReprO] {
override def left(l:A):B = ReprB(data - l.data)
override def join(l:A, r:B):C = ReprC(l.data + r.data)
}
class ListT {
type T
...
}
class List[T] {...}