Scala泛型类型和隐式类型类

标签 scala typeclass implicit

我试图理解 scala 隐式及其在类型类中的用法。 我有一个通用特征 FromString 和一个为标准类型定义 FromString 隐式实例的伴生对象,如下所示:

file: /src/main/scala/util/FromString.scala

package util
trait FromString[A] {
    def fromString(string: String): A
}

object FromString {
    def toFromString[T](p: String => T): FromString[T] = new FromString[T] {
        def fromString(x: String): T = p(x);
    }

    implicit val IntFromString = toFromString[Int](_.toInt);
    implicit val ByteFromString = toFromString[Byte](_.toByte);
    implicit val LongFromString = toFromString[Long](_.toLong);
    implicit val ShortFromString = toFromString[Short](_.toShort);
    implicit val FloatFromString = toFromString[Float](_.toFloat);
    implicit val DoubleFromString = toFromString[Double](_.toDouble);
    implicit val BooleanFromString = toFromString[Boolean](_.toBoolean);
    implicit val IntListFromString = toFromString[List[Int]](_.split(',').map(_.toInt).toList);

    def convertFromString[A](string: String)(implicit e: FromString[A]): A = e.fromString(string)
}

现在我可以使用FromString对象的convertFromString函数将字符串转换为标准类型,如下所示。这可以正确运行。

file: /src/main/scala/top/Main1.scala

package top
import util.FromString._
object Main {
    def main(args: Array[String]): Unit = {
        val d = convertFromString[Double]("4.5");
        val i = convertFromString[Int]("42");
        val li = convertFromString[List[Int]]("1,2,3");
        println(s"d=$d i=$i li=$li");
    }
}

但是,当我尝试使用泛型类中的相同内容时,如下所示,会导致错误无法找到参数 e: util.FromString[T] 的隐式值

file: /src/main/scala/util/Knob.scala

package util
import FromString._ 
class Knob[T](val name: String, default: T){
    var value: T = default;

    def update(valstr: String) {
        value = convertFromString[T](valstr);
    }
}

file: /src/main/scala/top/Main2.scala

package top
import util.Knob
import util.FromString._
object Main {
    def main(args: Array[String]): Unit = {
        val width = new Knob[Int]("Width",  3);
        width.update("100");
        println(s"width=$width");
    }
}

隐式是在对象中定义的,我猜测它们也在范围中可用。

最佳答案

具体类型Int仅在行中已知

val width = new Knob[Int]("Width",  3);

在此行之前,编译器不知道 T 类型是什么,并且无法在任何地方找到并插入 IntFromString 作为隐式参数。因此,您必须将 IntFromStringmain 中的调用站点传递到 Knob.update 中的使用站点。为此,只需将 FromString 类型类添加到 T:

class Knob[T: FromString](val name: String, default: T) {
  ...
}

使用泛型类型和类型类进行编程时的一般规则:具体类型类实例必须插入“世界的尽头”,即固定泛型类型参数(如 T)的行中并成为具体类型(如Int)。您必须将这些类型类实例从可以确定具体类型的站点一路传递到使用类型类实例的通用代码。


trait FromString[A] {
  def fromString(string: String): A
}

object FromString {
    def toFromString[T](p: String => T): FromString[T] = new FromString[T] {
        def fromString(x: String): T = p(x);
    }

    implicit val IntFromString = toFromString[Int](_.toInt);
    implicit val ByteFromString = toFromString[Byte](_.toByte);
    implicit val LongFromString = toFromString[Long](_.toLong);
    implicit val ShortFromString = toFromString[Short](_.toShort);
    implicit val FloatFromString = toFromString[Float](_.toFloat);
    implicit val DoubleFromString = toFromString[Double](_.toDouble);
    implicit val BooleanFromString = toFromString[Boolean](_.toBoolean);
    implicit val IntListFromString = toFromString[List[Int]](_.split(',').map(_.toInt).toList);

    def convertFromString[A](string: String)(implicit e: FromString[A]): A = e.fromString(string)
}

import FromString._

class Knob[T: FromString](val name: String, default: T) {
    var value: T = default

    def update(valstr: String) {
        value = convertFromString[T](valstr)
    }
}

object Main {
    def main(args: Array[String]): Unit = {

        val d = convertFromString[Double]("4.5");
        val i = convertFromString[Int]("42");
        val li = convertFromString[List[Int]]("1,2,3");
        println(s"d=$d i=$i li=$li");


        val width = new Knob[Int]("Width",  3)
        width.update("100")
        println(s"width=$width")
    }
}

关于Scala泛型类型和隐式类型类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50817600/

相关文章:

scala - Spark:使用Scala进行HBase批量加载

java - Scala 中的泛型类型

scala - Scala 在解析隐式时如何使用显式类型?

Haskell Data.List.Class 和语法

haskell - 在 Haskell 中为自定义数据类型创建 Eq 实例

scala - 用 `type` 参数声明一个函数 `implicit`

scala - Doobie 无法找到或构造类型 T 的 Read 实例

scala - 在 Scala 和 Tomcat 中使用 TriMap 的潜在内存泄漏

scala - HList的证据保全LUB约束

scala - "can' t 存在性抽象参数化类型..."