代码之家  ›  专栏  ›  技术社区  ›  Andrii Abramov Mk.Sl.

varargs的上下文绑定

  •  0
  • Andrii Abramov Mk.Sl.  · 技术社区  · 6 年前

    几天前我开始学习 Cats 我想实现方法 appendOptional 对于 Map[String, _: Show]

    我从以下想法开始:

    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 有上下文限制,但我没有找到任何这样的例子。

    另一种变体是创建许多重载方法(就像在许多libraris中所做的那样):

    def appendOptional[T1: Show, T2: Show](to: Map[String, String], v1: (String, Option[T1], v2: (String, Option[T2])))
    

    问题 :是否有方法定义varargs函数的上下文绑定?

    1 回复  |  直到 6 年前
        1
  •  1
  •   Alexey Romanov    6 年前

    严格地说,第一 界定界限的正确方式;varargs并不意味着参数的类型不同,只意味着参数的数量不同。

    使用各种类型实现所需的方式更复杂,需要打包 Show 实例和值。E、 g。

    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)