1. 序章

Scalaにはアクセス修飾子のシステムがあります。 このチュートリアルでは、これらのアクセス修飾子を見て、それらのスコープ(パッケージ、クラス、およびオブジェクト)について説明します。

2. クラスとオブジェクトのスコープ

クラスメンバーがパブリックの場合、定義にアクセス修飾子は必要ありません。実際、Scalaにはパブリックキーワードがありません。 これは、修飾子を指定しない場合のデフォルトのアクセスであり、Javaパブリックアクセスと同等です。

ただし、 private フィールドには、次のようにラベルを付ける必要があります。

class Rectangle(widthParam: Int, heightParam: Int, colorParam: String) {
    val width: Int = widthParam
    val height: Int = heightParam
    val color: String = colorParam
    private val numberOfVertexes: Int = 4
    //...
}

この例では、プライベートメンバーnumberOfVertexesは、クラス内でのみアクセスできます。

Scalaでは、private [this] 修飾子を使用して、オブジェクトスコープ外でメンバーがアクセスされないように保護することもできます。

abstract class Figure {
    //...
    private[this] val code = randomUUID.toString
    def printCode: Unit = println(s"$code")
    def compareCodes(that: Figure) = {
        this.code == that.code //that.code is not accessible
    }
}

修飾子private[this] は最も厳密な修飾子であり、その結果、フィールドにはクラスのインスタンスからのみアクセスできます。

3. パッケージスコープ

3.1. 保護された修飾子

保護とマークされたメンバーは、基本クラスとそのサブクラスでのみアクセスできます。 抽象クラスFigureのmembercolorの修飾子をprotectedに変更してみましょう。

abstract class Figure {
    //...
    protected val color: String
}

フィールドcolorは、基本クラスとそのサブクラスのスコープ外ではアクセスできなくなりました。 基本クラスとサブクラスの外部のどこかでcolorフィールドにアクセスしようとすると、コンパイル時エラーが発生します。

3.2. 保護された[パッケージ名]修飾子

パッケージ自体およびネストされたパッケージの参照によってメンバーにアクセスできるようにすることもできます。 この場合、抽象でcolorのアクセス修飾子をprotected[accessmodifiers] accessmodifiers はパッケージ名)に変更する必要がありますクラスFigure

abstract class Figure {
    //...
    protected[accessmodifiers] val color: String
}
class Composition(fig1: Figure, fig2: Figure) {
    val color = mixColors(fig1.color, fig2.color)
    //...
}

3.3. 保護された[これ]修飾子

protected [this]修飾子で定義されたメンバーは、それらが定義されているインスタンスとサブクラスのインスタンスでのみアクセスできます。

abstract class Figure {
    //...
    protected[this] val lineWidth: Int
}

メンバーlineWidthは、クラスインスタンスとサブクラスインスタンスでのみアクセスできます。 他の場合はアクセスできません。

4. ネストされたクラスのスコープ

ネストされたクラスの場合、アクセスルールはJavaのルールとは少し異なります。

class Rectangle があり、これにはプライベート Boolean フィールド、 isSquare 、およびInternalFigureというネストされたクラスが含まれているとします。

class Rectangle(widthParam: Int, heightParam: Int, colorParam: String) extends Figure {
    //...
    private val isSquare = width == height
    class InnerFigure(fig: Figure) {
        private val codeInner = randomUUID.toString
        val isInsideSquare = isSquare
        def printCodeInner = print(codeInner)
    }
}

この場合、isSquareは内部クラスからアクセスできます。 ただし、privateフィールドcodeInnerは、外部クラスからアクセスできません(Javaではそうではないことに注意してください)。

5. コンパニオンオブジェクトアクセス

クラスStar(頂点座標で定義)にコンパニオンオブジェクトがあるとします。 この場合、コンパニオンオブジェクトのすべてのメンバーは、プライベートであるかどうかに関係なく、インポートによってコンパニオンクラス内でアクセスでき、コンパニオンクラスのメンバーはいずれもコンパニオンオブジェクトでアクセスできません。

class Star(val vertexes: Map[Int, (Double, Double)], val color: String) extends Figure {
    import Star._
    override val lineWidth: Int = 1
    //...    
    val x = vertexes.values.toList.map(_._1)
    override protected val rightMostPoint = x.max
    val area = areaByVertexes(vertexes)
}

object Star {
    def apply(vertexes: Map[Int, (Double, Double)], color: String) =
      new Star(vertexes, color)
    private def areaByVertexes(vertexes: Map[Int, (Double, Double)]): Double = ??? // implemented somehow
    val right = rightMostPoint // Cannot resolve symbol rightMostPoint
}

コンパニオンクラスのimportStar ._ は、コンパニオンクラスのコンパニオンオブジェクトのメンバーへのアクセスのみを提供することに注意してください。

6. 結論

この記事では、Scalaのさまざまなアクセス修飾子を調べました。 さらに、それらがパッケージ、クラス、およびオブジェクトのスコープにどのように関連しているかについても見てきました。

いつものように、これらの例はGitHubから入手できます。