接受Future[String]和String的泛型参数类型



我需要定义一个函数

def acceptFutureOfStringOrString(param: T) = ???

其中T是既可以接受Future[String]又可以接受String的泛型类型。请告诉我应该如何定义类型。感谢

您可以定义一个函数;具有CCD_ 1":

def accept[F[_]](param: F[String]) = ???

当然,你不能完全使用它。但既然你提到了猫,你可以做例如

def accept[F[_]: Monad](param: F[String]) = ???

这将允许您调用map/flatMap,即F[String]上的链计算。您可以通过执行accept[cats.Id]("foo")使用原始值来调用它。这在FP方面实际上相当常见,尽管您会失去特定于Future的功能,比如使用Await.result或处理错误的能力。


如果你真的想只接受字符串或字符串的未来,你可以使用Either:

def accept(param: Either[String, Future[String]]) = ???

或者Either2K,另一个猫的东西:

def accept(param: Either2K[Id, Future, String]) = ???

如果你使用的是Scala 3,你可以使用一个联合类型:

def accept(param: String | Future[String]) = ???

如果你坚持使用Scala2,你也可以使用带有隐式转换的自定义数据类型,以避免在调用站点包装:

sealed trait Thingie
case class OfString(s: String) extends Thingie
case class OfFuture(fs: Future[String]) extends Thingie
object Thingie {
implicit def fromString(s: String): Thingie = OfString(s)
implicit def fromFutureString(fs: Future[String]): Thingie = OfFuture(fs)
}
def accept(param: Thingie) = ???
// Will look seamless
accept("foo")
accept(Future.successful("bar"))

没有上下文,我无法判断哪一个最适合你。如果您不能使F[_]变体工作,那么对于实用程序方法,请坚持使用"非此即彼"或"联合";隐式转换应该保留给花哨的DSL,甚至在那里使用得很少。

如果您只是想限制可以传递给函数的类型,请使用typeclass:

sealed trait AllowableType[T]
implicit object AllowString extends AllowableType[String] {}
implicit object AllowFutureString extends AllowableType[Future[String]] {}
def acceptFutureOfStringOrString[T: AllowableType](param: T) = ???

如果您想对取决于类型的值进行一些处理,请将处理函数作为方法添加到trait中,并在每个String0中实现它们。

作为Tim答案的一个细微变化,我可以变出这样的东西,但这是一种非常奇怪的做事方式。

sealed trait IsWithinBounds[P, T]
object IsWithinBounds {
implicit def Future[T]: IsWithinBounds[Future[T], T] = new IsWithinBounds[Future[T], T] {}
implicit def String: IsWithinBounds[String, String]  = new IsWithinBounds[String, String] {}
}
def t[T](param: T)(implicit ev: T IsWithinBounds String): Any = ???
t("some string")        //ok
t(Future("some future string")) //ok
t(42)              //compile error

感谢大家的回答。正确的答案是在Future上绘制地图,然后按照其他人的建议使用Future[String]中的String。

最新更新