Определение карты из строки в функцию в Scala - PullRequest
11 голосов
/ 06 января 2011

Я пытаюсь определить литерал Map с ключом: String, значение: (Any)=>String. Я пробовал следующее, но получаю синтаксическую ошибку:

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

Ответы [ 5 ]

10 голосов
/ 06 января 2011

Забавно, что на самом деле никто не дал тип, который будет работать.Вот один такой:

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

Причина, по которой он работает таким образом, заключается в том, что Function1 является противоположным вариантом на входе, поэтому (Nothing) => String является суперклассом (Int) => String.Он также является ко-вариантом на выходе, поэтому (Nothing) => Any будет суперклассом для любого другого Function1.

Конечно, вы не можете использовать его таким образом.Без манифестов вы даже не сможете раскрыть, что такое оригинальный тип Function1.Вы можете попробовать что-то вроде этого, хотя:

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 голосов
/ 06 января 2011

Int => String не является подклассом Any => String, скорее наоборот.Вы не можете поставить (заменить) функцию Int => String, когда код ожидает Any => String, поскольку этот код может применить функцию, скажем, «hi».

@ Предложение Бен работает, нокак это полезно?Вы не можете вызвать функцию, как только получите ее с карты.

Если вы действительно хотите это сделать, возможно, определите foo как частичную функцию:

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

Очевидно, это будетпотерпеть неудачу во время выполнения, если вы передадите ей строку, но вы всегда можете проверить, в порядке ли функция для использования с вашим параметром, используя isDefinedAt.(другая альтернатива может быть манифестом, но я не вижу здесь значения)

4 голосов
/ 06 января 2011

Если я позволю компилятору сделать вывод, я получу недопустимый тип:

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

В любом случае, вам нужен не тип Any, а универсальный тип "любого типа", который _:

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

Я только что опубликовал вопрос о как вызывать такие функции , потому что я на самом деле не знаю.

3 голосов
/ 06 января 2011

Черта Function1 является контравариантной для параметра, поэтому def foo(x: Int): String не является (Any) => String.Таким образом, будет работать следующее:

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 голосов
/ 21 сентября 2018

Вот как я это сделал, чтобы выполнить аналогичное требование.

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
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...