Scala隐式转换器
我试图找出如何为特定类型创建隐式转换器。在我的例子中,这将是一个Scala隐式转换器,scala,implicit-conversion,Scala,Implicit Conversion,我试图找出如何为特定类型创建隐式转换器。在我的例子中,这将是一个Set[IdParam[T]]到Set[IdTag[T]],其中 import shapeless.tag.@@ case class IdParam[T](value: IdTag[T]) type IdTag[T] = Id @@ T class Id(val value: Long) object Id { def tag[T](l: Long) = shapeless.tag[T][Id](new Id(l))
Set[IdParam[T]]
到Set[IdTag[T]]
,其中
import shapeless.tag.@@
case class IdParam[T](value: IdTag[T])
type IdTag[T] = Id @@ T
class Id(val value: Long)
object Id {
def tag[T](l: Long) = shapeless.tag[T][Id](new Id(l))
def value[T](l: Long) = Id.tag[T](l)
}
我写了一个简单的
implicit def toIds[T](idParams: Set[IdParam[T]]): Set[IdTag[T]] = idParams.map(_.value)
哪个好用。但我现在的主要问题是,是否有一种方法可以创建一个包含Seq和Set的隐式转换器。在等级制度上,这将意味着一个可移植的。
尝试了以下方法
implicit def toIds[I <: Iterable[IdParam[T]], T](idParams: I): Iterable[IdTag[T]] = idParams.map(_.value)
编辑
该隐式转换器应在控制器端点中使用
GET /campaigns @dummy.Campaigns.all(profileId: Set[IdParam[ProfileIdTag]] ?= Set.empty)
我有一个QueryStringBindable,它将作为字符串检索的查询参数转换为集[IdParam[a]]
object IdQueryStringBinder {
implicit def idParamQueryStringBinder[A](implicit stringBinder: QueryStringBindable[String]) =
new QueryStringBindable[IdParam[A]] {
def bind(key: String, params: Map[String, Seq[String]]): Option[Either[String, IdParam[A]]] =
for {
idEither <- stringBinder.bind(key, params)
} yield {
idEither match {
case Right(idString) =>
IdBinder.parseIdString(idString)
case Left(_) => Left("Unable to bind an Id")
}
}
override def unbind(key: String, id: IdParam[A]): String =
stringBinder.unbind(key, id.value.toString)
}
implicit def idsParamQueryStringBinder[A](implicit stringBinder: QueryStringBindable[String]) =
new QueryStringBindable[Set[IdParam[A]]] {
override def bind(key: String, params: Map[String, Seq[String]]): Option[Either[String, Set[IdParam[A]]]] = {
stringBinder.bind(key, params).map(_.right.flatMap(parse))
}
private def parse(idsString: String): Either[String, Set[IdParam[A]]] = {
val (wrongIds, correctIds) = idsString.split(",")
.map(id => IdBinder.parseIdString[A](id))
.partition(_.isLeft)
if (wrongIds.nonEmpty) {
Left(s"Could not bind the following Ids: ${wrongIds.map(_.left.get).mkString(",")}")
} else {
Right(correctIds.map(_.right.get).toSet)
}
}
override def unbind(key: String, ids: Set[IdParam[A]]): String =
stringBinder.unbind(key, ids.map(_.value.toString).mkString(","))
}
}
第一个端点工作,它使用定义的idParamQueryStringBinder
和以下隐式转换器
implicit def toId[T](idParam: IdParam[T]): IdTag[T] = idParam.value
您一定犯了一些编码错误,因为它对我来说非常好:
下次粘贴导致问题的完整代码,而不仅仅是小部分。添加导致错误的代码这是引发错误的原因:
[error]GET/activities@dummy.activities.all(profileId:Set[IdParam[ProfileIdTag]]?=Set.empty)
感谢您对此进行调查。我已经添加了代码的更多细节。@@是从无形状库中获取的,而不是scalaz。对不起,我以前没提过。
class Campaigns extends play.api.mvc.Controller {
def allByProfileId(profile: ProfileId) = ...
def all(profileIds: Set[ProfileId]) = ...
}
implicit def toId[T](idParam: IdParam[T]): IdTag[T] = idParam.value