简体   繁体   English

智能构造函数的Scala案例类实现?

[英]Scala case class implementation of smart constructors?

Trying to implement smart constructor using case classes. 尝试使用案例类实现智能构造函数。 Managed to override the copy method fine, and I presume the apply in the companion object should have done the trick, but I hit a wall when trying to pass in a BigInt . 设法很好地重写了copy方法,并且我认为在伴随对象中的apply应该已经完成​​了技巧,但是在尝试传递BigInt时遇到了BigInt I tried putting in def apply(value: BigInt): Option[Natural] but then scalac complains about conflicting symbols. 我尝试放入def apply(value: BigInt): Option[Natural]但随后scalac抱怨符号冲突。

import spire.math.Integral // companion object contains implicit Integral[BigInt]

case class Natural private (value: BigInt) {
  def copy(value: BigInt = this.value): Option[Natural] =
    Natural.apply(value)
}

object Natural {
  def apply[A](x: A)(implicit A: Integral[A]): Option[Natural] =
    if (A.isPositive(x)) Some(Natural(x))
    else None
}

/** In Foo.scala */
Natural(5L) // Option[Natural] = Some(Natural(5))
Natural(BigInt(5L)) // constructor Natural in class Natural cannot be accessed in object Foo

Perhaps such a thing is not possible? 也许这样的事情是不可能的?

Overloading is your problem here, as @jroesch points out in his answer. @jroesch在他的回答中指出,这里的重载是您的问题。

A solution to this problem is to change the type of the argument of the private primary constructor so that the latter cannot conflict with the public factory method. 解决此问题的方法是更改​​私有主构造函数的参数类型,以使后者不会与public factory方法冲突。 There are various ways of doing that in Scala ... one might go like this, 在Scala中,可以通过多种方式实现这一目标……

case class Wrap[T](t: T) extends AnyVal

case class Natural private (value: Wrap[BigInt]) {
  def copy(value: Wrap[BigInt] = this.value): Option[Natural] =
    Natural(value.unwrap)
}

object Natural {
  def apply[A](x: A)(implicit A: Integral[A]): Option[Natural] =
    if (A.isPositive(x)) Some(Natural(Wrap(x)))
    else None
}

I believe that the error you are encountering is because of method overloading. 我相信您遇到的错误是由于方法重载。 When creating a case class the compiler will generate a signature of: 创建案例类时,编译器将生成以下特征的签名:

def apply(x: T): T 

for a case class T in it's companion object T. So when you are invoking the method, method selection picks the most specific signature first. 因此,在调用方法时,方法选择将首先选择最具体的签名。 It attempts to invoke Natural.apply(x: T): T which I would hazard is also marked private transitively in the companion object. 它会尝试调用Natural.apply(x: T): T可能会危害的Natural.apply(x: T): T在同伴对象中也被标记为private。 The conflicting symbols then becomes an issue, because it generates an apply(x: T): T , and you are also defining an apply(x: T): T . 然后,冲突的符号成为问题,因为它生成了apply(x: T): T ,并且您还定义了apply(x: T): T

Your best bet is using a plain Scala class, and manually implementing the extractor pattern, hash, equality, ect. 最好的选择是使用普通的Scala类,并手动实现提取器模式,哈希,相等等。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM