2011-03-15 18 views
15

Intenté combinar argumentos implícitos con clases de casos, pero me quedé atascado.Clase de caso y argumentos implícitos y coincidencia de patrones

case class C(i: Int)(implicit b: Boolean) 
val c1 = C(1)(true) 
implicit val b = true 
val c2 = C(2) 
c1 match { 
    case C(i)(b) => // doesn´t work 
    case C(i,b) => // doesn´t work 
    case C(i) => // works, but wanted: if (b) i else 0 
} 

De acuerdo con la especificación del lenguaje Scala se inunda debido a que el compilador genera objeto extractora para las clases de caso: Mi implícita Boolean no es un miembro de la clase resultante caso, por lo que tiene que estar en el segundo (implícita) lista de argumentos (que yo no encuentro en el compañero object's aplicar el método, por desgracia):

una definición de clase caso de c[tps](ps1). . .(psn) con parámetros de tipo y valor tps parámetros ps genera implícitamente un objeto extractora (§ 8.1.8) que se define como sigue:

object c { 
    def apply[tps](ps1). . .(psn): c[tps] = new c[Ts](xs1). . .(xsn) 
    def unapply[tps](x: c[tps]) = 
    if (x eq null) scala.None 
    else scala.Some(x.xs11, . . . , x.xs1k) 
} 

¿Cómo puedo definir una clase de caso con los miembros que se suministran de forma implícita en el momento de la creación?

Respuesta

18

Puede definir una clase de caso con argumentos implícitos, pero como ha descubierto, no están disponibles para la coincidencia de patrones. Siempre se puede escribir su propio extractor de embargo:

case class C(i: Int)(implicit val b: Boolean) 

// You can't call this C because that seat is taken (can't overload the default unapply) 
object C_ { 
    // In order to be able to select `b` here, 
    // it needs to be declared as "implicit *val* b: Boolean" 
    def unapply(in: C) = Some((in.i, in.b)) 
} 

c1 match { 
    case C_(i, b) => ... 
} 
+0

En realidad, creo que * puede * definir el 'objeto C' para anular la clase de caso suministrada' unapply'. Además, 'implícito b' no se convierte automáticamente en' val b', por lo que hay algo más de trabajo. –

+0

"No se puede resolver la sobreaplicación sobrecargada" :) Y en cuanto a val, sí, estaba a mitad de edición. :) –

+1

Supongo que entonces, podría escribir igualmente: 'c1 coincidencia {caso x @ C (i) => if (x.b) i else 0}' – Mahdi

3

la respuesta de Alex es inteligente, sin embargo, no me gusta mucho la _ en el nombre del objeto, encuentro la sintaxis un poco extraño y recordando el guión hace coincidencia de patrones más difícil de usar. (Por supuesto, esto es todo subjetivo, por lo que sus sentimientos pueden variar).

Mi primer enfoque para hacer frente a esto fue mover los parámetros implícitos al método apply en el objeto complementario.

case class A(i: Int, b: Boolean) 

object Foo { 
    def apply(i: Int)(implicit b: Boolean): Foo = apply(a, b) 
} 

Pero esto resulta en

Error:(21, 14) double definition: 
method apply:(i: Int, b: Boolean)com.workday.cloud.master.package.A and 
method apply:(i: Int)(implicit b: Boolean)com.workday.cloud.master.package.A at line 24 
have same type after erasure: (i: Int, b: Boolean)com.workday.cloud.master.package.A 
    case class A(i: Int, b: Boolean) 
      ^

Como mi amigo Yuriy sugirió, podemos solucionar este problema mediante la adición de un parámetro implícito adicional Unused.

object A { 
    implicit object Unused 

    def apply(i: Int)(implicit b: Boolean, unused: Unused.type): A = apply(i, b) 
} 

El enfoque que elija depende de usted, me parece que este enfoque permite que mi código de cliente se vea más natural.

+0

thx para la sugerencia "no utilizada"! – comonad

+1

'no utilizado: Unit =()' funciona también – comonad

Cuestiones relacionadas