scala - 是否可以使用类型类来实现特征?

标签 scala typeclass implicit subtyping

我遇到了一种情况,我想实现给定的特征(下面示例中的CanBeString)。我希望可以选择使用新创建的案例类(下面的示例中的 NewImplementation)来实现该特征,或者通过向某些预先存在的类型添加功能来实现它(只需 >Int 在下面的示例中),通过使用类型类。下面可能最好地说明了这一点:

package example

// typeclass
trait ConvertsToString[A] {
  def asString(value: A): String
}

// the trait I would like the typeclass to implement
trait CanBeString {
  def asString: String
}

// this implementation approach taken from the scala with cats book
object ConvertsToStringInstances {
  implicit val intConvertsToString: ConvertsToString[Int] = 
    new ConvertsToString[Int] {
      def asString(value: Int): String = s"${value}"
    }
}

object ConvertsToStringSyntax {
  implicit class ConvertsToStringOps[A](value: A) {
    def asString(implicit c: ConvertsToString[A]): String = c.asString(value)
  }
}

object Test {
  import ConvertsToStringInstances._
  import ConvertsToStringSyntax._

  def testAsFunc(c: CanBeString): String = c.asString

  case class NewImplementation (f: Double) extends CanBeString {
    def asString = s"{f}"
  }

  println(testAsFunc(NewImplementation(1.002))) // this works fine!
  println(testAsFunc(1)) // this sadly does not.
}

这样的事情可能吗?我最近才发现类型类的主题,所以我知道我在这里要求的可能是可能的,但只是不明智的 - 如果是这样,请插话并让我知道更好的习惯用法可能是什么。

提前致谢,事后也致谢!

最佳答案

例如,您可以有两个重载版本的 testAsFunc(OOP 样式和类型类样式)

object Test {
  ...

  def testAsFunc(c: CanBeString): String = c.asString
  def testAsFunc[C: ConvertsToString](c: C): String = c.asString

  println(testAsFunc(NewImplementation(1.002))) // {f}
  println(testAsFunc(1)) // 1
}

或者,如果您希望拥有唯一的testAsFunc,那么您可以为要实现的特征的子类型添加类型类的实例

object ConvertsToStringInstances {
  implicit val intConvertsToString: ConvertsToString[Int] = ...

  implicit def canBeStringSubtypeConvertsToString[A <: CanBeString]: ConvertsToString[A] =
    new ConvertsToString[A] {
      override def asString(value: A): String = value.asString
    }
}

object Test {
  ...

  def testAsFunc[C: ConvertsToString](c: C): String = c.asString

  println(testAsFunc(NewImplementation(1.002))) // {f}
  println(testAsFunc(1)) // 1
}

请注意,如果对于 c 来说,同时存在 OOP-ish c.asString 和扩展方法 c.asString ,那么只有第一个实际上被调用了。

关于scala - 是否可以使用类型类来实现特征?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63545443/

相关文章:

haskell - 我该如何解决这种类型类歧义?

伴随对象中的Scala隐式Numeric [T]

Scala 隐式转换apply 方法

Scala:覆盖返回 null 的通用 Java 方法

haskell - 同类型类的两个实例为同一个类型

windows - 安装 scala-2.9.2.msi 后 scala 目录中没有 sbaz(在 Windows 上)

haskell - 在 Haskell 中,Ord 和 Enum 有时不兼容吗?

scala - 如何在 Scala 中将元组隐式转换为向量

scala - 使用 scala.tools.nsc.Global 解析 Scala 源代码

scala - 如何通过名称作为ActorRef获得Akka Actor ?