2011-05-30 10 views
6

Dado el siguiente código:Problema con Scala correspondientes + alcance

case class ChangeSet(field:String, from:Object, to:Object) 

private var changed:List[ChangeSet] = Nil 

def change(field:String, from:Object, to:Object) { 
    changed.find{ case ChangeSet(field,_,_) => true } match { 
    case Some(ChangeSet(field,to,_)) => // do stuff 
    case Some(_) => // do stuff 
    case _ => // do stuff 
    } 
} 

La línea de darme problemas es Some(ChangeSet(field,to,_)).

Compila pero lo que parece estar sucediendo es que Scala se está llenando en como un marcador de posición para un comodín. Baso esa suposición en el hecho de que cuando hago lo siguiente Some(ChangeSet(field,to,to)) obtengo el error to is already defined as value.

Lo que quería es hacer un objeto de cambios con to de los parámetros del método.

¿Es posible?

Respuesta

7

Cuando el patrón de juego Scala interpreta todos los identificadores comenzando con minúscula como marcadores de posición y llena de valores. Para decirle a Scala que use to como un valor constante desde el alcance externo que necesita para rodearlo con patillas: `to`. Alternativamente, podría cambiar el nombre de to por To como sugirió Rex Kerr, pero prefiero mantener mis variables en minúscula.

Esto debería funcionar:

def change(field:String, from:Object, to:Object) { 
    changed.find{ case ChangeSet(`field`,_,_) => true } match { 
    case Some(ChangeSet(`field`, `to`, _)) => // do stuff 
    case Some(_) => // do stuff 
    case _ => // do stuff 
    } 
} 
+2

La parte más complicada con la notación de los backticks es cómo hacer que se muestre correctamente en una respuesta de StackOverflow :-) –

1

No puede utilizar nombres de variables en los patrones de esa manera. Primero debe compararlo con una nueva variable y luego hacer una comparación explícita.

def change(field:String, from:Object, to:Object) { 
    changed.find{ case ChangeSet(f,_,_) => field == f } match { 
    case Some(ChangeSet(f,too,_)) if f == field && to == too => // do stuff 
    case Some(_) => // do stuff 
    case _ => // do stuff 
    } 
} 
+0

Eso no es del todo correcto: se puede usar la notación acentos abiertos, como se muestra en [respuesta de Kassens] (http://stackoverflow.com/questions/6172557/problem-with-scala-matching-scope/6173342#6173342). –

+0

¡genial! cuando fue eso agregado? –

+0

No lo sé; desde hace más de dos años al menos :-) –

1

Si se utiliza un nombre en minúscula en una comparación de patrones, Scala se rellenará con el valor. Si desea hacer coincidir solo si tiene ese valor, debe usar un nombre en mayúscula. Dejando a un lado la lógica de lo que estás tratando de hacer, y el cambio cuestionable en orden de nombres, que deseas:

def change(Field: String, from:Object, To: Object) { 
    changed.find{ 
    case ChangeSet(Field,_,_) => true 
    case _ => false // You need this line! No match is an exception, not false! 
    } match { 
    case Some(ChangeSet(Field,To,_)) => // do stuff 
    case Some(_) => // do stuff 
    case _ => // do stuff 
    } 
} 
4

Parece que hay dos confusiones aquí. El primero es el identificado por Rex y Kim. Puede leer this section de Programación en Scala para obtener más información. Todo se reduce a:

x match { case Some(foo) => } // variable pattern, defines and binds variable foo 
x match { case Some(Foo) => } // constant pattern, based on val Foo 
x match { case Some(`foo`) => } // constant pattern for lowercase val 

También puede utilizar un guardia a la restricción del partido

x match { case Some(foo) if condition => } 

La segunda confusión es que desea "crea un objeto de cambios con a partir de la parámetros de método ". Si entiendo correctamente que usted está tratando de construir un objeto utilizando la sintaxis clase de caso:

ChangeSet(field, from, to) 

esto no funciona en ese lado de la coincidencia de patrones. Lo que sucede en el ladocaso de la coincidencia de patrón en realidad puede ser visto como el revertir de la construcción del conjunto de cambios. match { case ChangeSet(field, from, to) => } tipo de deconstruye su objeto ChangeSet y asigna sus partes a los field, from y to Vals. Esto también es cierto cuando está compuesto así: Some(ChangeSet(field, from, to)), primero deconstruye Some y luego ChangeSet.Se puede ver que trabajando en valor definiciones ya que está aprovechando el mismo mecanismo deconstrucción:

scala> val cset = ChangeSet("a", "from", "to") 
cset: ChangeSet = ChangeSet(a,from,to) 

scala> val Some(ChangeSet(s, o1, o2)) = Some(cset) 
s: String = a 
o1: java.lang.Object = from 
o2: java.lang.Object = to 

Parece que lo que quiere hacer es construir un nuevo objeto que copia el valor de ChangeSet pero sustituyendo un solo campo . clases caso apoya esto con copy, continuando con mi ejemplo REPL:

scala> val cset2 = cset.copy(from = o2) 
cset2: ChangeSet = ChangeSet(a,to,to) 

Con esto en mente, aquí es otra sugerencia para change:

def change(field:String, from:Object, to:Object) { 
    changed.find(_.field == field) match { 
    case Some(cset) => 
     val csetnew = cset.copy(from = to) 
     // do stuff with csetnew 
    case None => 
     // do stuff 
    } 
} 
Cuestiones relacionadas