From 688d535749ff000af422f995f8162c668ebee62a Mon Sep 17 00:00:00 2001 From: Ben Luo Date: Fri, 13 Jan 2023 20:54:44 +0800 Subject: [PATCH 1/3] add tabs in zh-cn/overview/scala3-book/num9 --- .../overviews/scala3-book/taste-modeling.md | 229 +++++++++++++++++- 1 file changed, 218 insertions(+), 11 deletions(-) diff --git a/_zh-cn/overviews/scala3-book/taste-modeling.md b/_zh-cn/overviews/scala3-book/taste-modeling.md index 57981e10d3..1e4afe828c 100644 --- a/_zh-cn/overviews/scala3-book/taste-modeling.md +++ b/_zh-cn/overviews/scala3-book/taste-modeling.md @@ -32,7 +32,7 @@ It’s more about modeling operations, imho.” How to resolve? Is there a good DDD term to use here? {% endcomment %} -### traits +### Traits Scala trait 可以用作简单的接口,但它们也可以包含抽象和具体的方法和字段,并且它们可以有参数,就像类一样。 它们为您提供了一种将行为组织成小型模块化单元的好方法。 @@ -40,6 +40,30 @@ Scala trait 可以用作简单的接口,但它们也可以包含抽象和具 作为如何将 traits 用作接口的示例,以下是三个 traits,它们为狗和猫等动物定义了结构良好并且模块化的行为: +{% tabs traits class=tabs-scala-version %} +{% tab 'Scala 2' for=traits %} + +```scala +trait Speaker { + def speak(): String // has no body, so it’s abstract +} + +trait TailWagger { + def startTail(): Unit = println("tail is wagging") + def stopTail(): Unit = println("tail is stopped") +} + +trait Runner { + def startRunning(): Unit = println("I’m running") + def stopRunning(): Unit = println("Stopped running") +} +``` + +{% endtab %} + +{% tab 'Scala 3' for=traits %} + + ```scala trait Speaker: def speak(): String // 没有函数体,这样它是抽象的。 @@ -53,17 +77,51 @@ trait Runner: def stopRunning(): Unit = println("Stopped running") ``` +{% endtab %} +{% endtabs %} + 鉴于这些特征,这里有一个 `Dog` 类,它扩展了所有这些特征,同时为抽象 `speak` 方法提供了一种行为: +{% tabs traits-class class=tabs-scala-version %} +{% tab 'Scala 2' for=traits-class %} + +```scala +class Dog(name: String) extends Speaker with TailWagger with Runner { + def speak(): String = "Woof!" +} +``` + +{% endtab %} + +{% tab 'Scala 3' for=traits-class %} + ```scala class Dog(name: String) extends Speaker, TailWagger, Runner: def speak(): String = "Woof!" ``` +{% endtab %} +{% endtabs %} + 请注意该类如何使用 `extends` 关键字扩展 traits。 类似地,这里有一个 `Cat` 类,它实现了这些相同的 traits,同时还覆盖了它继承的两个具体方法: +{% tabs traits-override class=tabs-scala-version %} +{% tab 'Scala 2' for=traits-override %} + +```scala +class Cat(name: String) extends Speaker with TailWagger with Runner { + def speak(): String = "Meow" + override def startRunning(): Unit = println("Yeah ... I don’t run") + override def stopRunning(): Unit = println("No need to stop") +} +``` + +{% endtab %} + +{% tab 'Scala 3' for=traits-override %} + ```scala class Cat(name: String) extends Speaker, TailWagger, Runner: def speak(): String = "Meow" @@ -71,8 +129,28 @@ class Cat(name: String) extends Speaker, TailWagger, Runner: override def stopRunning(): Unit = println("No need to stop") ``` +{% endtab %} +{% endtabs %} + 这些示例显示了如何使用这些类: +{% tabs traits-use class=tabs-scala-version %} +{% tab 'Scala 2' for=traits-use %} + +```scala +val d = new Dog("Rover") +println(d.speak()) // prints "Woof!" + +val c = new Cat("Morris") +println(c.speak()) // "Meow" +c.startRunning() // "Yeah ... I don’t run" +c.stopRunning() // "No need to stop" +``` + +{% endtab %} + +{% tab 'Scala 3' for=traits-use %} + ```scala val d = Dog("Rover") println(d.speak()) // prints "Woof!" @@ -83,6 +161,9 @@ c.startRunning() // "Yeah ... I don’t run" c.stopRunning() // "No need to stop" ``` +{% endtab %} +{% endtabs %} + 如果该代码有意义---太好了,您把 traits 作为接口感到舒服。 如果没有,请不要担心,它们在 [Domain Modeling][data-1] 章节中有更详细的解释。 @@ -91,6 +172,24 @@ c.stopRunning() // "No need to stop" Scala _classes_ 用于 OOP 风格的编程。 这是一个模拟“人”的类的示例。在 OOP 中,字段通常是可变的,所以 `firstName` 和 `lastName` 都被声明为 `var` 参数: +{% tabs class_1 class=tabs-scala-version %} +{% tab 'Scala 2' for=class_1 %} + +```scala +class Person(var firstName: String, var lastName: String) { + def printFullName() = println(s"$firstName $lastName") +} + +val p = new Person("John", "Stephens") +println(p.firstName) // "John" +p.lastName = "Legend" +p.printFullName() // "John Legend" +``` + +{% endtab %} + +{% tab 'Scala 3' for=class_1 %} + ```scala class Person(var firstName: String, var lastName: String): def printFullName() = println(s"$firstName $lastName") @@ -101,13 +200,31 @@ p.lastName = "Legend" p.printFullName() // "John Legend" ``` +{% endtab %} +{% endtabs %} + 请注意,类声明创建了一个构造函数: -```斯卡拉 +{% tabs class_2 class=tabs-scala-version %} +{% tab 'Scala 2' for=class_2 %} + +```scala +// this code uses that constructor +val p = new Person("John", "Stephens") +``` + +{% endtab %} + +{% tab 'Scala 3' for=class_2 %} + +```scala // 此代码使用该构造函数 val p = Person("约翰", "斯蒂芬斯") ``` +{% endtab %} +{% endtabs %} + [Domain Modeling][data-1] 章节中介绍了构造函数和其他与类相关的主题。 ## FP 领域建模 @@ -120,20 +237,57 @@ to replace the Scala2 “sealed trait + case class” pattern. How to resolve? 以 FP 风格编写代码时,您将使用以下结构: -- 枚举来定义 ADT -- 样例类 -- Traits +- 代数数据类型(ADT)来定义数据 +- Traits 来定义数据上的功能 + +### 枚举和 Sum Types -### 枚举 +Sum types 是在 Scala 中给代数数据类型(ADT)建模的一种方法。 `enum` 构造是在 Scala 3 中对代数数据类型 (ADT) 进行建模的好方法。 + 例如,披萨具有三个主要属性: - 面饼大小 - 面饼类型 - 馅料 -这些是用枚举简洁地建模的: +这些是用枚举简洁地建模的,它们是只包含单例值的 sum types: + +{% tabs enum_1 class=tabs-scala-version %} +{% tab 'Scala 2' for=enum_1 %} + +In Scala 2 `sealed` classes and `case object` are combined to define an enumeration: + +```scala +sealed abstract class CrustSize +object CrustSize { + case object Small extends CrustSize + case object Medium extends CrustSize + case object Large extends CrustSize +} + +sealed abstract class CrustType +object CrustType { + case object Thin extends CrustType + case object Thick extends CrustType + case object Regular extends CrustType +} + +sealed abstract class Topping +object Topping { + case object Cheese extends Topping + case object Pepperoni extends Topping + case object BlackOlives extends Topping + case object GreenOlives extends Topping + case object Onions extends Topping +} +``` + +{% endtab %} +{% tab 'Scala 3' for=enum_1 %} + +Scala 3 提供了 `enum` 结构来定义枚举: ```scala enum CrustSize: @@ -146,8 +300,32 @@ enum Topping: case Cheese, Pepperoni, BlackOlives, GreenOlives, Onions ``` +{% endtab %} +{% endtabs %} + 一旦你有了一个枚举,你就可以按照你通常使用特征、类或对象的所有方式来使用枚举: +{% tabs enum_2 class=tabs-scala-version %} +{% tab 'Scala 2' for=enum_2 %} + +```scala +import CrustSize._ +val currentCrustSize = Small + +// enums in a `match` expression +currentCrustSize match { + case Small => println("Small crust size") + case Medium => println("Medium crust size") + case Large => println("Large crust size") +} + +// enums in an `if` statement +if (currentCrustSize == Small) println("Small crust size") +``` + +{% endtab %} +{% tab 'Scala 3' for=enum_2 %} + ```scala import CrustSize.* val currentCrustSize = Small @@ -162,7 +340,26 @@ currentCrustSize match if currentCrustSize == Small then println("Small crust size") ``` -下面是另一个如何在 Scala 中创建和使用 ADT 的示例: +{% endtab %} +{% endtabs %} + +下面是另一个如何在 Scala 中创建 sum type 的示例,它不能被叫作枚举,因为 `succ` 样例类有参数:的示例: + +{% tabs enum_3 class=tabs-scala-version %} +{% tab 'Scala 2' for=enum_3 %} + +```scala +sealed abstract class Nat +object Nat { + case object Zero extends Nat + case class Succ(pred: Nat) extends Nat +} +``` + +Sum Types 在本书的[领域建模]({% link _overviews/scala3-book/domain-modeling-tools.md %})部分有详细的介绍。 + +{% endtab %} +{% tab 'Scala 3' for=enum_3 %} ```scala enum Nat: @@ -170,11 +367,15 @@ enum Nat: case Succ(pred: Nat) ``` -枚举在本书的 [领域建模][data-1] 部分和 [参考文档]({{ site.scala3ref }}/enums/enums.html) 中有详细介绍。 +枚举在本书的 [领域建模]({% link _overviews/scala3-book/domain-modeling-tools.md %})部分和 [参考文档]({{ site.scala3ref }}/enums/enums.html) 中有详细介绍。 + +{% endtab %} +{% endtabs %} -### 样例类 +### Product Types + +product type 是代数数据类型(ADT),它只含有一个形状,例如一个单例对象,在Scala 中用 `case` 对象来代表;或者是一个可以获取字段的不可变结构,用 `case` 类来代表。 -Scala `case` 类允许您使用不可变数据结构对概念进行建模。 `case` 类具有 `class` 的所有功能,还包含其他功能,使它们对函数式编程很有用。 当编译器在 `class` 前面看到 `case` 关键字时,它具有以下效果和好处: @@ -193,6 +394,9 @@ NOTE: Julien had a comment about how he decides when to use case classes vs clas 这段代码演示了几个 `case` 类的特性: +{% tabs case-class %} +{% tab 'Scala 2 and 3' for=case-class %} + ```scala // define a case class case class Person( @@ -216,6 +420,9 @@ val p2 = p.copy(name = "Elton John") p2 // : Person = Person(Elton John,Singer) ``` +{% endtab %} +{% endtabs %} + 有关 `case` 类的更多详细信息,请参阅 [领域建模][data-1] 部分。 [data-1]: {% link _zh-cn/overviews/scala3-book/domain-modeling-tools.md %} From 3b9f3e0d81aa7ba716971000d9a4c41a88d8ac3b Mon Sep 17 00:00:00 2001 From: Ben Luo Date: Tue, 17 Jan 2023 13:37:37 +0800 Subject: [PATCH 2/3] modified translation according review. --- _zh-cn/overviews/scala3-book/taste-modeling.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/_zh-cn/overviews/scala3-book/taste-modeling.md b/_zh-cn/overviews/scala3-book/taste-modeling.md index 1e4afe828c..a0d8a27ffc 100644 --- a/_zh-cn/overviews/scala3-book/taste-modeling.md +++ b/_zh-cn/overviews/scala3-book/taste-modeling.md @@ -66,7 +66,7 @@ trait Runner { ```scala trait Speaker: - def speak(): String // 没有函数体,这样它是抽象的。 + def speak(): String // has no body, so it’s abstract trait TailWagger: def startTail(): Unit = println("tail is wagging") @@ -257,7 +257,7 @@ Sum types 是在 Scala 中给代数数据类型(ADT)建模的一种方法。 {% tabs enum_1 class=tabs-scala-version %} {% tab 'Scala 2' for=enum_1 %} -In Scala 2 `sealed` classes and `case object` are combined to define an enumeration: +在 Scala 2 中,用 `sealed` 类和 `case object` 组合在一起来定义枚举: are combined to define an enumeration: ```scala sealed abstract class CrustSize From add4b1f8d584c5d6234245f0ab5d57f793ad23ec Mon Sep 17 00:00:00 2001 From: Jamie Thompson Date: Wed, 18 Jan 2023 10:09:20 +0100 Subject: [PATCH 3/3] Update _zh-cn/overviews/scala3-book/taste-modeling.md remove redundant english --- _zh-cn/overviews/scala3-book/taste-modeling.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_zh-cn/overviews/scala3-book/taste-modeling.md b/_zh-cn/overviews/scala3-book/taste-modeling.md index a0d8a27ffc..ca39aafe34 100644 --- a/_zh-cn/overviews/scala3-book/taste-modeling.md +++ b/_zh-cn/overviews/scala3-book/taste-modeling.md @@ -257,7 +257,7 @@ Sum types 是在 Scala 中给代数数据类型(ADT)建模的一种方法。 {% tabs enum_1 class=tabs-scala-version %} {% tab 'Scala 2' for=enum_1 %} -在 Scala 2 中,用 `sealed` 类和 `case object` 组合在一起来定义枚举: are combined to define an enumeration: +在 Scala 2 中,用 `sealed` 类和 `case object` 组合在一起来定义枚举: ```scala sealed abstract class CrustSize