可变参数的上下文绑定
Context bound for varargs
几天前我开始学习Cats,我想为Map[String, _: Show]
实现方法appendOptional
。
我从以下想法开始:
def appendOptional[T: Show](to: Map[String, String], values: (String, Option[T])*): Map[String, String] =
values.foldLeft(values) {
case (collector, (key, Some(value))) =>
collector + (key -> implicitly[Show[T]].show(value))
case (collector, _) => collector
}
并像这样使用它:
def createProps(initial: Map[String, String], name: Option[String], age: Option[Int])
val initial = Map("one" -> "one", "two" -> "two")
val props = appendOptional(initial, "name" -> name, "age" -> age)
我知道这种方法非常幼稚和直接,因为 implicitly[Show[T]].show(value)
实际上会查找 Show[Any]
。
此外,我有一个想法接受 HList
与上下文绑定,但我还没有找到任何例子。
另一种变体是创建大量重载方法(就像在很多库中所做的那样):
def appendOptional[T1: Show, T2: Show](to: Map[String, String], v1: (String, Option[T1], v2: (String, Option[T2])))
问题:有没有办法为可变参数函数定义上下文绑定?
严格来说,第一个是定义边界的正确方法; varargs 并不意味着参数的类型不同,只是它们的数量。
使用不同类型实现您想要的方法更加复杂,需要将 Show
个实例与值打包在一起。例如
case class HasShow[A](x: A)(implicit val ev: Show[A])
def appendOptional(to: Map[String, String], values: (String, Option[HasShow[_]])*): Map[String, String] =
values.foldLeft(values) {
// value.ev.show(value.x)) can be extracted into a method on HasShow as well
case (collector, (key, Some(value: HasShow[a]))) =>
collector + (key -> value.ev.show(value.x))
case (collector, _) => collector
}
val props = appendOptional(initial, "name" -> name.map(HasShow(_)), "age" -> age.map(HasShow(_)))
您可以为 HasShow
添加更多隐式转换以简化调用站点,但这样您可以更好地了解发生了什么。
对于这个具体案例,我认为更好更简单的解决方案是
implicit class MapOp(self: Map[String, String]) extends AnyVal {
def appendOptional[A: Show](key: String, value: Option[A]) =
value.fold(self)(x => self + (key -> Show.show(x)))
}
val props = initial.appendOptional("name", name).appendOptional("age", age)
几天前我开始学习Cats,我想为Map[String, _: Show]
实现方法appendOptional
。
我从以下想法开始:
def appendOptional[T: Show](to: Map[String, String], values: (String, Option[T])*): Map[String, String] =
values.foldLeft(values) {
case (collector, (key, Some(value))) =>
collector + (key -> implicitly[Show[T]].show(value))
case (collector, _) => collector
}
并像这样使用它:
def createProps(initial: Map[String, String], name: Option[String], age: Option[Int])
val initial = Map("one" -> "one", "two" -> "two")
val props = appendOptional(initial, "name" -> name, "age" -> age)
我知道这种方法非常幼稚和直接,因为 implicitly[Show[T]].show(value)
实际上会查找 Show[Any]
。
此外,我有一个想法接受 HList
与上下文绑定,但我还没有找到任何例子。
另一种变体是创建大量重载方法(就像在很多库中所做的那样):
def appendOptional[T1: Show, T2: Show](to: Map[String, String], v1: (String, Option[T1], v2: (String, Option[T2])))
问题:有没有办法为可变参数函数定义上下文绑定?
严格来说,第一个是定义边界的正确方法; varargs 并不意味着参数的类型不同,只是它们的数量。
使用不同类型实现您想要的方法更加复杂,需要将 Show
个实例与值打包在一起。例如
case class HasShow[A](x: A)(implicit val ev: Show[A])
def appendOptional(to: Map[String, String], values: (String, Option[HasShow[_]])*): Map[String, String] =
values.foldLeft(values) {
// value.ev.show(value.x)) can be extracted into a method on HasShow as well
case (collector, (key, Some(value: HasShow[a]))) =>
collector + (key -> value.ev.show(value.x))
case (collector, _) => collector
}
val props = appendOptional(initial, "name" -> name.map(HasShow(_)), "age" -> age.map(HasShow(_)))
您可以为 HasShow
添加更多隐式转换以简化调用站点,但这样您可以更好地了解发生了什么。
对于这个具体案例,我认为更好更简单的解决方案是
implicit class MapOp(self: Map[String, String]) extends AnyVal {
def appendOptional[A: Show](key: String, value: Option[A]) =
value.fold(self)(x => self + (key -> Show.show(x)))
}
val props = initial.appendOptional("name", name).appendOptional("age", age)