From e297f09fe7b85b176a49a34f4592adca14f502b2 Mon Sep 17 00:00:00 2001 From: sila-strike Date: Sun, 27 Oct 2024 19:39:04 +0700 Subject: [PATCH 1/2] update `/th/tour/traits` page --- _th/tour/traits.md | 147 +++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 136 insertions(+), 11 deletions(-) diff --git a/_th/tour/traits.md b/_th/tour/traits.md index 92dc07597c..ad75e54045 100644 --- a/_th/tour/traits.md +++ b/_th/tour/traits.md @@ -11,16 +11,28 @@ next-page: tuples previous-page: classes --- -Trait ใช้เพื่อแชร์ interface และ field ระหว่างคลาส มันจะเหมือนกับ interface ใน Java 8 -คลาส และ object สามารถขยาย trait ได้แต่ trait ไม่สามารถ instant เป็น object และไม่สามารถมี parameter ได้ +Trait ใช้เพื่อแชร์ interface และ field ระหว่างคลาส โดยที่ trait จะคล้ายกับ interface ใน Java 8\ +คลาส และ object สามารถ extend trait ได้ แต่เราไม่สามารถสร้าง object จาก trait ได้\ +ดังนั้น trait จึงไม่สามารถมี parameter เช่นเดียวกับที่คลาสมี + +## การกำหนด Trait -## การกำหนด trait วิธีที่ง่ายที่สุดในการกำหนด trait คือการประกาศด้วย keyword `trait` และ indentifier: +{% tabs trait-hair-color %} {% tab 'Scala 2 and 3' for=trait-hair-color %} + ```scala mdoc trait HairColor ``` + +{% endtab %} {% endtabs %} + trait จะมีประโยชน์อย่างยิ่งด้วยการเป็น generic type และเป็น abstract method + +{% tabs trait-iterator-definition class=tabs-scala-version %} + +{% tab 'Scala 2' for=trait-iterator-definition %} + ```scala mdoc trait Iterator[A] { def hasNext: Boolean @@ -28,10 +40,30 @@ trait Iterator[A] { } ``` -การขยาย `trait Iterator[A]` ต้องการ type `A` และ implementation ของ method `hasNext` และ `next` +{% endtab %} + +{% tab 'Scala 3' for=trait-iterator-definition %} + +```scala +trait Iterator[A]: + def hasNext: Boolean + def next(): A +``` + +{% endtab %} + +{% endtabs %} + +การขยาย (extend) `trait Iterator[A]` ต้องการ type `A` และ implementation ของ method `hasNext` และ `next` + +## การใช้ Trait + +ใช้ keyword `extends` เพื่อขยาย trait จากนั้นให้ implement abstract member ใดๆ ของ trait โดยใช้ keyword `override`: + +{% tabs trait-intiterator-definition class=tabs-scala-version %} + +{% tab 'Scala 2' for=trait-intiterator-definition %} -## การใช้ traits -ใช้ keyword `extends` เพื่อขยาย trait ดังนั้นจะ implement abstract member ใดๆ ของ trait โดยใช้ keyword `override`: ```scala mdoc:nest trait Iterator[A] { def hasNext: Boolean @@ -55,10 +87,75 @@ val iterator = new IntIterator(10) iterator.next() // returns 0 iterator.next() // returns 1 ``` -คลาส `IntIterator` นี้รับค่า parameter `to` เป็น upper bound มัน `extends Iterator[Int]` ซึ่งหมายความว่า method `next` จะต้อง return เป็น Int -## Subtyping -ในเมื่อ trait ที่ให้มานั้น required, subtype ของ trait สามารถถูกใช้แทนที่ได้ +{% endtab %} + +{% tab 'Scala 3' for=trait-intiterator-definition %} + +```scala +trait Iterator[A]: + def hasNext: Boolean + def next(): A + +class IntIterator(to: Int) extends Iterator[Int]: + private var current = 0 + override def hasNext: Boolean = current < to + override def next(): Int = + if hasNext then + val t = current + current += 1 + t + else + 0 +end IntIterator + +val iterator = new IntIterator(10) +iterator.next() // returns 0 +iterator.next() // returns 1 +``` + +{% endtab %} + +{% endtabs %} + +คลาส `IntIterator` นี้รับค่า parameter `to` เพื่อกำหนดค่าสูงสุด (upper bound) โดยที่คลาส `IntIterator` ได้ extend จาก `Iterator[Int]`\ +ดังนั้น method `next` จะต้อง return ค่าเป็น Int + +## การใช้ Subtype + +เมื่อจำเป็นต้องใช้ trait ใดๆ เราสามารถใช้ subtype (คลาสใดก็ตาม ที่ extend มาจาก trait นั้นๆ) แทนได้ + +> ***Note by Thai translator:***\ +> "เมื่อจำเป็นต้องใช้ trait ใดๆ" ในที่นี้ น่าจะหมายถึงเรามีการระบุไว้ว่า parameter ที่ได้ระบุ type เป็น trait\ +> ดังนั้นเราสามารถใช้ **subtype ใดๆ ที่ implement จาก trait นั้นๆ ได้** +> +> **ลองพิจารณา code นี้:** +> +> ```scala +> val dog = new Dog("Harry") // คลาส `Dog` เป็น subtype ของ trait `Pet` +> +> // parameter `pet` มี type เป็น trait `Pet` +> def getPetName(pet: Pet): String = pet.name +> +> getPetName(dog) +> ``` +> +> ถ้าอิงจากตัวอย่างจาก code block ด้านล่าง เราจะเห็นได้ว่า code ด้านบน\ +> เราส่งตัวแปร `dog` ซึ่งเป็น instance ของคลาส `Dog` ไปให้ function `getPetName`\ +> โดยที่คลาส `Dog` ก็เป็น subtype ของ trait `Pet` อีกทีหนึ่ง + +{% tabs trait-pet-example class=tabs-scala-version %} + +{% tab 'Scala 2' for=trait-pet-example %} + +{% tabs trait-pet-example class=tabs-scala-version %} + +{% tab 'Scala 2' for=trait-pet-example %} + +{% tabs trait-pet-example class=tabs-scala-version %} + +{% tab 'Scala 2' for=trait-pet-example %} + ```scala mdoc import scala.collection.mutable.ArrayBuffer @@ -76,6 +173,34 @@ val animals = ArrayBuffer.empty[Pet] animals.append(dog) animals.append(cat) animals.foreach(pet => println(pet.name)) // แสดงค่า Harry Sally + ``` -`trait Pet` มี abstract field `name` ซึ่ง implement โดย Cat และ Dog ใน constructor ของมัน -ในบรรทัดสุดท้าย เราเรียก `pet.name` ซึ่งจะต้องถูก implement แล้วใน subtype ใดๆ ของ trait `Pet` + +{% endtab %} + +{% tab 'Scala 3' for=trait-pet-example %} + +```scala +import scala.collection.mutable.ArrayBuffer + +trait Pet: + val name: String + +class Cat(val name: String) extends Pet +class Dog(val name: String) extends Pet + +val dog = Dog("Harry") +val cat = Cat("Sally") + +val animals = ArrayBuffer.empty[Pet] +animals.append(dog) +animals.append(cat) +animals.foreach(pet => println(pet.name)) // แสดงค่า Harry Sally +``` + +{% endtab %} + +{% endtabs %} + +`trait Pet` มี abstract field `name` ซึ่ง implement ไว้ใน constructor ของคลาส `Cat` และ `Dog`\ +ในบรรทัดสุดท้าย เราเรียกใช้ `pet.name` ซึ่งได้มีการ implement `name` ไว้ใน subtype ใดๆ ของ trait `Pet` แล้ว From e9a8f43c1221bcf9fae1151ba928aed4b9636790 Mon Sep 17 00:00:00 2001 From: fResult Sila Date: Fri, 1 Nov 2024 13:56:42 +0700 Subject: [PATCH 2/2] fix error after solving conflict --- Gemfile.lock | 3 +++ _th/tour/traits.md | 10 ++-------- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 45a14bc109..4c94cc844c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -233,6 +233,8 @@ GEM mutex_m (0.2.0) net-http (0.4.1) uri + nokogiri (1.16.5-aarch64-linux) + racc (~> 1.4) nokogiri (1.16.5-arm64-darwin) racc (~> 1.4) nokogiri (1.16.5-x64-mingw-ucrt) @@ -285,6 +287,7 @@ GEM zeitwerk (2.6.7) PLATFORMS + aarch64-linux arm64-darwin-22 arm64-darwin-23 x64-mingw-ucrt diff --git a/_th/tour/traits.md b/_th/tour/traits.md index ad75e54045..ed89e15801 100644 --- a/_th/tour/traits.md +++ b/_th/tour/traits.md @@ -9,6 +9,8 @@ language: th next-page: tuples previous-page: classes +topics: traits +prerequisite-knowledge: expressions, classes, generics, objects, companion-objects --- Trait ใช้เพื่อแชร์ interface และ field ระหว่างคลาส โดยที่ trait จะคล้ายกับ interface ใน Java 8\ @@ -148,14 +150,6 @@ iterator.next() // returns 1 {% tab 'Scala 2' for=trait-pet-example %} -{% tabs trait-pet-example class=tabs-scala-version %} - -{% tab 'Scala 2' for=trait-pet-example %} - -{% tabs trait-pet-example class=tabs-scala-version %} - -{% tab 'Scala 2' for=trait-pet-example %} - ```scala mdoc import scala.collection.mutable.ArrayBuffer