Тип Scala для объекта или функции, возвращающей объект - PullRequest
1 голос
/ 22 февраля 2012

Итак, я попал в Scala и у меня возник вопрос, возможно ли то, что я хочу сделать, или есть лучший способ.

Я хочу иметь возможность принимать в качестве параметра Map, ключи которой являются либо строками, либо функцией 0-args, возвращающей строку. Так например

def main(args: List[String]){
    f = F(
      Map(
      "key" -> "value",
      "key2" ->(()=> {"valule2"})
    )
    )

    println(f("key"))

}
    case class F(arg: Map[String, ???]){
        def apply(s: String): String = {arg(s)}
    }

Это явно не компилируется. Есть ли способ сделать это?

Ответы [ 2 ]

8 голосов
/ 22 февраля 2012

В этом случае вы можете использовать scala.Either

scala> val map: Map[String, Either[String, () => String]] = Map.empty
map: Map[String,Either[String,() => String]] = Map()

scala> map + ("key" -> Left("value"))
res0: scala.collection.immutable.Map[String,Either[String,() => String]] = Map(key -> Left(value))

scala> res0("key")
res1: Either[String,() => String] = Left(value)

scala> map + ("key2" -> Right(() => "value2"))
res2: scala.collection.immutable.Map[String,Either[String,() => String]] = Map(key2 -> Right(<function0>))

scala> res2("key2")
res3: Either[String,() => String] = Right(<function0>)

Обновление

Вы можете скрыть реализацию от вызывающей стороны, используя что-то вроде этого.

def toEither[T <: Any : Manifest](x: T): Either[String, () => String] =
  x match {
    case x: String => Left(x)
    case x: Function0[String] if manifest[T] <:< manifest[() => String] => Right(x)
    case _ => throw new IllegalArgumentException
  }

Фактический тип Function0 исключен из-за стирания типа, но его можно проверить с помощью Manifest

scala> map + ("key" -> toEither("value"))
res1: scala.collection.immutable.Map[String,Either[String,() => String]] = Map(key -> Left(value))

scala> map + ("key2" -> toEither(() => "value2"))
res2: scala.collection.immutable.Map[String,Either[String,() => String]] = Map(key2 -> Right(<function0>))

scala> res2("key2").right.get()
res3: String = value2

scala> map + ("key2" -> toEither(() => 5))
java.lang.IllegalArgumentException

scala> map + ("key2" -> toEither(false))
java.lang.IllegalArgumentException

Update2

Поскольку @Submonoid правильно исправил меня вкомментарии ниже, есть гораздо более простой способ справиться с Either.

type StringOrFun = Either[String, () => String]
implicit def either(x: String): StringOrFun = Left(x)
implicit def either(x: () => String): StringOrFun = Right(x)

val m: Map[String, StringOrFun] = Map("key" -> "value", "key2" -> (() => "value2"))
3 голосов
/ 22 февраля 2012

Кроме того, вы можете заключить любую строку в функцию, которая вычисляется в эту строку:

implicit def delayed[A](a : A) = () => a
val m = Map[String, () => String]("a" -> "b", "c" -> (() => "d"))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...