首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Scala协变容器

Scala协变容器
EN

Stack Overflow用户
提问于 2014-06-11 11:13:38
回答 1查看 340关注 0票数 2

我从一本Scala食谱上看到了一个例子。我理解了这个例子,并做了一些修改,以确保我彻底地理解了这个示例。

代码示例,

代码语言:javascript
复制
trait Animal {
    def speak
}

class Dog(var name: String) extends Animal {
    def speak { println("Dog says woof") }
}

class SuperDog(name: String) extends Dog(name) {
     override def speak { println("I'm a SuperDog") }
} 

// solution 1
class Container[+T](val elem : T) 

def makeDogsSpeak(dogHouse: Container[Dog]) {
    dogHouse.elem.speak
}

val superDogHouse = new Container(new SuperDog("Wonder Dog")) 
makeDogsSpeak(superDogHouse) 

代码语言:javascript
复制
// solution 2
class Container[T](val elem : T)  // remove covariant from type 

def makeDogsSpeak[U <: Dog](dogHouse: Container[U]) {
    dogHouse.elem.speak
}

val superDogHouse = new Container(new SuperDog("Wonder Dog"))
makeDogsSpeak(superDogHouse)
  1. 与解决方案2相比,解决方案1有什么优势吗?还是说这是偏好的问题?
  2. 对于解决方案1,我将代码修改为,

代码语言:javascript
复制
class Container[T](val elem : T) // remove covariant from type       
val superDogHouse = new Container(new SuperDog("Wonder Dog")) 
makeDogsSpeak(superDogHouse) // compilation error

但如果我这么做

代码语言:javascript
复制
makeDogsSpeak(new Container(new SuperDog("Wonder Dog"))) // superDogHouse removed

编译器编译了。这里发生了什么事?不是“相同”的密码吗?谢谢

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2014-06-11 11:49:20

关于方差声明(问题1):

申报-一方差异:

代码语言:javascript
复制
class Container[+T](val elem : T)

使用-侧差异:

代码语言:javascript
复制
def makeDogsSpeak(dogHouse: Container[_ <: Dog])

使用声明或使用侧方差表示法取决于您的代码设计。在某些情况下,方法可以是泛型的(并且可以使用简短表示法的类型推断),但在某些情况下,方法不能是泛型的。

对于某些类来说,参数约束只是实现良好设计的一种方法。例如:

代码语言:javascript
复制
trait List[+A]
object Nil extends List[Nothing]

使用:

代码语言:javascript
复制
val xs : List[Int] = Nil // will not possible in case List[A]

在某些情况下,还需要混合声明&使用侧变量,因为参数在容器中的位置与方差有关。

共变位置参数:

代码语言:javascript
复制
trait C[+T] {
  def get : T
}

反变位置:

代码语言:javascript
复制
trait C[-T] {
  def set(x : T): Unit
}

但不是:

代码语言:javascript
复制
trait C[+T] {
  def get : T 
  def set(x : T): Unit // wrong position of type T
}

通过混合声明-&使用侧方差来修正:

代码语言:javascript
复制
trait C[+T] {
  def get : T 
  def set[TT >: T](x : TT): Unit // ok
}

关于问题2

考虑到类型推断的规则,对于编译器,代码如下所示:

代码语言:javascript
复制
val superDogHouse = new Container[SuperDog](new SuperDog("Wonder Dog")) 
makeDogsSpeak(superDogHouse) // compilation error

代码语言:javascript
复制
makeDogsSpeak(new Container[Dog](new SuperDog("Wonder Dog")))

它在第一种情况下工作而在第二种情况下不起作用的原因是一种容器。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/24161491

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档