From 51d91b66a9d296ea9f0d5f082d54ffb6a93f38ec Mon Sep 17 00:00:00 2001 From: Dongxu Wang Date: Tue, 16 Oct 2018 14:55:45 +0800 Subject: [PATCH 1/2] Add Chinese translation of abstract-types. --- _zh-cn/tour/abstract-types.md | 62 ++++++++++++++++++++++++++++++++++- 1 file changed, 61 insertions(+), 1 deletion(-) diff --git a/_zh-cn/tour/abstract-types.md b/_zh-cn/tour/abstract-types.md index 6fe6dcdf04..e31906e2bd 100644 --- a/_zh-cn/tour/abstract-types.md +++ b/_zh-cn/tour/abstract-types.md @@ -1,6 +1,6 @@ --- layout: tour -title: Abstract Types +title: 抽象类型 discourse: false @@ -13,3 +13,63 @@ language: zh-cn next-page: compound-types previous-page: inner-classes --- + +特质和抽象类可以包含一个抽象类型成员,意味着实际类型可由具体实现来确定。例如: + +```tut +trait Buffer { + type T + val element: T +} +``` +这里定义的抽象类型`T`是用来描述成员`element`的类型的。通过抽象类来扩展这个特质后,就可以添加一个类型上边界来让抽象类型`T`变得更加具体。 + +```tut +abstract class SeqBuffer extends Buffer { + type U + type T <: Seq[U] + def length = element.length +} +``` +注意这里是如何借助另外一个抽象类型`U`来限定类型上边界的。通过声明类型`T`只可以是`Seq[U]`的子类(其中U是一个新的抽象类型),这个`SeqBuffer`类就限定了缓冲区中存储的元素类型只能是序列。 + +含有抽象类型成员的特质或类([classes](classes.html))经常和匿名类的初始化一起使用。为了能够阐明问题,下面看一段程序,它处理一个涉及整型列表的序列缓冲区。 + +```tut +abstract class IntSeqBuffer extends SeqBuffer { + type U = Int +} + + +def newIntSeqBuf(elem1: Int, elem2: Int): IntSeqBuffer = + new IntSeqBuffer { + type T = List[U] + val element = List(elem1, elem2) + } +val buf = newIntSeqBuf(7, 8) +println("length = " + buf.length) +println("content = " + buf.element) +``` +这里的工厂方法`newIntSeqBuf`使用了`IntSeqBuf`的匿名类实现方式,其类型`T`被设置成了`List[Int]`。 + +把抽象类型成员转成类的类型参数或者反过来,也是可行的。如下面这个版本只用了类的类型参数来转换上面的代码: + +```tut +abstract class Buffer[+T] { + val element: T +} +abstract class SeqBuffer[U, +T <: Seq[U]] extends Buffer[T] { + def length = element.length +} + +def newIntSeqBuf(e1: Int, e2: Int): SeqBuffer[Int, Seq[Int]] = + new SeqBuffer[Int, List[Int]] { + val element = List(e1, e2) + } + +val buf = newIntSeqBuf(7, 8) +println("length = " + buf.length) +println("content = " + buf.element) +``` + +需要注意的是为了隐藏从方法`newIntSeqBuf`返回的对象的具体序列实现的类型,这里的[型变标号](variances.html)(`+T <: Seq[U]`)是必不可少的。此外要说明的是,有些情况下用类型参数替换抽象类型是行不通的。 From 7a48e662173a74468c859eb49aee8ea41afe5443 Mon Sep 17 00:00:00 2001 From: Dongxu Wang Date: Thu, 18 Oct 2018 14:51:03 +0800 Subject: [PATCH 2/2] Add Chinese translation of upper-type-bounds. --- _zh-cn/tour/upper-type-bounds.md | 41 +++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/_zh-cn/tour/upper-type-bounds.md b/_zh-cn/tour/upper-type-bounds.md index fe321e4a0c..d13f6cb2fe 100644 --- a/_zh-cn/tour/upper-type-bounds.md +++ b/_zh-cn/tour/upper-type-bounds.md @@ -1,6 +1,6 @@ --- layout: tour -title: Upper Type Bounds +title: 类型上界 discourse: false @@ -13,3 +13,42 @@ language: zh-cn next-page: lower-type-bounds previous-page: variances --- + +在Scala中,[类型参数](generic-classes.html)和[抽象类型](abstract-types.html)都可以有一个类型边界约束。这种类型边界在限制类型变量实际取值的同时还能展露类型成员的更多信息。比如像`T <: A`这样声明的类型上界表示类型变量`T`应该是类型`A`的子类。下面的例子展示了类`PetContainer`的一个类型参数的类型上界。 + +```tut +abstract class Animal { + def name: String +} + +abstract class Pet extends Animal {} + +class Cat extends Pet { + override def name: String = "Cat" +} + +class Dog extends Pet { + override def name: String = "Dog" +} + +class Lion extends Animal { + override def name: String = "Lion" +} + +class PetContainer[P <: Pet](p: P) { + def pet: P = p +} + +val dogContainer = new PetContainer[Dog](new Dog) +val catContainer = new PetContainer[Cat](new Cat) +``` + +```tut:fail +// this would not compile +val lionContainer = new PetContainer[Lion](new Lion) +``` +类`PetContainer`接受一个必须是`Pet`子类的类型参数`P`。因为`Dog`和`Cat`都是`Pet`的子类,所以可以构造`PetContainer[Dog]`和`PetContainer[Cat]`。但在尝试构造`PetContainer[Lion]`的时候会得到下面的错误信息: + +`type arguments [Lion] do not conform to class PetContainer's type parameter bounds [P <: Pet]` + +这是因为`Lion`并不是`Pet`的子类。