В этом случае вы можете использовать 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"))