iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 16
1
Software Development

認識scala系列 第 16

Scala day 16 (traits self type)

  • 分享至 

  • xImage
  •  

Self types

Self types 使用的符號是 =>
Self types 的作用是把不同的 trait 混合(mixed)在一起,並且定義了要 with 它的話,也必須同時具有它 this 的 trait :

scala> trait Ids {
     |  val id = "ids"
     |  def getId : String
     | }
defined trait Ids

scala> trait Names {
     |  val name = "names"
     |  def getName : String
     | }
defined trait Names

this 只能有一個,所以要多個 Self types 要使用 with :

scala> trait Users {
     |  this : Ids with Names =>
     |  val user = "user"
     |  def getUser : String
     | }
defined trait Users

定義一個 class 去 extends Users,這時候會出錯,因為使用 Self types 的 trait 等於強迫定義了如果要 with 它時,也一定要 with 它所混合的 trait.這邊 Users 的 Self types 有 Ids 與 Names,所以類別 Customer 也要 with Ids 與 Names :

scala> class Customer(id:String,name:String,user:String) extends Users
<console>:12: error: illegal inheritance;
 self-type Customer does not conform to Users's selftype Users with Ids with Names
       class Customer(id:String,name:String,user:String) extends Users

如果 class 的變數名稱如果與 trait 的變數相同會產生衝突,所以要注意(Ids已有id,Names已有name,Users已有user) :

scala> class Customer(id:String,name:String,user:String) extends Users with Ids with Names {
     |  def getId = id
     |  def getName = name
     |  def getUser = user
     | }
<console>:14: error: parameter 'id' requires field but conflicts with value id in trait Ids
       class Customer(id:String,name:String,user:String) extends Users with Ids with Names {
                      ^
<console>:14: error: parameter 'name' requires field but conflicts with value name in trait Names
       class Customer(id:String,name:String,user:String) extends Users with Ids with Names {
                                ^
<console>:14: error: parameter 'user' requires field but conflicts with value user in trait Users
       class Customer(id:String,name:String,user:String) extends Users with Ids with Names {
                                            ^

把變數名稱改掉 :

scala> class Customer(cid:String,cname:String,cuser:String) extends Users with Ids with Names {
     |  def getId = cid
     |  def getName = cname
     |  def getUser = cuser
     | }
defined class Customer

scala> val cu = new Customer("1","Daniel","user1")
cu: Customer = Customer@3a62fa79

scala> cu.getId
res4: String = 1

scala> cu.id
res7: String = ids

Self types 定義 function

Self types 也可以定義 with 它的類別一定也要具有 Self types 定義好的方法 :

scala> trait Counter {
     |  this : {
     |   def count(mum1:Int,num2:Int): Unit
     |   def getSum: Int
     |  } =>
     | }
defined trait Counter

scala> trait MyCounter {
     |  this : Counter =>
     | }
defined trait MyCounter

沒實作方法的話,就會出錯 :

scala> class RealCounter extends MyCounter with Counter
<console>:13: error: illegal inheritance;
 self-type RealCounter does not conform to Counter's selftype Counter with AnyRef{def count(mum1: Int,num2: Int): Unit; def getSum: Int}
       class RealCounter extends MyCounter with Counter
                                                ^

再來做個實驗,如果是 abstract class,沒定義的話還是會出錯,但可以不用在 abstract class 實作出方法,可以先定義成抽象方法,就可以過了 :

scala> abstract class RealCounter extends MyCounter with Counter
<console>:13: error: illegal inheritance;
 self-type RealCounter does not conform to Counter's selftype Counter with AnyRef{def count(mum1: Int,num2: Int): Unit; def getSum: Int}
       abstract class RealCounter extends MyCounter with Counter
                                                         ^

scala> abstract class RealCounter extends MyCounter with Counter {
     |  def count(num1:Int,num2:Int): Unit
     |  def getSum: Int
     | }
defined class RealCounter

最後還是乖乖實作方法吧 :

scala> class RealCounter extends MyCounter with Counter {
     |  var sum = 0
     |  def count(num1:Int , num2:Int):Unit = sum = num1 + num2
     |  def getSum = sum
     | }
defined class RealCounter

scala> val counter = new RealCounter
counter: RealCounter = RealCounter@5e585461

scala> counter.count(2,3)

scala> counter.getSum
res9: Int = 5

總結


  • trait 本身其實已經是在定義方法及型態了,所以 Self types 概念上好像差不多.差異是不用寫很多 extends 和 with 定義在 this 裡就好.雖然現在還沒了解它的好處,不過可以先玩玩看.

上一篇
Scala day 15 (traits & abstract class)
下一篇
Scala day 17 (Option type)
系列文
認識scala30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言