需要帮助找出 Scala 编译器错误
我一直在用 scala 开发一个项目,但是我收到了一些我不太理解的错误消息。我正在使用的课程相对简单。 例如:
abstract class Shape
case class Point(x: Int, y: Int) extends Shape
case class Polygon(points: Point*) extends Shape
现在假设我创建一个多边形:
val poly = new Polygon(new Point(2,5), new Point(7,0), new Point(3,1))
然后,如果我尝试确定可能包含该多边形的最小可能矩形的位置和大小,我会收到各种我不太理解的错误。
以下是不同尝试的片段以及它们产生的相应错误消息。
val upperLeftX = poly.points.reduceLeft(Math.min(_.x, _.x))
给出错误:
“扩展函数缺少参数类型 ((x$1) => x$1.x)”
val upperLeftX =
poly.points.reduceLeft((a: Point, b: Point) => (Math.min(a.x, b.x)))
给出以下错误:
“类型不匹配;
发现:(点,点)=>国际
必填:(任意,点)=> Any”
我对这两个错误消息感到非常困惑。如果有人能更清楚地解释我做错了什么,我将非常感激。是的,我看到第二个错误说我需要输入“Any” ”但我不明白如何实施一个可以根据需要进行的更改。显然,简单地将“a:Point”更改为“a:Any”并不是一个可行的解决方案,那么我错过了什么?
I have been working on a project in scala, but I am getting some error messages that I don't quite understand. The classes that I am working with are relatively simple.
For example:
abstract class Shape
case class Point(x: Int, y: Int) extends Shape
case class Polygon(points: Point*) extends Shape
Now suppose that I create a Polygon:
val poly = new Polygon(new Point(2,5), new Point(7,0), new Point(3,1))
Then if I attempt to determine the location and size of the smallest possible rectangle that could contain the polygon, I get various errors that I don't quite understand.
Below are snippets of different attempts and the corresponding error messages that they produce.
val upperLeftX = poly.points.reduceLeft(Math.min(_.x, _.x))
Gives the error:
"missing parameter type for expanded function ((x$1) => x$1.x)"
val upperLeftX =
poly.points.reduceLeft((a: Point, b: Point) => (Math.min(a.x, b.x)))
Gives this error:
"type mismatch;
found : (Point, Point) => Int
required: (Any, Point) => Any"
I am very confused about both of these error messages. If anyone could explain more clearly what I am doing incorrectly, I would really appreciate it. Yes, I see that the second error says that I need type "Any" but I don't understand exactly how to implement a change that would work as I need it. Obviously simply changing "a: Point" to "a: Any" is not a viable solution, so what am I missing?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
reduceLeft
的类型为reduceLeft[B >: A](op: (B, A) => B): B
,A
是Point
,并且您尝试将其应用于(a: Point, b: Point) =>; (Math.min(ax,bx))
。编译器的推理如下:
Math.min(ax, bx)
返回Int
,因此Int
必须是B
的子类型代码>.并且B
也必须是Point
的超类型。为什么?B
是累加器的类型,其初始值是Polygon
中的第一个Point
。这就是B>:A
的含义。Int
和Point
的唯一超类型是Any
;所以B
是Any
并且op
的类型应该是(Any, Point) =>;任何
,正如错误消息所示。The type of
reduceLeft
isreduceLeft[B >: A](op: (B, A) => B): B
,A
isPoint
, and you are trying to apply it to(a: Point, b: Point) => (Math.min(a.x, b.x))
.The compiler reasons thus:
Math.min(a.x, b.x)
returnsInt
, soInt
must be a subtype ofB
. AndB
must also be a supertype ofPoint
. Why?B
is the type of the accumulator, and its initial value is the firstPoint
in yourPolygon
. That's the meaning ofB >: A
.The only supertype of
Int
andPoint
isAny
; soB
isAny
and the type ofop
should be(Any, Point) => Any
, just as the error message says.这是 Scala 2.8.0.RC2
reduceLeft
需要一个(Point, Point) => 类型的函数点
。 (更准确地说,(B, Point) => B
,其中B
的下界为Point
。请参阅 Scaladoc 方法减少左
。This is Scala 2.8.0.RC2
reduceLeft
requires here a function of the type(Point, Point) => Point
. (more precisely(B, Point) => B
withB
with a lower bound toPoint
. See Scaladoc at the methodreduceLeft
.另一种选择是poly.points.foldLeft(Int.MaxValue)((b, a) => Math.min(b, ax)),它也应该适用于 Scala 2.7.x。与reduceLeft版本相比,不同之处在于
不过Eastsun的解决方案更加优雅。
顺便说一句,如果您已经有了案例类,您可以省略 new 关键字,并且可以在伴随对象中使用自动生成的工厂方法。因此,创建多边形的线变为 val poly = Polygon(Point(2,5), Point(7,0), Point(3,1)),这更容易阅读。
Another alternative is
poly.points.foldLeft(Int.MaxValue)((b, a) => Math.min(b, a.x))
, which should also work with Scala 2.7.x. The differences compared to the reduceLeft version areInt.MaxValue
in our case, any real data will be smaller or equal to this)Nevertheless Eastsun's solution is more elegant.
BTW if you already have case classes you can ommit the new keyword, and can use the automatically generated factory method in the companion object. So the line creating the poly becomes
val poly = Polygon(Point(2,5), Point(7,0), Point(3,1))
, which is a bit easier to read.我看到每个人似乎都已经锁定了第二个片段,所以我将回答第一个片段:
您的意思是这样的:
但是,这不是下划线的工作原理。有很多含义需要强调,但其中有两个与这里相关。
首先,它可能意味着部分功能应用程序。例如,
Math.min(_, 0)
会将参数部分应用到min
,并返回一个应用其余参数的函数。换句话说,它相当于x => Math.min(x, 0)
,忽略类型注释。无论如何,只有当下划线单独代替一个(或多个)参数时,这一含义才适用。然而,您的示例中的情况并非如此,因为您在下划线后面添加了
.x
。如果下划线出现在任何类型的表达式中,例如示例中的方法调用,则该下划线是匿名函数中参数的占位符。在第二个含义中,理解匿名函数的边界尤为重要。具体来说,匿名函数将由最里面的括号或括起来的大括号或任何逗号分隔。
现在,将该规则应用于第一个片段中的表达式意味着编译器会像这样看到 snipper:
因此,这里有两个问题。首先,您将两个函数传递给
min
,而不是两个双精度数。其次,由于min
并不期望接收函数,因此编译器无法推断这些函数的类型。由于您没有提供有关上面a
和b
类型的任何信息,因此它会对此进行抱怨。如果您确实提供了此类类型,则错误消息将如下所示:
I see everyone seems to have latched onto the second snippet, so I'll answer the first one:
You intended that to mean this:
However, that's not how underscore works. There are many meanings to underscore, but two of them are relevant here.
First, it may mean a partial function application. For example,
Math.min(_, 0)
would partially apply the parameters tomin
, and return a function that apply the remaining ones. In other words, it is equivalent tox => Math.min(x, 0)
, ignoring the type annotations. At any rate, this meaning only applies if the underscore is all by itself in the place of one (or more) of the parameters.That, however, is not the case in your example, because you added a
.x
after the underscore. If the underscore appears in any kind of expression, such as the method call in your example, then that underscore is a placeholder for a parameter in an anonymous function.In this second meaning it is particularly important to understand the boundaries of the anonymous function. Specifically, the anonymous function will be delimited by the innermost parenthesis or curly brackets that encloses it, or by any comma.
Now, applying that rule to the expression in the first snippet means that snipper is seen by the compiler like this:
So, there are two problems here. First, you are passing two functions to
min
instead of two doubles. Second, becausemin
isn't expecting to receive functions, the compiler can't infer what the type of these functions might be. Since you did not provide any information about the types ofa
andb
above, it complains about that.If you did provide such types, the error message would be something like this: