@@ -11,27 +11,59 @@ next-page: tuples
11
11
previous-page : classes
12
12
---
13
13
14
- Trait ใช้เพื่อแชร์ interface และ field ระหว่างคลาส มันจะเหมือนกับ interface ใน Java 8
15
- คลาส และ object สามารถขยาย trait ได้แต่ trait ไม่สามารถ instant เป็น object และไม่สามารถมี parameter ได้
14
+ Trait ใช้เพื่อแชร์ interface และ field ระหว่างคลาส โดยที่ trait จะคล้ายกับ interface ใน Java 8\
15
+ คลาส และ object สามารถ extend trait ได้ แต่เราไม่สามารถสร้าง object จาก trait ได้\
16
+ ดังนั้น trait จึงไม่สามารถมี parameter เช่นเดียวกับที่คลาสมี
17
+
18
+ ## การกำหนด Trait
16
19
17
- ## การกำหนด trait
18
20
วิธีที่ง่ายที่สุดในการกำหนด trait คือการประกาศด้วย keyword ` trait ` และ indentifier:
19
21
22
+ {% tabs trait-hair-color %} {% tab 'Scala 2 and 3' for=trait-hair-color %}
23
+
20
24
``` scala mdoc
21
25
trait HairColor
22
26
```
27
+
28
+ {% endtab %} {% endtabs %}
29
+
23
30
trait จะมีประโยชน์อย่างยิ่งด้วยการเป็น generic type และเป็น abstract method
31
+
32
+ {% tabs trait-iterator-definition class=tabs-scala-version %}
33
+
34
+ {% tab 'Scala 2' for=trait-iterator-definition %}
35
+
24
36
``` scala mdoc
25
37
trait Iterator [A ] {
26
38
def hasNext : Boolean
27
39
def next (): A
28
40
}
29
41
```
30
42
31
- การขยาย ` trait Iterator[A] ` ต้องการ type ` A ` และ implementation ของ method ` hasNext ` และ ` next `
43
+ {% endtab %}
44
+
45
+ {% tab 'Scala 3' for=trait-iterator-definition %}
46
+
47
+ ``` scala
48
+ trait Iterator [A ]:
49
+ def hasNext : Boolean
50
+ def next (): A
51
+ ```
52
+
53
+ {% endtab %}
54
+
55
+ {% endtabs %}
56
+
57
+ การขยาย (extend) ` trait Iterator[A] ` ต้องการ type ` A ` และ implementation ของ method ` hasNext ` และ ` next `
58
+
59
+ ## การใช้ Trait
60
+
61
+ ใช้ keyword ` extends ` เพื่อขยาย trait จากนั้นให้ implement abstract member ใดๆ ของ trait โดยใช้ keyword ` override ` :
62
+
63
+ {% tabs trait-intiterator-definition class=tabs-scala-version %}
64
+
65
+ {% tab 'Scala 2' for=trait-intiterator-definition %}
32
66
33
- ## การใช้ traits
34
- ใช้ keyword ` extends ` เพื่อขยาย trait ดังนั้นจะ implement abstract member ใดๆ ของ trait โดยใช้ keyword ` override ` :
35
67
``` scala mdoc:nest
36
68
trait Iterator [A ] {
37
69
def hasNext : Boolean
@@ -55,10 +87,75 @@ val iterator = new IntIterator(10)
55
87
iterator.next() // returns 0
56
88
iterator.next() // returns 1
57
89
```
58
- คลาส ` IntIterator ` นี้รับค่า parameter ` to ` เป็น upper bound มัน ` extends Iterator[Int] ` ซึ่งหมายความว่า method ` next ` จะต้อง return เป็น Int
59
90
60
- ## Subtyping
61
- ในเมื่อ trait ที่ให้มานั้น required, subtype ของ trait สามารถถูกใช้แทนที่ได้
91
+ {% endtab %}
92
+
93
+ {% tab 'Scala 3' for=trait-intiterator-definition %}
94
+
95
+ ``` scala
96
+ trait Iterator [A ]:
97
+ def hasNext : Boolean
98
+ def next (): A
99
+
100
+ class IntIterator (to : Int ) extends Iterator [Int ]:
101
+ private var current = 0
102
+ override def hasNext : Boolean = current < to
103
+ override def next (): Int =
104
+ if hasNext then
105
+ val t = current
106
+ current += 1
107
+ t
108
+ else
109
+ 0
110
+ end IntIterator
111
+
112
+ val iterator = new IntIterator (10 )
113
+ iterator.next() // returns 0
114
+ iterator.next() // returns 1
115
+ ```
116
+
117
+ {% endtab %}
118
+
119
+ {% endtabs %}
120
+
121
+ คลาส ` IntIterator ` นี้รับค่า parameter ` to ` เพื่อกำหนดค่าสูงสุด (upper bound) โดยที่คลาส ` IntIterator ` ได้ extend จาก ` Iterator[Int] ` \
122
+ ดังนั้น method ` next ` จะต้อง return ค่าเป็น Int
123
+
124
+ ## การใช้ Subtype
125
+
126
+ เมื่อจำเป็นต้องใช้ trait ใดๆ เราสามารถใช้ subtype (คลาสใดก็ตาม ที่ extend มาจาก trait นั้นๆ) แทนได้
127
+
128
+ > *** Note by Thai translator:*** \
129
+ > "เมื่อจำเป็นต้องใช้ trait ใดๆ" ในที่นี้ น่าจะหมายถึงเรามีการระบุไว้ว่า parameter ที่ได้ระบุ type เป็น trait\
130
+ > ดังนั้นเราสามารถใช้ ** subtype ใดๆ ที่ implement จาก trait นั้นๆ ได้**
131
+ >
132
+ > ** ลองพิจารณา code นี้:**
133
+ >
134
+ > ``` scala
135
+ > val dog = new Dog (" Harry" ) // คลาส `Dog` เป็น subtype ของ trait `Pet`
136
+ >
137
+ > // parameter `pet` มี type เป็น trait `Pet`
138
+ > def getPetName (pet : Pet ): String = pet.name
139
+ >
140
+ > getPetName(dog)
141
+ > ```
142
+ >
143
+ > ถ้าอิงจากตัวอย่างจาก code block ด้านล่าง เราจะเห็นได้ว่า code ด้านบน\
144
+ > เราส่งตัวแปร `dog` ซึ่งเป็น instance ของคลาส `Dog` ไปให้ function `getPetName`\
145
+ > โดยที่คลาส `Dog` ก็เป็น subtype ของ trait `Pet` อีกทีหนึ่ง
146
+
147
+ {% tabs trait - pet- example class = tabs- scala- version % }
148
+
149
+ {% tab ' Scala 2 ' for=trait-pet-example %}
150
+
151
+ {% tabs trait - pet- example class = tabs- scala- version % }
152
+
153
+ {% tab ' Scala 2 ' for=trait-pet-example %}
154
+
155
+ {% tabs trait - pet- example class = tabs- scala- version % }
156
+
157
+ {% tab ' Scala 2 ' for=trait-pet-example %}
158
+
62
159
```scala mdoc
63
160
import scala .collection .mutable .ArrayBuffer
64
161
@@ -76,6 +173,34 @@ val animals = ArrayBuffer.empty[Pet]
76
173
animals.append(dog)
77
174
animals.append(cat)
78
175
animals.foreach(pet => println(pet.name)) // แสดงค่า Harry Sally
176
+
79
177
```
80
- ` trait Pet ` มี abstract field ` name ` ซึ่ง implement โดย Cat และ Dog ใน constructor ของมัน
81
- ในบรรทัดสุดท้าย เราเรียก ` pet.name ` ซึ่งจะต้องถูก implement แล้วใน subtype ใดๆ ของ trait ` Pet `
178
+
179
+ {% endtab % }
180
+
181
+ {% tab ' Scala 3 ' for=trait-pet-example %}
182
+
183
+ ```scala
184
+ import scala .collection .mutable .ArrayBuffer
185
+
186
+ trait Pet :
187
+ val name : String
188
+
189
+ class Cat (val name : String ) extends Pet
190
+ class Dog (val name : String ) extends Pet
191
+
192
+ val dog = Dog (" Harry" )
193
+ val cat = Cat (" Sally" )
194
+
195
+ val animals = ArrayBuffer .empty[Pet ]
196
+ animals.append(dog)
197
+ animals.append(cat)
198
+ animals.foreach(pet => println(pet.name)) // แสดงค่า Harry Sally
199
+ ```
200
+
201
+ {% endtab % }
202
+
203
+ {% endtabs % }
204
+
205
+ `trait Pet` มี abstract field `name` ซึ่ง implement ไว้ใน constructor ของคลาส `Cat` และ `Dog`\
206
+ ในบรรทัดสุดท้าย เราเรียกใช้ `pet.name` ซึ่งได้มีการ implement `name` ไว้ใน subtype ใดๆ ของ trait `Pet` แล้ว
0 commit comments