当只需要一种收集方法时如何使用隐式转换而不是结构类型
How to use implicit conversion instead of structural typing when only one collection method is needed
我有一个方法,我只需要访问一个类型的一个方法(appended
,或:+
)。我希望能够同时使用自定义大小写 class 和普通大小写 List
。来自 TypeScript 背景,我知道如何使用结构类型来做到这一点:
case class CustomContainer[T](data: List[T]) {
def :+(other: T): CustomContainer[T] = copy(data = data :+ other)
}
def append[T, A <: { def :+(other: T): A }](appendable: A, other: T): A = appendable :+ other
append(List(1,2,3), 4) // List(1,2,3,4)
append(CustomContainer(List(1,2,3)), 4) // CustomContainer(List(1,2,3,4))
但是,我也知道使用结构类型在性能和可维护性方面存在劣势。我想找到一个更好的方法,所以我尝试使用特征来做到这一点,但症结在于我无法 List
扩展我定义的某些特征。我感觉答案是隐式转换,但我不知道如何将某些东西隐式转换为特征,这是一种抽象类型。
这是我目前尝试过的方法:
trait Appendable[T, C] {
def :+(other: T): C
}
case class CustomContainer[T](data: List[T]) extends Appendable[T, CustomContainer[T]] {
override def :+(other: T): CustomContainer[T] = copy(data = data :+ other)
}
implicit def listToAppendable[T](list: List[T]): Appendable[T, List[T]] = ??? // What goes here?
def append[T, A <: Appendable[T, A]](appendable: A, other: T): A = appendable :+ other
append(List(1,2,3), 4) // List(1,2,3,4)
append(CustomContainer(List(1,2,3)), 4) // CustomContainer(List(1,2,3,4))
???
位置是什么?或者有更好的方法吗?
我正在使用 Scala 2.10.4。
您可以为此使用类型 class:
final case class CustomContainer[T](data: List[T])
trait Appendable[T, C[_]] {
def specialAppend(other: T, acc: C[T]): C[T]
}
object Appendable {
implicit def listAppendable[A]: Appendable[A, List] = new Appendable[A, List] {
override def specialAppend(other: A, acc: List[A]): List[A] = other :: acc
}
implicit def customContainerAppendable[A]: Appendable[A, CustomContainer] = new Appendable[A, CustomContainer] {
override def specialAppend(other: A, acc: CustomContainer[A]): CustomContainer[A] = acc.copy(data = other :: acc.data)
}
}
object Foo {
implicit class AppendableOps[A, C[_]](val c: C[A]) {
def :+!(elem: A)(implicit appendable: Appendable[A, C]): C[A] = appendable.specialAppend(elem, c)
}
def main(args: Array[String]): Unit = {
println(List(1,2,3,4) :+! 6)
println(CustomContainer(List(1)) :+! 2)
()
}
}
产量:
List(6, 1, 2, 3, 4)
CustomContainer(List(2, 1))
我有一个方法,我只需要访问一个类型的一个方法(appended
,或:+
)。我希望能够同时使用自定义大小写 class 和普通大小写 List
。来自 TypeScript 背景,我知道如何使用结构类型来做到这一点:
case class CustomContainer[T](data: List[T]) {
def :+(other: T): CustomContainer[T] = copy(data = data :+ other)
}
def append[T, A <: { def :+(other: T): A }](appendable: A, other: T): A = appendable :+ other
append(List(1,2,3), 4) // List(1,2,3,4)
append(CustomContainer(List(1,2,3)), 4) // CustomContainer(List(1,2,3,4))
但是,我也知道使用结构类型在性能和可维护性方面存在劣势。我想找到一个更好的方法,所以我尝试使用特征来做到这一点,但症结在于我无法 List
扩展我定义的某些特征。我感觉答案是隐式转换,但我不知道如何将某些东西隐式转换为特征,这是一种抽象类型。
这是我目前尝试过的方法:
trait Appendable[T, C] {
def :+(other: T): C
}
case class CustomContainer[T](data: List[T]) extends Appendable[T, CustomContainer[T]] {
override def :+(other: T): CustomContainer[T] = copy(data = data :+ other)
}
implicit def listToAppendable[T](list: List[T]): Appendable[T, List[T]] = ??? // What goes here?
def append[T, A <: Appendable[T, A]](appendable: A, other: T): A = appendable :+ other
append(List(1,2,3), 4) // List(1,2,3,4)
append(CustomContainer(List(1,2,3)), 4) // CustomContainer(List(1,2,3,4))
???
位置是什么?或者有更好的方法吗?
我正在使用 Scala 2.10.4。
您可以为此使用类型 class:
final case class CustomContainer[T](data: List[T])
trait Appendable[T, C[_]] {
def specialAppend(other: T, acc: C[T]): C[T]
}
object Appendable {
implicit def listAppendable[A]: Appendable[A, List] = new Appendable[A, List] {
override def specialAppend(other: A, acc: List[A]): List[A] = other :: acc
}
implicit def customContainerAppendable[A]: Appendable[A, CustomContainer] = new Appendable[A, CustomContainer] {
override def specialAppend(other: A, acc: CustomContainer[A]): CustomContainer[A] = acc.copy(data = other :: acc.data)
}
}
object Foo {
implicit class AppendableOps[A, C[_]](val c: C[A]) {
def :+!(elem: A)(implicit appendable: Appendable[A, C]): C[A] = appendable.specialAppend(elem, c)
}
def main(args: Array[String]): Unit = {
println(List(1,2,3,4) :+! 6)
println(CustomContainer(List(1)) :+! 2)
()
}
}
产量:
List(6, 1, 2, 3, 4)
CustomContainer(List(2, 1))