2011-01-06 24 views
10

Estoy tratando de definir un literal de mapa con clave: String, valor: (Any)=>String. He intentado lo siguiente, pero sale un error de sintaxis:Definir un mapa de cadena a función en Scala

def foo(x: Int): String = /... 
def bar(x: Boolean): String = /... 
val m = Map[String, (Any) => String]("hello" -> foo, "goodbye" -> bar) 
+1

Incluso si la sintaxis en su pregunta trabajó, tiene que haber algo gracioso que estás haciendo con tipos de enviar el tipo correcto de la función se obtiene a partir del mapa. Hay muchas más complicaciones aquí. ¿Qué estás ** realmente ** tratando de hacer? Tal vez haya una solución mejor que no dependa de un mapa de funciones de diferentes tipos. –

Respuesta

9

Es curioso que nadie realmente dio un tipo que sería trabajo. Aquí es uno de esos:

def foo(x: Int): String = x.toString 
def bar(x: Boolean): String = x.toString 
val m = Map[String, (Nothing) => String]("hello" -> foo, "goodbye" -> bar) 

La razón de por qué funciona de esta manera es porque es Function1 contra-variante de la entrada, por lo (Nothing) => String es una superclase de (Int) => String. También es una variante en la salida, por lo que (Nothing) => Any sería una superclase de cualquier otra Function1.

Por supuesto, no puede usarlo así. Sin manifiestos, ni siquiera puede descubrir cuál es el tipo original de Function1. Usted podría intentar algo como esto, sin embargo:

def f[T : Manifest](v: T) = v -> manifest[T] 
val m = Map[String, ((Nothing) => String, Manifest[_])]("hello" -> f(foo), "goodbye" -> f(bar)) 

val IntManifest = manifest[Int] 
val BooleanManifest = manifest[Boolean] 
val StringManifest = manifest[String] 
m("hello")._2.typeArguments match { 
    case List(IntManifest, StringManifest) => 
     m("hello")._1.asInstanceOf[(Int) => String](5) 
    case List(BooleanManifest, StringManifest) => 
     m("hello")._1.asInstanceOf[(Boolean) => String](true) 
    case _ => "Unknown function type" 
} 
4

Si dejo que el compilador inferir que me parezco conseguir un tipo ilegal:

scala> val m = Map("hello" -> foo _, "goodbye" -> bar _) 
m: scala.collection.immutable.Map[java.lang.String,(Boolean with Int) => String] = 
       Map((hello,<function1>), (goodbye,<function1>)) 

scala> m("hello")(8) 
<console>:9: error: type mismatch; 
found : Int(8) 
required: Boolean with Int 
     m("hello")(8) 
scala> var q = new Boolean with Int 
<console>:5: error: illegal inheritance from final class Boolean 
     var q = new Boolean with Int 

De todos modos, lo que quiere no es el tipo Any pero un genérico de "cualquier tipo", que es _:

scala> val mm = Map[String, (_) => String]("hello" -> foo _, "goodbye" -> bar _) 
mm: scala.collection.immutable.Map[String,Function1[_, String]] = 
       Map((hello,<function1>), (goodbye,<function1>)) 

me acaba de publicar una pregunta sobre how to invoke such functions porque no sé realmente.

3

Trait Function1 es contravariante para el parámetro, por lo que def foo(x: Int): String no es (Any) => String. Así que la siguiente funcionaría:

scala> def baz(x: Any): String = "baz"       
baz: (x: Any)String 

scala> val m2 = Map[String, (String) => String]("hello" -> baz) 
m2: scala.collection.immutable.Map[String,(String) => String] = Map((hello,<function1>)) 
4

Int => cadena no es una subclase de Cualquier => String, más bien, al contrario. No puede poner (reemplazar) una función Int => Cadena cuando un código espera Cualquiera => Cadena, ya que ese código puede aplicar la función con, digamos, "hola".

@Ben la sugerencia funciona, pero ¿cómo es útil? no puede invocar la función una vez que la obtiene del Mapa.

Si realmente quiere hacer esto, tal vez definir foo como una función parcial:

val foo: PartialFunction[Any, String] = {case i: Int => ....} 

Obviamente, esto se producirá un error en tiempo de ejecución si se le pasa una cadena, pero siempre se puede comprobar si la función está está bien para usar con su parámetro usando isDefinedAt. (Otra alternativa puede ser manifiestos, pero no veo el valor aquí)

+0

Sí, estoy a punto de publicar la pregunta "¿cómo lo invocas?" porque yo no me conozco –

+0

Vaya, no definí bien. Fijo – IttayD

Cuestiones relacionadas