Scala案例类私有构造函数但公共应用方法
Posted
技术标签:
【中文标题】Scala案例类私有构造函数但公共应用方法【英文标题】:Scala case class private constructor but public apply method 【发布时间】:2020-05-16 23:11:00 【问题描述】:如果我有以下带有私有构造函数的案例类,并且我无法访问伴随对象中的应用方法。
case class Meter private (m: Int)
val m = Meter(10) // constructor Meter in class Meter cannot be accessed...
有没有办法使用带有私有构造函数的案例类,但将生成的应用方法保留在伴随的公共中?
我知道这两个选项之间没有区别(在我的示例中):
val m1 = new Meter(10)
val m2 = Meter(10)
但我想禁止第一个选项。
-- 编辑--
令人惊讶的是以下作品(但不是我真正想要的):
val x = Meter
val m3 = x(10) // m3 : Meter = Meter(10)
【问题讨论】:
您使用的是哪个版本的 Scala?我刚刚在我的 2.10.0 REPL 中尝试过,val m2 = Meter(10)
没有给出任何错误]
@LuigiPlinge 我正在使用 Scala 2.10.3
似乎是 case class Meter private (m: Int)
行导致错误,当声明为***对象 (scalafiddle.net/console/eb6fdc36b281b7d5eabf33396c2683a2) 但在另一个对象或 REPL (scalafiddle.net/console/cdc0d6e63aa8e41c89689f54970bb35f) 中声明时它可以工作跨度>
【参考方案1】:
这是拥有 private 构造函数和 public apply 方法的技术。
trait Meter
def m: Int
object Meter
def apply(m: Int): Meter = MeterImpl(m)
private case class MeterImpl(m: Int) extends Meter println(m)
object Application extends App
val m1 = new Meter(10) // Forbidden
val m2 = Meter(10)
背景资料private-and-protected-constructor-in-scala
【讨论】:
@senia,不,它没有。这是 new Meter(10) 的编译错误;特质仪表是一个特质;不接受构造函数参数 我错过了。您应该将Meter
定义为trait Meter def m: Int
以允许访问m
。你也可以sealed
。
我认为这是一个很好的解决方法,因为您可以从案例类中获得所要求的行为和一些好处(例如,实现 equals)。但与单例类相比,它有点重。
在这种情况下println(Meter(1))
不会导致> MeterImpl(1)
?并不是说这不能回答问题,但我想要一个不会发生这种情况的解决方案。【参考方案2】:
似乎请求的行为(私有构造函数,但公共 .apply
)可能是 Scala 2.12 实现这些的方式。
我是从相反的角度得出的——希望私有案例类构造函数也阻止.apply
方法。原因在这里:https://github.com/akauppi/case-class-gym
有趣的是,用例有何不同。
【讨论】:
【参考方案3】:有一些隐含的技巧是可能的:
// first case
case class Meter[T] private (m: T)(implicit ev: T =:= Int)
object Meter
def apply(m: Int) = new Meter(m + 5)
创建了另一个构造函数(并应用方法签名),但保证该参数只能是Int
。
在您拥有具有案例类功能的案例类(具有模式匹配、哈希码和等于)之后,排除默认构造函数:
scala> val m = Meter(10)
m: Metter[Int] = Meter(15)
scala> val m = new Meter(10)
<console>:9: error: constructor Meter in class Meter cannot be accessed in object $iw
val m = new Meter(10)
或带有类型标记(朴素实现):
trait Private
case class Meter private (m: Integer with Private)
object Meter
def apply(m: Int) = new Meter((m + 5).asInstanceOf[Integer with Private])
它按预期工作:
val x = new Meter(10)
<console>:11: error: constructor Meter in class Meter cannot be accessed in object $iw
new Meter(10)
^
val x = Meter(10)
x: Meter = Meter(15)
here 描述的基本类型和类型标签的一些可能问题
【讨论】:
以上是关于Scala案例类私有构造函数但公共应用方法的主要内容,如果未能解决你的问题,请参考以下文章