Класс абстракции метода copy () - PullRequest
12 голосов
/ 26 мая 2010

Я хотел бы знать, можно ли абстрагировать метод copy от case-классов. В основном у меня есть что-то вроде sealed trait Op, а затем что-то вроде case class Push(value: Int) extends Op и case class Pop() extends Op.

Первая проблема: класс case без аргументов / членов не определяет метод копирования. Вы можете попробовать это в 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)

Есть ли причина, по которой компилятор делает это исключение? Я думаю, что это не совсем так, и я ожидал бы, что каждый класс case будет определять метод копирования.

Вторая проблема: у меня есть метод def ops: List[Op], и я хотел бы скопировать все операции, например ops map { _.copy() }. Как бы я определил метод копирования в черте Op? Я получаю ошибку «слишком много аргументов», если говорю def copy(): Op. Однако, поскольку все методы copy () имеют только необязательные аргументы: почему это неверно? И как мне сделать это правильно? Сделав другой метод с именем def clone(): Op и напишите везде def clone() = copy() для всех классов case? Я надеюсь, что нет.

Ответы [ 5 ]

12 голосов
/ 26 мая 2010

Вы, кажется, путаете copy с clone. Цель copy - сделать почти идентичную копию, но с чем-то измененным. Что это может быть, зависит от параметров класса case, поэтому невозможно сделать его обычным методом.

В случае case class X() не имеет особого смысла иметь метод copy, так как там нечего менять.

С другой стороны, clone - это метод Java, целью которого является создание идеальных копий объекта, что, по-видимому, является тем, что вам нужно.

9 голосов
/ 26 мая 2010
  1. Какая польза от метода копирования, сгенерированного компилятором, для классов case без каких-либо аргументов? Это просто вернет новый Foo и ничего не скопирует.
  2. К цитата Лукаса Ритца (я полагаю, он это реализовал):
Методы копирования генерируются только в том случае, если в классе нет члена с именем «copy», определенного или унаследованного.
2 голосов
/ 07 октября 2011

Как правильно заметил Мирко, вы не можете абстрагироваться от метода копирования. Я поддерживаю точку зрения Дэниела, что клонирование может быть тем, что вам нужно, хотя я бы обернул его некоторым вспомогательным кодом, чтобы уменьшить шаблон.

Вы можете определить черту mixin с функцией копирования и просто смешать ее с вашими классами дел:

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())

Таким образом, вместо добавления идентичного метода к каждому из ваших классов дел, вы заставляете их расширять черту помощника, которая делает их чище и экономит некоторые нажатия клавиш.

С другой стороны, клонирование не имело бы смысла для неизменных объектов, поэтому я предполагаю, что у ваших классов изменчивое состояние. Я бы посоветовал вам пересмотреть, если вы действительно не можете сделать их неизменяемыми, и использовать этот тип клонирования только в крайнем случае. Неизменность защитит себя от класса ошибок.

1 голос
/ 26 мая 2010

Ответ Бена. Но что, если вы хотите что-то вроде этого:

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"))
1 голос
/ 26 мая 2010

Зачем вам нужно создавать идентичные копии ваших экземпляров класса дел? Классы case по умолчанию являются неизменяемыми, поэтому их можно безопасно использовать совместно.

В любом случае, я не думаю, что вы можете делать то, что вы просите, с параметрами по умолчанию:

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

Компилятор не создает методы со всеми комбинациями необязательных параметров в определяющем классе. Значения по умолчанию вставляются в место, где вызывается метод.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...