Defining a Map from String to Function in Scala

前端 未结 5 837
粉色の甜心
粉色の甜心 2021-02-05 21:17

I am trying to define a Map literal with key: String, value: (Any)=>String. I tried the following, but get a syntax error:

def foo(x         


        
相关标签:
5条回答
  • 2021-02-05 21:17

    Trait Function1 is contravariant for parameter, so def foo(x: Int): String is not a (Any) => String. So the following would work:

    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>))
    
    0 讨论(0)
  • 2021-02-05 21:22

    Int => String is not a subclass of Any => String, rather, the contrary. You can't put (replace) an Int => String function when a code expects Any => String, since that code can apply the function with, say, "hi".

    @Ben suggestion works, but how is it useful? you can't invoke the function once you get it from the Map.

    If you really want to do this, maybe define foo as a partial function:

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

    Obviously, this will fail at runtime if you pass it a string, but you can always test if the function is ok for use with your parameter by using isDefinedAt. (another alternative may be manifests, but I don't see the value here)

    0 讨论(0)
  • 2021-02-05 21:28

    This is how I did it to fulfill a similar requirement.

    object MapToMethods {
    private def increment(x: Int): Int = x+1
    private def decrement(x: Int): Int = x-1
    
    val m: Map[String, Int => Int] =Map("increment" -> increment, "decrement" ->decrement)
    
    println(m("increment")(2)) //prints 3
    println(m("decrement")(3)) //prints 2
    }
    
    0 讨论(0)
  • 2021-02-05 21:38

    Funny that no one actually gave a type that would work. Here's one such:

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

    The reason why it works this way is because Function1 is contra-variant on the input, so (Nothing) => String is a superclass of (Int) => String. It is also co-variant on the output, so (Nothing) => Any would be a superclass to any other Function1.

    Of course, you can't use it like that. Without manifests, you can't even uncover what the original type of Function1 is. You could try something like this, though:

    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"
    }
    
    0 讨论(0)
  • 2021-02-05 21:44

    If I let the compiler infer it I seem to get an illegal type:

    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
    

    Anyway, what you want is not the type Any but a generic of "any type" which is _:

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

    I just posted a question about how to invoke such functions because I don't actually know.

    0 讨论(0)
提交回复
热议问题