You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何可从其他包通过伴生对象访问Scala包作用域类?

Scala包级私有访问规则疑问解答

问题场景

Quark.scala(包a)

package a

object Quark {
    def apply(): Quark = new Quark()
}

private[a] class Quark {
    def foo(): String = "bar"
}

可运行的Main.scala(包b)

package b

object Main {
    def main(args: Array[String]): Unit = {
        val quark = Quark()
        println(quark.foo()) // 编译通过,可正常执行
    }
}

编译报错的Main.scala(包b)

package b

object Main {
    def main(args: Array[String]): Unit = {
        val quark = new Quark() // 编译报错!
        println(quark.foo())
    }
}

规则解析

你困惑的核心是没分清private[a]的作用范围边界:

  • private[a] class Quark 限制的是类的构造权限和类本身的直接可见性:只有包a内部的代码能直接执行new Quark(),也只有包a内可以直接引用Quark类型。
  • 但Quark类的foo()方法是默认公共权限(Scala中无修饰符的成员为public),只要能合法拿到Quark的实例,不管实例来自哪个包,都能调用它的公共成员方法。

第一个Main代码能运行,是因为Quark()调用的是包a内伴生对象的apply()方法——这个方法属于包a范畴,有权限创建Quark实例,之后把实例返回给包b的代码。包b拿到实例后,调用公共的foo()完全符合规则。

第二个Main代码直接执行new Quark(),是在包b里尝试调用Quark的构造方法,违反了private[a]的构造权限限制,因此编译器报错。

关键规则总结

  • private[X]属于限定私有,X可以是包、类或对象:
    • 修饰类时,仅约束类的构造器访问和类的直接引用权限,不影响类的非私有成员的访问
    • 修饰成员方法/字段时,才会限制该成员的访问范围
  • 类的成员默认是公共的,只要持有类的实例,就能调用这些成员。

官方规则依据

Scala语言规范中对限定私有(Qualified Private)的定义:

标记为private[C]的元素,仅能在C的定义范围内被访问。对于类的限定私有修饰,它约束的是类的构造和直接可见性,但类的非私有成员不受此约束——只要持有类的实例,就能调用这些成员。

内容的提问来源于stack exchange,提问作者kylemart

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 13:05:08