问题描述
我正在编写一个小型Scala程序,该程序应该:
I am writing a small Scala Program which should:
- 从本地FS逐行读取文件
- 从每一行中解析三个双精度值
- 根据这三个值创建案例类的实例
- 将这些实例传递到二进制堆
为了能够将String
解析为Double
和CoordinatePoint
,我想出了以下特征:
To be able to parse String
s to both Double
s and CoordinatePoint
s I've came up with this trait:
trait Parseable[T] {
def parse(input: String): Either[String, T]
}
并且我为后者提供了许多类型对象实现:
and I have a number of type object implementations for the latter:
object Parseable {
implicit val parseDouble: Parseable[Double] = new Parseable[Double] {
override def parse(input: String): Either[String, Double] = {
val simplifiedInput = input.replaceAll("[ \\n]", "").toLowerCase
try Right(simplifiedInput.toDouble) catch {
case _: NumberFormatException =>
Left(input)
}
}
}
implicit val parseInt: Parseable[Int] = new Parseable[Int] {
override def parse(input: String): Either[String, Int] = {
val simplifiedInput = input.replaceAll("[ \\n]", "").toLowerCase
try Right(simplifiedInput.toInt) catch {
case _: NumberFormatException =>
Left(input)
}
}
}
implicit val parseCoordinatePoint: Parseable[CoordinatePoint] = new Parseable[CoordinatePoint] {
override def parse(input: String): Either[String, CoordinatePoint] = {
val simplifiedInput = input.replaceAll("[ \\n]", "").toLowerCase
val unparsedPoints: List[String] = simplifiedInput.split(",").toList
val eithers: List[Either[String, Double]] = unparsedPoints.map(parseDouble.parse)
val sequence: Either[String, List[Double]] = eithers.sequence
sequence match {
case Left(value) => Left(value)
case Right(doublePoints) => Right(CoordinatePoint(doublePoints.head, doublePoints(1), doublePoints(2)))
}
}
}
}
我有一个公共对象,该对象将调用委派给相应的隐式Parseable
(在同一文件中):
I have a common object that delegates the call to a corresponding implicit Parseable
(in the same file):
object InputParser {
def parse[T](input: String)(implicit p: Parseable[T]): Either[String, T] = p.parse(input)
}
仅供参考-这是CoordinatePoint
案例类:
and just for reference - this is the CoordinatePoint
case class:
case class CoordinatePoint(x: Double, y: Double, z: Double)
在我的主程序中(确认文件在那里,并且不为空,等等.)我想将每一行转换为CoordinatePoint
的实例,如下所示:
In my main program (after having validated that the file is there, and is not empty, etc..) I want to transform each line into an instance of CoordinatePoint
as follows:
import Parseable._
import CoordinatePoint._
...
private val bufferedReader = new BufferedReader(new FileReader(fileName))
private val streamOfMaybeCoordinatePoints: Stream[Either[String, CoordinatePoint]] = Stream
.continually(bufferedReader.readLine())
.takeWhile(_ != null)
.map(InputParser.parse(_))
我得到的错误是:
[error] /home/vgorcinschi/data/eclipseProjects/Algorithms/Chapter 2 Sorting/algorithms2_1/src/main/scala/ca/vgorcinschi/algorithms2_4/selectionfilter/SelectionFilter.scala:42:27: ambiguous implicit values:
[error] both value parseDouble in object Parseable of type => ca.vgorcinschi.algorithms2_4.selectionfilter.Parseable[Double]
[error] and value parseInt in object Parseable of type => ca.vgorcinschi.algorithms2_4.selectionfilter.Parseable[Int]
[error] match expected type ca.vgorcinschi.algorithms2_4.selectionfilter.Parseable[T]
[error] .map(InputParser.parse(_))
[error] ^
[error] one error found
[error] (Compile / compileIncremental) Compilation failed
[error] Total time: 1 s, completed Sep 1, 2020 10:38:18 PM
我不明白,也不知道在哪里寻找编译器为何找到Parseable[Int]
和Parseable[Double]
,但是找不到唯一的一个-Parseable[CoordinatePoint]
.
I don't understand nor know where to look for why is the compiler finding Parseable[Int]
and Parseable[Double]
but not the only right one - Parseable[CoordinatePoint]
.
所以我想,好的,让我先指定一下转换函数来帮助编译器:
So I thought, ok let me give the compiler a hand by specifying the transformation function from beforehand:
private val bufferedReader = new BufferedReader(new FileReader(fileName))
val stringTransformer: String => Either[String, CoordinatePoint] = s => InputParser.parse(s)
private val streamOfMaybeCoordinatePoints: Stream[Either[String, CoordinatePoint]] = Stream
.continually(bufferedReader.readLine())
.takeWhile(_ != null)
.map(stringTransformer)
可惜这只是在函数声明中的代码上方产生了相同的错误.
Alas this yields the same error just a bit up the code - in the function declaration.
我很想知道是什么导致了这种行为.既要纠正代码又要获取个人知识.在这一点上,我很好奇.
I would love to learn what is that that causes such behavior. Both to rectify the code and for personal knowledge. At this point I am very curious.
推荐答案
一个解决方法是显式指定参数类型
One fix is to specify type prameter explicitly
InputParser.parse[CoordinatePoint](_)
另一个是优先考虑隐式.例如
Another is to prioritize implicits. For example
trait LowPriorityParseable1 {
implicit val parseInt: Parseable[Int] = ...
}
trait LowPriorityParseable extends LowPriorityParseable1 {
implicit val parseDouble: Parseable[Double] = ...
}
object Parseable extends LowPriorityParseable {
implicit val parseCoordinatePoint: Parseable[CoordinatePoint] = ...
}
顺便说一句,由于您将隐式对象放入了同伴对象中,因此现在导入它们并没有多大意义.
By the way, since you put implicits into the companion object it doesn't make much sense now to import them.
在的呼叫站点
object InputParser {
def parse[T](input: String)(implicit p: Parseable[T]): Either[String, T] = p.parse(input)
}
推断
类型参数T
(如果未明确指定)不早于解析隐式(类型推断和隐式解析相互影响).否则以下代码将无法编译
type parameter T
is inferred (if not specified explicitly) not before the implicit is resolved (type inference and implicit resolution make impact on each other). Otherwise the following code wouldn't compile
trait TC[A]
object TC {
implicit val theOnlyImplicit: TC[Int] = null
}
def materializeTC[A]()(implicit tc: TC[A]): TC[A] = tc
materializeTC() // compiles, A is inferred as Int
因此,在隐式解析过程中,编译器将尝试尽早推断类型(否则,在具有TC
的示例中,类型A
会被推断为Nothing
,而不会找到隐式).顺便说一句,隐式转换是一个例外,编译器将尝试隐式转换(也会带来麻烦)
So during implicit resolution compiler tries to infer types not too early (otherwise in the example with TC
type A
would be inferred as Nothing
and implicit wouldn't be found). By the way, an exception is implicit conversions where compiler tries to infer types eagerly (sometimes this can make troubles too)
// try to infer implicit parameters immediately in order to:
// 1) guide type inference for implicit views
// 2) discard ineligible views right away instead of risking spurious ambiguous implicits
这篇关于Scala:“含糊的隐式值",但找不到正确的值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!