scala 案例类 copy() 方法抽象

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2911562/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-22 02:11:04  来源:igfitidea点击:

Case class copy() method abstraction

scalacopy

提问by Joa Ebert

I would like to know if it is possible to abstract the copy method of case classes. Basically I have something like sealed trait Opand then something like case class Push(value: Int) extends Opand case class Pop() extends Op.

我想知道是否可以抽象案例类的复制方法。基本上我有类似的东西sealed trait Op,然后有类似的东西case class Push(value: Int) extends Opcase class Pop() extends Op

The first problem: A case class without arguments/members does not define a copy method. You can try this in the REPL.

第一个问题:没有参数/成员的案例类没有定义复制方法。您可以在 REPL 中尝试此操作。

scala> case class Foo()
defined class Foo

scala> Foo().copy()
<console>:8: error: value copy is not a member of Foo
       Foo().copy()
             ^

scala> case class Foo(x: Int)
defined class Foo

scala> Foo(0).copy()
res1: Foo = Foo(0)

Is there a reason why the compiler makes this exception? I think it is rather unituitive and I would expect everycase class to define a copy method.

编译器是否有原因导致此异常?我认为它相当统一,我希望每个案例类都定义一个复制方法。

The second problem: I have a method def ops: List[Op]and I would like to copy all ops like ops map { _.copy() }. How would I define the copy method in the Optrait? I get a "too many arguments" error if I say def copy(): Op. However, since all copy() methods have only optional arguments: why is this incorrect? And, how do I do that correct? By making another method named def clone(): Opand write everywhere def clone() = copy()for all the case classes? I hope not.

第二个问题:我有一个方法def ops: List[Op],我想复制所有像ops map { _.copy() }. 我将如何定义特征中的复制方法Op?如果我说def copy(): Op. 但是,由于所有 copy() 方法都只有可选参数:为什么这是不正确的?而且,我该怎么做才能正确?通过为所有案例类创建另一种命名def clone(): Op和写入方法def clone() = copy()?我希望不是。

采纳答案by Mirko Stocker

  1. What would be the benefit of a compiler generated copy method for case classes without any arguments? This would just return a new Foo, and not copy anything.
  2. To quote Lukas Rytz(I believe he implemented it):
  1. 编译器为没有任何参数的 case 类生成复制方法有什么好处?这只会返回一个新的 Foo,而不是复制任何东西。
  2. 引用卢卡斯Rytz(我相信他实现了它):
The copy methods are only generated if there is no member named"copy" in the class, directly defined or inherited.
仅当类中没有直接定义或继承的名为“copy”的成员时才生成复制方法。

回答by Daniel C. Sobral

You seem to be confusing copywith clone. The goal of copyis to make an almostidentical copy, but with something changed. What that something might be depends on the parameters of the case class, so it's not possible to make it a common method.

你似乎是混乱copyclone。的目标copy是制作一个几乎相同的副本,但有所改变。那个东西可能是什么取决于案例类的参数,所以不可能使它成为一个通用的方法。

In the case of case class X(), it doesn't make much sense to have a copymethod, as there's nothing there to be changed.

在 的情况下case class X(),拥有一个copy方法没有多大意义,因为没有什么可以改变的。

On the other hand, cloneis a Java method whose goal is to produce perfect copies of an object, which seems to be what you want.

另一方面,clone是一种 Java 方法,其目标是生成对象的完美副本,这似乎是您想要的。

回答by Przemek Pokrywka

As Mirko correctly pointed out, you cannot really abstract over copy method. I support Daniel's view, that cloning may be what you want, although I would wrap it with some helper code to reduce boilerplate.

正如 Mirko 正确指出的那样,您不能真正抽象复制方法。我支持丹尼尔的观点,克隆可能是你想要的,尽管我会用一些帮助代码包装它以减少样板。

You can define a mixin trait with copy functionality and just mix it into your case classes then:

您可以定义具有复制功能的混合特征,然后将其混合到您的案例类中:

trait ClonableAs[T] extends Cloneable { this: T => 
  def makeClone() = super.clone().asInstanceOf[T]
}

case class Foo(i: Int) extends ClonableAs[Foo]

List(Foo(1), Foo(2), Foo(3)).map(_.makeClone())

That way instead of adding an identical method to each of your case classes, you make them extend the helper trait, which makes them cleaner and saves you some keystrokes.

这样,您无需为每个 case 类添加相同的方法,而是让它们扩展 helper 特性,这使它们更干净并为您节省了一些击键次数。

On the other hand, the cloning would make no sense for immutable objects, so I infer your classes have mutable state. I would advise you to reconsider if you really cannot make them immutable, and use that type of cloning only at last resort. Immutability will protect yourself from a class of errors.

另一方面,克隆对于不可变对象毫无意义,因此我推断您的类具有可变状态。如果你真的不能让它们一成不变,我建议你重新考虑,并且只在最后的手段中使用这种类型的克隆。不变性将保护自己免受一类错误的影响。

回答by huynhjl

Upvoted Ben's answer. But what if you wanted to something like this:

赞成本的回答。但是如果你想要这样的东西怎么办:

sealed trait Op 
case class Push(value: Int, context:String) extends Op
case class Pop(context:String) extends Op

val stackOps = List(Push(3, "foo"), Pop("foo"))

def copyToContext(newContext:String, ops:List[Op]): List[Op] = {
    // ... ?
}

val changedOps = copyToContext("bar", stackOps)

// would return: List(Push(3, "bar"), Pop("bar"))

回答by Ben Lings

Why do you need to create identical copies of your case class instances? Case classes are, by default, immutable so can be safely shared.

为什么需要创建案例类实例的相同副本?默认情况下,案例类是不可变的,因此可以安全地共享。

In any case, I don't think you can do what you're asking with default parameters:

无论如何,我认为您无法使用默认参数执行您的要求:

scala> trait Op { def copy():Op }          
defined trait Op

scala> case class Op1(v:Int) extends Op    
<console>:6: error: class Op1 needs to be abstract, since method copy in trait Op of type ()Op is not defined
       case class Op1(v:Int) extends Op

The compiler doesn't create methods with all combinations of the optional parameters in the defining class. The default values are inserted in the place where the method is called.

编译器不会创建具有定义类中可选参数的所有组合的方法。默认值插入到调用方法的位置。