LL脳がscalaの勉強を始めたよ その39


Scalaコップ本13章の残りをやっていきますよー、今回はアクセス権とかそのへんです

アクセス修飾子

アクセス修飾子ってのはprivateとかprotectedとかそのへんですね、とりあえずザザっと見ていきますかねー

非公開(private)メンバー

privateが付けられたメンバーは、それを含むクラスとかオブジェクトからしか見えませんよー、ってやつです。ちなみにJavaと違ってScalaでは内部クラスも同じルールデス…ってJavaのルールの方が違和感ですな…

文字ばっかりだとイメージがつかないので、ちょっとサンプルを見てみましょうかね

// 外側クラス
class Outer {
  // 内側クラス
  class Inner {
    // 非公開メンバーですよ
    private def f() { println("f") }
    class InnerMost {
      // privateメンバーと同じ所属なのでScalaもJavaもOK
      f()
    }
  }
  // Innerの外からのアクセスなのでScalaではNG
  // でもJavaではOKっぽい
  (new inner).f()
}

Javaは同一クラスに所属していればクラス内クラスのアクセス権は思い切りスルー出来るっぽいなぁ…うん、逆にJavaをやる場合にはまりそうな気がするなぁ…c⌒っ゚д゚)っφ メモメモ...

限定公開(protected)メンバー

privateの次はサブクラスのみアクセス可能なprotectedですよー

ここでもJavaと違って同一パッケージに所属していてもサブクラスでなければアクセス出来ない、というScalaルールが強調されています。うん、Javaもいろいろ歴史があったんだろうなぁ(´・ω・`)

こちらもサンプル見てイメージんぐしてみますよ

// 同一パッケージ内に複数のクラスを突っ込みますよ
package p {
  // とある親クラスです
  class Super {
    protected def f() { println("f") }
  }
  // そしてサブクラスです
  class Sub extend Super {
    // サブクラスなのでprotectedにアクセスできます
    f()
  }
  まったく親子関係のないクラスです
  class Other {
    // Scalaではアクセス出来ません
    // Javaでは同一パッケージ内なのでアクセスできます(´・ω・`)
    (new Super).f()
  }
}

じゃ、Javaって…混乱生まないのか…と思ってしまうのがLL脳

公開メンバー

いわゆるひとつのpublicです。フリーアクセスです。でもScalaでは何も付けないデス。

アクセス保護のスコープ

Scalaでは”限定子”とかいうものを使うことで柔軟なアクセス制御を行うことが出来るみたいです。

限定子は例えばPrivate[X]とかprotected[X]みたいな感じで使いマス。それぞれXまで非公開とか、Xまで限定公開って意味らしいんですが…さっぱりイメージできないのでサンプルやりましょうサンプル

いろいろ限定子をつけたアクセス構造を書いてみますよ

package bobsrockets {
  package navigation {
    // bobsrocketsパッケージまで非公開
    private[bobsrockets] class Navigator {
      // navigationパッケージまで限定公開
      protected[navigation] def useStarChart() {}
      class LegOfJourney {
        // Navigatiorクラスまで非公開
        private[Navigator] val distance = 100
      }
      // オブジェクト非公開
      private[this] var speed = 200
    }
  }
}

それぞれこんな感じのアクセス権になるみたいですねー

  • private[bobsrockets]
    • bobsrocketパッケージ全体はアクセス可能だけど、ソレ以外は非公開デス
    • 上のサンプルだと全て(bobsrockets内)の範囲からアクセス可能です
  • protected[navigation]
    • navigationパッケージとそのサブクラスからはアクセス可能だけども、ソレ以外はダメです
    • 上のサンプルだとnavigationパッケージからのみアクセスできますね
  • private[Navigator]
    • 上の例だと LegOfJourneyがNavigatorクラスの中にあるので、Navigatorクラスのみアクセス可能です
  • private[this]
    • 同じオブジェクトからのみアクセス可能です
    • 上の例だとNavigatorクラスの同一インスタンスからのみアクセス可能です
オブジェクト非公開

オブジェクト非公開は同一インスタンスからのアクセスのみ可能なので、こんな感じのアクセスはコンパイラ様に怒られます

class Navigator {
  private[this] var speed = 200
  def access(){
    // 異なるインスタンスからのアクセスなのでダメです
    val other = new Navigator
    other.speed
  }
} 

でもこれならOKのがっちりガードデス

class Navigator {
  private[this] var speed = 200
  def access(){
    // 同じインスタンスからのアクセスなのでOKです
    this.speed
  }
}
限定子の使える条件

限定子は下のように全く異なるクラスには指定でき無しみたい。あくまでもJava風の外側が同じものは皆仲間!を実現するためのものですかね。

package foo {                                                                                       
  class Huga {
    def huga(){
      val h = new Hoge
      h.hoge
    }
  }
  class Hoge {
    // 異なるクラスに対する限定子を指定しましたよ
    private[Huga] def hoge() { println("hoge") }
  }
}

// Hugaは外側のクラスじゃないからダメよ、なコンパイルエラーでした
bob2.scala:9: error: Huga is not an enclosing class
    private[Huga] def hoge() { println("hoge") }
                      ^
one error found

Java風の同じ傘の下は仲間だぜ!はOKでした

package foo {                                                                                       
  class Huga {
    def huga(){
      val h = new Hoge
      h.hoge
    }
    class Hoge {
      // 外側のクラスをしてするのはOKですよ
      private[Huga] def hoge() { println("hoge") }
    }
  }
}

まあ、飛び道具的にアクセス権を指定してしまうとカオスになるのが目に見えてますカラネ…そりゃそうだわ

可視性とコンパニオンオブジェクト

コンパニオンクラス・コンパニオンオブジェクト同士ではフリーアクセスみたいです。コンパニオンズは一心同体なのですねー

ちらっとサンプル見てみますよー

// コンパニオンクラスです
class Rocket {
  // オブジェクトのモジュール利用ですねー
  // Rocketオブジェクトのprivateメンバーのfuelに楽々アクセスできますねー
  import Rocket.fuel
  private def canGoHomeAgain = fuel  > 20
}
// コンパニオンオブジェクトです
object Rocket {
  private def fuel = 10
  def chooseStrategy(rocket:Rocket) {
    // こちらもRocketクラスのprivateメンバーcanGoHomeAgainにアクセスできます
    if(rocket.canGoHomeAgain)
      println("Go Home!")
    else
      println("Pick A Start!")
  }
}

コンパニオンズは仲良し!という話でした。ちなみにScalaのシングルトンオブジェクトはサブクラスを持たないのでコンパニオンズ間のアクセス性の問題にはprotectedの存在は余り意味がないみたいです…残念(´・ω・`)

いじょうー

モジュール構造やアクセス権を取り扱ってきた13章はコレにて終わりですー、次は単体テスト関連の14章ですなー。だんだん具体的な話になってきたので頑張りますよー(`・ω・´)