在线观看不卡亚洲电影_亚洲妓女99综合网_91青青青亚洲娱乐在线观看_日韩无码高清综合久久

鍍金池/ 教程/ Scala/  初始化抽象 vals
 初始化抽象 vals
延遲初始化(Lazy vals)
Type 成員
抽象類型
預(yù)先初始化成員的值

 初始化抽象 vals

抽象定義的 vals 在某些時候起到父類參數(shù)的角色,它們允許你在子類中提供最父類中省略的定義,這對于 Trait 來說尤其重要,因為 Trait 沒有提供你可以傳入?yún)?shù)的構(gòu)造函數(shù)。因此為 Trait 提供參數(shù)支持通常是通過抽象 vals 來實現(xiàn)的。
例如我們之前例子中使用過的有理數(shù)類型,使用 Trait 方式定義如下:


trait RationalTrait{
    val numerArg:Int
    val denomArg:Int
}

我們之前使用的 Rational 類定義定義了兩個參數(shù) n,d 代表分子和分母。 這里我們使用 RationalTrait 定義了兩個抽象 vals 值, 為了構(gòu)造這個 Trait 的一個實例,你需要提供這些抽象成員的實現(xiàn),這里可以使用匿名類實例的方法構(gòu)造一個實例:


scala> val r= new RationalTrait {
     | val numerArg = 1
     | val denomArg = 2
     | }
r: RationalTrait = $anon$1@341f55dd

這種構(gòu)造 RationalTrait 實例在形式上和之前的 new Rational(1,2) 有點想像,但還是有些細(xì)節(jié)上的差別-在表達(dá)式初始化的順序上的差異: 當(dāng)你使用如下代碼:


new Rational(expr1,expr2)

其中的兩個表達(dá)式 expr1,expr2 在初始化類 Rational 之前就計算好了,因此在初始化 Rational 時,這些表達(dá)式是可以用的。而對于 Trait 來說,情況卻相反:


new RationalTrait{
    val numerArg = expr1
    val denomArg = expr2
}

計算表達(dá)式 expr1,expr2 是和處理化匿名類實例的過程中進(jìn)行的,而匿名類處理化是在 RationalTrait 之后進(jìn)行的,因此在初始化 RationalTrait 時,這兩個值是不可用的(或者是這兩個值是缺省值0),這對于 RationalTrait 定義來說,不是個什么問題,因為 RationalTrait 的初始化沒有使用到 numerArg 和 denomArg , 但對于下面的 RationalTrait 定義就存在問題了:


trait RationalTrait{
    val numerArg :Int
    val denomArg :Int

    require(denomArg !=0)
    private val g = gcd(numerArg,denomArg)

    val numer = numerArg/g
    val denom = denomArg/g

    private def gcd(a:Int,b:Int):Int =
        if(b==0) a else gcd(b, a % b)

    override def toString = numer + "/" + denom
}

如果此時,你使用某些表達(dá)式來構(gòu)造這 個Trait 的實例,就會出問題了:


scala> new RationalTrait {
     | val numerArg = x 
     | val denomArg  = 2 * x
     | }
java.lang.IllegalArgumentException: requirement failed
  at scala.Predef$.require(Predef.scala:207)
  at RationalTrait$class.$init$(<console>:11)
  ... 39 elided

scala> new RationalTrait {
     | val numerArg = 1
     | val denomArg  = 2
     | }
java.lang.IllegalArgumentException: requirement failed
  at scala.Predef$.require(Predef.scala:207)
  at RationalTrait$class.$init$(<console>:11)
  ... 39 elided

這是因為在執(zhí)行 RationalTrait 的初始化代碼時 denomArg 的值還是0,就拋出異常了。 由此你可以知道抽象 Val 值和類參數(shù)之間的不同,對于使用 Trait 的這個問題,Scala 提供了兩個解決方案:預(yù)先初始化的域和 lazy vals。我們在下篇中介紹他們。