Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/16.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
模块化Scala设计:如何避免构造函数;推出;样板?_Scala_Boilerplate - Fatal编程技术网

模块化Scala设计:如何避免构造函数;推出;样板?

模块化Scala设计:如何避免构造函数;推出;样板?,scala,boilerplate,Scala,Boilerplate,也许一位对风格和优雅有着良好感觉的Scala专家可以帮助我找到一种更好的方法来构造下面的代码,它有一个构造函数“push out”问题 我们从一个简单的基类开始: class Foo(val i: Int, val d: Double, val s: String) { def add(f: Foo) = new Foo(i + f.i, d + f.d, s + f.s) override def toString = "Foo(%d,%f,%s)".format(i,d,s) }

也许一位对风格和优雅有着良好感觉的Scala专家可以帮助我找到一种更好的方法来构造下面的代码,它有一个构造函数“push out”问题

我们从一个简单的基类开始:

class Foo(val i: Int, val d: Double, val s: String) {

  def add(f: Foo) = new Foo(i + f.i, d + f.d, s + f.s)
  override def toString = "Foo(%d,%f,%s)".format(i,d,s)

}
为了在复杂应用程序中进行类型检查,我需要一个不带任何附加状态的子类:

class Bar(i: Int, d: Double, s: String) extends Foo(i,d,s) {

  override def toString = "Bar(%d,%f,%s)".format(i,d,s)

}
目前,当我添加两个条时,我只得到一个Foo:

val x = new Bar(1,2.3,"x")
val y = new Bar(4,5.6,"y")
val xy = x.add(y)
回复中有以下回复:

x  : Bar = Bar(1,2.300000,x)
y  : Bar = Bar(4,5.600000,y)
xy : Foo = Foo(5,7.900000,xy)
如何让两个条以优雅的方式添加在一起形成另一个条(而不是一个Foo),而不必复制和粘贴Foo的add方法,如下所示

class Bar(i: Int, d: Double, s: String) extends Foo(i,d,s) {

  // ugly copy-and-paste from Foo:
  def add(b: Bar) = new Bar(i + b.i, d + b.d, s + b.s)
  override def toString = "Bar(%d,%f,%s)".format(i,d,s)

}
我有很多这样的条(基本上都是Foo的副本,但对于类型检查非常重要),一个无剪切粘贴的解决方案将带来好处


谢谢

我尽量避免继承。所以这里有另一种方法

Bar
Foo
具有完全相同的构造函数,并且两者都是无状态的。如果您想要有几个子类型,只是为了传递任何附加信息,可以使用泛型参数作为“标签”。例如:

trait Kind
trait Bar extends Kind

class Foo[T<:Kind](val i: Int, val d: Double, val s: String) {
   def add(f: Foo[T]) = new Foo[T](i + f.i, d + f.d, s + f.s)
   override def toString = "Foo(%d,%f,%s)".format(i,d,s)
}


scala> val b1 = new Foo[Bar](2,3.0,"hello")
b1: Foo[Bar] = Foo(2,3.000000,hello)

scala> val b2 = new Foo[Bar](3,1.0," world")
b2: Foo[Bar] = Foo(3,1.000000, world)

scala> b1 add b2
res1: Foo[Bar] = Foo(5,4.000000,hello world)
特征类型
特性条扩展了种类
类Foo[T val b1=新Foo[Bar](2,3.0,“你好”)
b1:Foo[Bar]=Foo(2,3.000000,你好)
scala>val b2=new Foo[Bar](3,1.0,“世界”)
b2:Foo[Bar]=Foo(3,1.000000,世界)
scala>b1添加b2
res1:Foo[Bar]=Foo(5,4.000000,你好世界)

现在,
add
是类型安全的。如果您希望能够支持特定于每个
条的操作(例如,不同的
toString
),那么您可以使用类型类来获取
toString
,以显示
种类
,扩展@paradigmatic的答案,您可以更进一步,使
Kind
成为一个类型类

trait Kind[T] { def name : String }
trait Bar
implicit object BarHasKind extends Kind[Bar] { val name = "Bar" }

class Foo[T : Kind](val i : Int, val d : Double, val s : String) {
  def add(f : Foo[T]) = new Foo[T](i + f.i, d + f.d, s + f.s)
  override def toString = implicitly[Kind[T]].name + "(%d,%f,%s)".format(i,d,s)
}

scala> val b1 = new Foo[Bar](2, 3.0, "hello")
b1: Foo[Bar] = Bar(2,3.000000,hello)

trait Biz
implicit object BizHasKind extends Kind[Biz] { val name = "Biz" }

scala> val b2 = new Foo[Biz](1, 1.0, "One")
它与以前一样是类型安全的:

scala> b1 add b2
<console>:16: error: type mismatch;
  found   : Foo[Biz]
  required: Foo[Bar]

scala> b2 add b2
resN: Foo[Biz] = Biz(2,2.000000,OneOne)
scala>b1添加b2
:16:错误:类型不匹配;
发现:Foo[Biz]
必填项:Foo[Bar]
scala>b2添加b2
resN:Foo[Biz]=Biz(2,2.000000,OneOne)

对于您希望依赖于标记的任何属性,请在
类中抽象地声明它们,并在隐式对象中提供实现。

使用类型参数化的方法有一个限制,即它不允许您以继承的自然方式扩展功能ld是一个可重写的工厂方法(它只是构造函数的委托):

类Foo(val i:Int,val d:Double,val s:String){ 受保护的def create(i:Int,d:Double,s:String)=新的Foo(i,d,s)
def add[A为了类型安全,我喜欢“参数作为标签”的想法。谢谢!很有趣。与声明'def name=“Foo'相比,您的“隐式”方法有什么优势方法,并让Bar和Biz覆盖它?这并不是一个真正的优势,我只是想表明,即使在没有继承的环境中,您也可以完全实现这一点,类似于公认答案中提出的设置。
class Foo(val i: Int, val d: Double, val s: String) {

  protected def create(i: Int, d: Double, s: String) = new Foo(i, d, s)

  def add[A <: Foo](f: A) = create(i + f.i, d + f.d, s + f.s)

  override def toString = "Foo(%d,%f,%s)".format(i,d,s)
}

class Bar(i: Int, d: Double, s: String) extends Foo(i,d,s) {

  protected override def create(i: Int, d: Double, s: String) = new Bar(i, d, s)

  override def toString = "Bar(%d,%f,%s)".format(i,d,s)

  // additional methods...

}

println( new Foo(10, 10.0, "10") add new Bar(10, 10.0, "10") )
println( new Bar(10, 10.0, "10") add new Foo(10, 10.0, "10") )