Skip to content

Commit e8fefb9

Browse files
benluobishabosha
andauthored
add tabs in zh-cn/overview/scala3-book/num9 (#2673)
* add tabs in zh-cn/overview/scala3-book/num9 * modified translation according review. * Update _zh-cn/overviews/scala3-book/taste-modeling.md remove redundant english Co-authored-by: Jamie Thompson <bishbashboshjt@gmail.com>
1 parent 5694c91 commit e8fefb9

File tree

1 file changed

+219
-12
lines changed

1 file changed

+219
-12
lines changed

_zh-cn/overviews/scala3-book/taste-modeling.md

Lines changed: 219 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -32,17 +32,41 @@ It’s more about modeling operations, imho.”
3232
How to resolve? Is there a good DDD term to use here?
3333
{% endcomment %}
3434

35-
### traits
35+
### Traits
3636

3737
Scala trait 可以用作简单的接口,但它们也可以包含抽象和具体的方法和字段,并且它们可以有参数,就像类一样。
3838
它们为您提供了一种将行为组织成小型模块化单元的好方法。
3939
稍后,当您想要创建属性和行为的具体实现时,类和对象可以扩展特征,根据需要混合尽可能多的特征以实现所需的行为。
4040

4141
作为如何将 traits 用作接口的示例,以下是三个 traits,它们为狗和猫等动物定义了结构良好并且模块化的行为:
4242

43+
{% tabs traits class=tabs-scala-version %}
44+
{% tab 'Scala 2' for=traits %}
45+
46+
```scala
47+
trait Speaker {
48+
def speak(): String // has no body, so it’s abstract
49+
}
50+
51+
trait TailWagger {
52+
def startTail(): Unit = println("tail is wagging")
53+
def stopTail(): Unit = println("tail is stopped")
54+
}
55+
56+
trait Runner {
57+
def startRunning(): Unit = println("I’m running")
58+
def stopRunning(): Unit = println("Stopped running")
59+
}
60+
```
61+
62+
{% endtab %}
63+
64+
{% tab 'Scala 3' for=traits %}
65+
66+
4367
```scala
4468
trait Speaker:
45-
def speak(): String // 没有函数体,这样它是抽象的。
69+
def speak(): String // has no body, so it’s abstract
4670

4771
trait TailWagger:
4872
def startTail(): Unit = println("tail is wagging")
@@ -53,26 +77,80 @@ trait Runner:
5377
def stopRunning(): Unit = println("Stopped running")
5478
```
5579

80+
{% endtab %}
81+
{% endtabs %}
82+
5683
鉴于这些特征,这里有一个 `Dog` 类,它扩展了所有这些特征,同时为抽象 `speak` 方法提供了一种行为:
5784

85+
{% tabs traits-class class=tabs-scala-version %}
86+
{% tab 'Scala 2' for=traits-class %}
87+
88+
```scala
89+
class Dog(name: String) extends Speaker with TailWagger with Runner {
90+
def speak(): String = "Woof!"
91+
}
92+
```
93+
94+
{% endtab %}
95+
96+
{% tab 'Scala 3' for=traits-class %}
97+
5898
```scala
5999
class Dog(name: String) extends Speaker, TailWagger, Runner:
60100
def speak(): String = "Woof!"
61101
```
62102

103+
{% endtab %}
104+
{% endtabs %}
105+
63106
请注意该类如何使用 `extends` 关键字扩展 traits。
64107

65108
类似地,这里有一个 `Cat` 类,它实现了这些相同的 traits,同时还覆盖了它继承的两个具体方法:
66109

110+
{% tabs traits-override class=tabs-scala-version %}
111+
{% tab 'Scala 2' for=traits-override %}
112+
113+
```scala
114+
class Cat(name: String) extends Speaker with TailWagger with Runner {
115+
def speak(): String = "Meow"
116+
override def startRunning(): Unit = println("Yeah ... I don’t run")
117+
override def stopRunning(): Unit = println("No need to stop")
118+
}
119+
```
120+
121+
{% endtab %}
122+
123+
{% tab 'Scala 3' for=traits-override %}
124+
67125
```scala
68126
class Cat(name: String) extends Speaker, TailWagger, Runner:
69127
def speak(): String = "Meow"
70128
override def startRunning(): Unit = println("Yeah ... I don’t run")
71129
override def stopRunning(): Unit = println("No need to stop")
72130
```
73131

132+
{% endtab %}
133+
{% endtabs %}
134+
74135
这些示例显示了如何使用这些类:
75136

137+
{% tabs traits-use class=tabs-scala-version %}
138+
{% tab 'Scala 2' for=traits-use %}
139+
140+
```scala
141+
val d = new Dog("Rover")
142+
println(d.speak()) // prints "Woof!"
143+
144+
val c = new Cat("Morris")
145+
println(c.speak()) // "Meow"
146+
c.startRunning() // "Yeah ... I don’t run"
147+
c.stopRunning() // "No need to stop"
148+
```
149+
150+
{% endtab %}
151+
152+
{% tab 'Scala 3' for=traits-use %}
153+
76154
```scala
77155
val d = Dog("Rover")
78156
println(d.speak()) // prints "Woof!"
@@ -83,6 +161,9 @@ c.startRunning() // "Yeah ... I don’t run"
83161
c.stopRunning() // "No need to stop"
84162
```
85163

164+
{% endtab %}
165+
{% endtabs %}
166+
86167
如果该代码有意义---太好了,您把 traits 作为接口感到舒服。
87168
如果没有,请不要担心,它们在 [Domain Modeling][data-1] 章节中有更详细的解释。
88169

@@ -91,6 +172,24 @@ c.stopRunning() // "No need to stop"
91172
Scala _classes_ 用于 OOP 风格的编程。
92173
这是一个模拟“人”的类的示例。在 OOP 中,字段通常是可变的,所以 `firstName``lastName` 都被声明为 `var` 参数:
93174

175+
{% tabs class_1 class=tabs-scala-version %}
176+
{% tab 'Scala 2' for=class_1 %}
177+
178+
```scala
179+
class Person(var firstName: String, var lastName: String) {
180+
def printFullName() = println(s"$firstName $lastName")
181+
}
182+
183+
val p = new Person("John", "Stephens")
184+
println(p.firstName) // "John"
185+
p.lastName = "Legend"
186+
p.printFullName() // "John Legend"
187+
```
188+
189+
{% endtab %}
190+
191+
{% tab 'Scala 3' for=class_1 %}
192+
94193
```scala
95194
class Person(var firstName: String, var lastName: String):
96195
def printFullName() = println(s"$firstName $lastName")
@@ -101,13 +200,31 @@ p.lastName = "Legend"
101200
p.printFullName() // "John Legend"
102201
```
103202

203+
{% endtab %}
204+
{% endtabs %}
205+
104206
请注意,类声明创建了一个构造函数:
105207

106-
```斯卡拉
208+
{% tabs class_2 class=tabs-scala-version %}
209+
{% tab 'Scala 2' for=class_2 %}
210+
211+
```scala
212+
// this code uses that constructor
213+
val p = new Person("John", "Stephens")
214+
```
215+
216+
{% endtab %}
217+
218+
{% tab 'Scala 3' for=class_2 %}
219+
220+
```scala
107221
// 此代码使用该构造函数
108222
val p = Person("约翰", "斯蒂芬斯")
109223
```
110224

225+
{% endtab %}
226+
{% endtabs %}
227+
111228
[Domain Modeling][data-1] 章节中介绍了构造函数和其他与类相关的主题。
112229

113230
## FP 领域建模
@@ -120,20 +237,57 @@ to replace the Scala2 “sealed trait + case class” pattern. How to resolve?
120237

121238
以 FP 风格编写代码时,您将使用以下结构:
122239

123-
- 枚举来定义 ADT
124-
- 样例类
125-
- Traits
240+
- 代数数据类型(ADT)来定义数据
241+
- Traits 来定义数据上的功能
242+
243+
### 枚举和 Sum Types
126244

127-
### 枚举
245+
Sum types 是在 Scala 中给代数数据类型(ADT)建模的一种方法。
128246

129247
`enum` 构造是在 Scala 3 中对代数数据类型 (ADT) 进行建模的好方法。
248+
130249
例如,披萨具有三个主要属性:
131250

132251
- 面饼大小
133252
- 面饼类型
134253
- 馅料
135254

136-
这些是用枚举简洁地建模的:
255+
这些是用枚举简洁地建模的,它们是只包含单例值的 sum types:
256+
257+
{% tabs enum_1 class=tabs-scala-version %}
258+
{% tab 'Scala 2' for=enum_1 %}
259+
260+
在 Scala 2 中,用 `sealed` 类和 `case object` 组合在一起来定义枚举:
261+
262+
```scala
263+
sealed abstract class CrustSize
264+
object CrustSize {
265+
case object Small extends CrustSize
266+
case object Medium extends CrustSize
267+
case object Large extends CrustSize
268+
}
269+
270+
sealed abstract class CrustType
271+
object CrustType {
272+
case object Thin extends CrustType
273+
case object Thick extends CrustType
274+
case object Regular extends CrustType
275+
}
276+
277+
sealed abstract class Topping
278+
object Topping {
279+
case object Cheese extends Topping
280+
case object Pepperoni extends Topping
281+
case object BlackOlives extends Topping
282+
case object GreenOlives extends Topping
283+
case object Onions extends Topping
284+
}
285+
```
286+
287+
{% endtab %}
288+
{% tab 'Scala 3' for=enum_1 %}
289+
290+
Scala 3 提供了 `enum` 结构来定义枚举:
137291

138292
```scala
139293
enum CrustSize:
@@ -146,8 +300,32 @@ enum Topping:
146300
case Cheese, Pepperoni, BlackOlives, GreenOlives, Onions
147301
```
148302

303+
{% endtab %}
304+
{% endtabs %}
305+
149306
一旦你有了一个枚举,你就可以按照你通常使用特征、类或对象的所有方式来使用枚举:
150307

308+
{% tabs enum_2 class=tabs-scala-version %}
309+
{% tab 'Scala 2' for=enum_2 %}
310+
311+
```scala
312+
import CrustSize._
313+
val currentCrustSize = Small
314+
315+
// enums in a `match` expression
316+
currentCrustSize match {
317+
case Small => println("Small crust size")
318+
case Medium => println("Medium crust size")
319+
case Large => println("Large crust size")
320+
}
321+
322+
// enums in an `if` statement
323+
if (currentCrustSize == Small) println("Small crust size")
324+
```
325+
326+
{% endtab %}
327+
{% tab 'Scala 3' for=enum_2 %}
328+
151329
```scala
152330
import CrustSize.*
153331
val currentCrustSize = Small
@@ -162,19 +340,42 @@ currentCrustSize match
162340
if currentCrustSize == Small then println("Small crust size")
163341
```
164342

165-
下面是另一个如何在 Scala 中创建和使用 ADT 的示例:
343+
{% endtab %}
344+
{% endtabs %}
345+
346+
下面是另一个如何在 Scala 中创建 sum type 的示例,它不能被叫作枚举,因为 `succ` 样例类有参数:的示例:
347+
348+
{% tabs enum_3 class=tabs-scala-version %}
349+
{% tab 'Scala 2' for=enum_3 %}
350+
351+
```scala
352+
sealed abstract class Nat
353+
object Nat {
354+
case object Zero extends Nat
355+
case class Succ(pred: Nat) extends Nat
356+
}
357+
```
358+
359+
Sum Types 在本书的[领域建模]({% link _overviews/scala3-book/domain-modeling-tools.md %})部分有详细的介绍。
360+
361+
{% endtab %}
362+
{% tab 'Scala 3' for=enum_3 %}
166363

167364
```scala
168365
enum Nat:
169366
case Zero
170367
case Succ(pred: Nat)
171368
```
172369

173-
枚举在本书的 [领域建模][data-1] 部分和 [参考文档]({{ site.scala3ref }}/enums/enums.html) 中有详细介绍。
370+
枚举在本书的 [领域建模]({% link _overviews/scala3-book/domain-modeling-tools.md %})部分和 [参考文档]({{ site.scala3ref }}/enums/enums.html) 中有详细介绍。
371+
372+
{% endtab %}
373+
{% endtabs %}
174374

175-
### 样例类
375+
### Product Types
376+
377+
product type 是代数数据类型(ADT),它只含有一个形状,例如一个单例对象,在Scala 中用 `case` 对象来代表;或者是一个可以获取字段的不可变结构,用 `case` 类来代表。
176378

177-
Scala `case` 类允许您使用不可变数据结构对概念进行建模。
178379
`case` 类具有 `class` 的所有功能,还包含其他功能,使它们对函数式编程很有用。
179380
当编译器在 `class` 前面看到 `case` 关键字时,它具有以下效果和好处:
180381

@@ -193,6 +394,9 @@ NOTE: Julien had a comment about how he decides when to use case classes vs clas
193394

194395
这段代码演示了几个 `case` 类的特性:
195396

397+
{% tabs case-class %}
398+
{% tab 'Scala 2 and 3' for=case-class %}
399+
196400
```scala
197401
// define a case class
198402
case class Person(
@@ -216,6 +420,9 @@ val p2 = p.copy(name = "Elton John")
216420
p2 // : Person = Person(Elton John,Singer)
217421
```
218422

423+
{% endtab %}
424+
{% endtabs %}
425+
219426
有关 `case` 类的更多详细信息,请参阅 [领域建模][data-1] 部分。
220427

221428
[data-1]: {% link _zh-cn/overviews/scala3-book/domain-modeling-tools.md %}

0 commit comments

Comments
 (0)