Skip to content

Commit 25d5814

Browse files
authored
add code tab and modified translation. (#2817)
* add code tab and modified translation. * modified according to comments.
1 parent daeb986 commit 25d5814

File tree

1 file changed

+94
-15
lines changed

1 file changed

+94
-15
lines changed

_zh-cn/overviews/scala3-book/ca-type-classes.md

Lines changed: 94 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -14,101 +14,180 @@ permalink: "/zh-cn/scala3/book/:title.html"
1414
---
1515

1616

17-
_类型类_是一种抽象的参数化类型,它允许您在不使用子类型的情况下向任何封闭数据类型添加新行为。
17+
_类型类_ 是一种抽象的参数化类型,它允许您在不使用子类型的情况下向任何封闭数据类型添加新行为。
18+
如果你从 Java 那边过来,你可以将类型类视为类似于 [`java.util.Comparator[T]`][comparator] 的东西。
19+
20+
> Oliveira 等人写的论文 [“Type Classes as Objects and Implicits”][typeclasses-paper] (2010) 讨论了在 Scala 中类型类背后的基本观点。
21+
> 虽然论文用了旧的 Scala 版本,但其中的观点至今依然有用。
22+
1823
这在多用例中很有用,例如:
1924

2025
- 表达你不拥有的类型——来自标准库或第三方库——如何符合这种行为
2126
- 为多种类型表达这种行为,而不涉及这些类型之间的子类型关系
2227

23-
Scala 3 中,类型类只是具有一个或多个参数的 traits,其实现由 `given` 实例提供。
28+
类型类只是具有一个或多个参数的 traits,其实现在 Scala 3 中,`given` 实例提供,在 Scala 2 中用 `implicit`
2429

2530
## 例子
2631

27-
例如,`Show` 是 Haskell 中众所周知的类型类,下面的代码显示了在 Scala 3 中实现它的一种方法。
32+
例如,`Show` 是 Haskell 中众所周知的类型类,下面的代码显示了在 Scala 中实现它的一种方法。
2833
如果您认为 Scala 类没有 `toString` 方法,您可以定义一个 `Show` 类型类,然后把此行为添加到任意的类,这个类是能够转换为自定义字符串。
2934

3035
### 类型类
3136

3237
创建类型类的第一步是声明具有一个或多个抽象方法的参数化 trait。
3338
因为 `Showable` 只有一个名为 `show` 的方法,所以写成这样:
3439

40+
{% tabs 'definition' class=tabs-scala-version %}
41+
{% tab 'Scala 2' %}
42+
```scala
43+
// a type class
44+
trait Showable[A] {
45+
def show(a: A): String
46+
}
47+
```
48+
{% endtab %}
49+
{% tab 'Scala 3' %}
3550
```scala
3651
// a type class
3752
trait Showable[A]:
3853
extension(a: A) def show: String
3954
```
55+
{% endtab %}
56+
{% endtabs %}
4057

41-
这是 Scala 3 的说法,任何实现此 trait 的类型都必须定义 `show` 方法的工作方式。
42-
请注意,语法非常接近普通的 trait:
58+
请注意,通常当你要定义 `Show` trait时,下面这样的办法接近普通的面向对象的办法:
4359

60+
{% tabs 'trait' class=tabs-scala-version %}
61+
{% tab 'Scala 2' %}
62+
```scala
63+
// a trait
64+
trait Show {
65+
def show: String
66+
}
67+
```
68+
{% endtab %}
69+
{% tab 'Scala 3' %}
4470
```scala
4571
// a trait
4672
trait Show:
4773
def show: String
4874
```
75+
{% endtab %}
76+
{% endtabs %}
4977

5078
有几件重要的事情需要指出:
5179

52-
1.`Showable` 这样的类型类有一个类型参数 `A` 来说明我们为哪种类型提供了 `show` 的实现;相反,像 `Show` 这样的正常特征不会
53-
2. 要将 show 功能添加到特定类型 `A`正常 trait 需要 `A extends Show`,而对于类型类,我们需要实现 `Showable[A]`
54-
3. 为了在两个 `Showable` 中允许相同的方法调用语法来模仿 `Show`,我们将 `Showable.show` 定义为扩展方法。
80+
1.`Showable` 这样的类型类有一个类型参数 `A` 来说明我们为哪种类型提供了 `show` 的实现;相反,像 `Show` 这样的传统的 trait 不会
81+
2. 要将 show 功能添加到特定类型 `A`传统的 trait 需要 `A extends Show`,而对于类型类,我们需要实现 `Showable[A]`
82+
3. 在 Scala 3 中,为了在两个 `Showable` 中允许相同的方法调用语法来模仿 `Show`,我们将 `Showable.show` 定义为扩展方法。
5583

5684
### 实现具体实例
5785

5886
下一步是确定在应用程序中,`Showable` 适用于哪些类,然后为它们实现该行为。
5987
例如,为这个 `Person` 类实现 `Showable`
6088

89+
{% tabs 'person' %}
90+
{% tab 'Scala 2 and 3' %}
6191
```scala
6292
case class Person(firstName: String, lastName: String)
6393
```
94+
{% endtab %}
95+
{% endtabs %}
6496

65-
你将为 `Showable[Person]` 定义一个 `given` 值。
66-
这段代码为 `Person` 类提供了一个 `Showable` 的具体实例:
97+
你将为 `Showable[Person]` 定义一个 _规范值_ ,例如下面的代码为 `Person` 类提供了一个 `Showable` 的实例:
6798

99+
{% tabs 'instance' class=tabs-scala-version %}
100+
{% tab 'Scala 2' %}
101+
```scala
102+
implicit val showablePerson: Showable[Person] = new Showable[Person] {
103+
def show(p: Person): String =
104+
s"${p.firstName} ${p.lastName}"
105+
}
106+
```
107+
{% endtab %}
108+
{% tab 'Scala 3' %}
68109
```scala
69110
given Showable[Person] with
70111
extension(p: Person) def show: String =
71112
s"${p.firstName} ${p.lastName}"
72113
```
73-
74-
如图所示,这被定义为 `Person` 类的扩展方法,它使用 `show` 方法主体内的引用 `p`
114+
{% endtab %}
115+
{% endtabs %}
75116

76117
### 使用类型类
77118

78119
现在你可以像这样使用这个类型类:
79120

121+
{% tabs 'usage' class=tabs-scala-version %}
122+
{% tab 'Scala 2' %}
123+
```scala
124+
val person = Person("John", "Doe")
125+
println(showablePerson.show(person))
126+
```
127+
128+
注意,在实践中,类型类一般与类型未知的值一起使用,而不像下面章节展示的 `Person` 类。
129+
{% endtab %}
130+
{% tab 'Scala 3' %}
80131
```scala
81132
val person = Person("John", "Doe")
82133
println(person.show)
83134
```
135+
{% endtab %}
136+
{% endtabs %}
84137

85138
同样,如果 Scala 没有可用于每个类的 `toString` 方法,您可以使用此技术将 `Showable` 行为添加到您希望能够转换为 `String` 的任何类。
86139

87140
### 编写使用类型类的方法
88141

89142
与继承一样,您可以定义使用 `Showable` 作为类型参数的方法:
90143

144+
{% tabs 'method' class=tabs-scala-version %}
145+
{% tab 'Scala 2' %}
146+
```scala
147+
def showAll[A](as: List[A])(implicit showable: Showable[A]): Unit =
148+
as.foreach(a => println(showable.show(a)))
149+
150+
showAll(List(Person("Jane"), Person("Mary")))
151+
```
152+
{% endtab %}
153+
{% tab 'Scala 3' %}
91154
```scala
92-
def showAll[S: Showable](xs: List[S]): Unit =
93-
xs.foreach(x => println(x.show))
155+
def showAll[A: Showable](as: List[A]): Unit =
156+
as.foreach(x => println(a.show))
94157

95158
showAll(List(Person("Jane"), Person("Mary")))
96159
```
160+
{% endtab %}
161+
{% endtabs %}
97162

98163
### 具有多种方法的类型类
99164

100165
请注意,如果要创建具有多个方法的类型类,则初始语法如下所示:
101166

167+
{% tabs 'multiple-methods' class=tabs-scala-version %}
168+
{% tab 'Scala 2' %}
169+
```scala
170+
trait HasLegs[A] {
171+
def walk(a: A): Unit
172+
def run(a: A): Unit
173+
}
174+
```
175+
{% endtab %}
176+
{% tab 'Scala 3' %}
102177
```scala
103178
trait HasLegs[A]:
104179
extension (a: A)
105180
def walk(): Unit
106181
def run(): Unit
107182
```
183+
{% endtab %}
184+
{% endtabs %}
108185

109186
### 一个真实的例子
110187

111188
有关如何在 Scala 3 中使用类型类的真实示例,请参阅[多元相等性部分][multiversal]中的 `CanEqual` 讨论。
112189

113-
190+
[typeclasses-paper]: https://infoscience.epfl.ch/record/150280/files/TypeClasses.pdf
191+
[typeclasses-chapter]: {% link _overviews/scala3-book/ca-type-classes.md %}
192+
[comparator]: https://docs.oracle.com/javase/8/docs/api/java/util/Comparator.html
114193
[multiversal]: {% link _zh-cn/overviews/scala3-book/ca-multiversal-equality.md %}

0 commit comments

Comments
 (0)