Универсальный тип Scala и класс неявного типа - PullRequest
0 голосов
/ 12 июня 2018

Я пытаюсь понять последствия 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)
}

Теперь я могу использовать функцию convertFromString объекта FromString для преобразования строки в стандартные типы, как показанониже.Это работает правильно.

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");
    }
}

Однако, когда я пытаюсь использовать ту же вещь из универсального класса, как показано ниже, это приводит к ошибке could not find implicit value for parameter 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");
    }
}

последствия определены в объекте, и я предполагаю, что они также доступны в области видимости.

1 Ответ

0 голосов
/ 12 июня 2018

Тип бетона Int известен только в строке

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

. Перед этой строкой компилятор не знает, какой будет тип T, и не может найти и вставить IntFromString как неявный аргумент в любом месте.Таким образом, вы должны передать IntFromString с сайта вызова в main на сайт использования в 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")
    }
}
...