2011-07-12 7 views
15

En Mercurio puedo usar:¿Scala tiene una sintaxis de actualización de registros para hacer clones modificados de estructuras de datos inmutables?

A = B^some_field := SomeValue 

para unirse A a una copia de B, excepto que some_field es SomeValue en lugar de lo que fuera en B. Creo que el equivalente Haskell es algo así como:

a = b { some_field = some_value } 

Scala tiene algo como esto para "modificar" valores inmutables. La alternativa parece ser tener un constructor que establezca directamente cada campo en la instancia, lo que no siempre es ideal (si hay invariantes que el constructor debería mantener). Además, sería muy complicado y mucho más frágil si tuviera que pasar explícitamente cualquier otro valor en la instancia de la que quiero tener una copia modificada.

No pude encontrar nada al respecto mediante googlear, o en una breve encuesta del manual de referencia del idioma o "Scala By Example" (que he leído de principio a fin, pero aún no he asimilado , así que bien puede estar allí).

puedo ver que esta característica podría tener algunas interacciones extrañas con protección de acceso al estilo de Java y subclases aunque ...

+1

¿No son las clases de casos lo que estás buscando? http://daily-scala.blogspot.com/2010/01/case-classes-in-28.html –

+0

Vea también http://stackoverflow.com/questions/3900307/cleaner-way-to-update-nested- estructuras –

Respuesta

11

Puede usar clases de casos para esto, pero no es necesario. Las clases de casos no son nada mágicas: el modificador case solo te ahorra un montón de tipeo. El método de copia se realiza mediante el uso de parámetros predeterminados y con nombre. Los nombres son los mismos que los campos y los valores predeterminados son los valores actuales de los campos. Aquí hay un ejemplo:

class ClassWithCopy(val field1:String, val field2:Int) { 
    def copy(field1:String = this.field1, field2:Int = this.field2) = { 
     new ClassWithCopy(field1,field2); 
    } 
} 

Puede usar esto igual que el método de copia en las clases de casos. Los parámetros nominales y predeterminados son una característica muy útil, y no solo para los métodos de copia.

+2

Guau, ¿cómo puedo echar de menos que Scala ha llamado el paso de parámetros? Eso será muy útil. Estoy aceptando esta respuesta, ya que explica cómo funciona el método de copia en las clases de casos, así como también cómo puedo aplicar las ideas incluso cuando las clases de casos no son apropiadas. – Ben

4

Si el objeto que está pensando en la modificación es una clase de caso, entonces usted puede utilizar el autogenerado método de copia:

scala> val user = User(2, "Sen") 
user: User = User(2,Sen) 

scala> val corrected = user.copy(name = "Sean") 
corrected: User = User(2,Sean) 
26

Si define su clase como un case class, se genera un método conveniente copy, y decir que es se puede especificar con parámetros nombrados nuevos valores para ciertos campos.

scala> case class Sample(str: String, int: Int) 
defined class Sample 

scala> val s = Sample("text", 42) 
s: Sample = Sample(text,42) 

scala> val s2 = s.copy(str = "newText") 
s2: Sample = Sample(newText,42) 

Incluso funciona con las clases de casos polimórficas:

scala> case class Sample[T](t: T, int: Int) 
defined class Sample 

scala> val s = Sample("text", 42) 
s: Sample[java.lang.String] = Sample(text,42) 

scala> val s2 = s.copy(t = List(1,2,3), 42) 
s2: Sample[List[Int]] = Sample(List(1, 2, 3),42) 

Tenga en cuenta que s2 tiene un tipo diferente de s.

+0

Muchas gracias por la edición, Lukas, ¡Acabo de aprender algo nuevo! –

+0

¡Gracias por los excelentes ejemplos! La copia polimórfica es muy ingeniosa. – Ben

Cuestiones relacionadas