2010-05-20 83 views
6

我一直在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))) 

給出了這樣的錯誤:
類型不匹配;
找到:(Point,Point)=> Int
required:(Any,Point)=>任何

我對這兩個錯誤消息非常困惑。如果有人能更清楚地解釋我做錯了什麼,我會非常感激。是的,我發現第二個錯誤說我需要輸入「Any」,但我不明白如何實施可以根據需要進行更改的更改。顯然,簡單地將「a:Point」改爲「a:Any」不是一個可行的解決方案,所以我錯過了什麼?

回答

6

類型的reduceLeftreduceLeft[B >: A](op: (B, A) => B): BAPoint,而你正試圖將其應用到(a: Point, b: Point) => (Math.min(a.x, b.x))

的編譯原因:Math.min(a.x, b.x)返回Int,所以Int必須是B的子類型,並且B也必須是超類型Point。爲什麼?B是累加器的類型,並且其初始值是您的Polygon中的第一個Point。這就是B >: A的含義。

IntPoint的唯一超類型是Any;因此BAnyop的類型應爲(Any, Point) => Any,就像錯誤消息所述。

+0

好的......我認爲我其實已經明白這一點。感謝您的解釋! – klactose 2010-05-20 07:24:55

2

這是斯卡拉2.8.0.RC2

scala> abstract class Shape 
defined class Shape 

scala> case class Point(x: Int, y: Int) extends Shape 
defined class Point 

scala> case class Polygon(points: Point*) extends Shape 
defined class Polygon 

scala> val poly = new Polygon(new Point(2,5), new Point(7,0), new Point(3,1)) 
poly: Polygon = Polygon(WrappedArray(Point(2,5), Point(7,0), Point(3,1))) 

scala> val upperLeftX = poly.points.reduceLeft((a:Point,b:Point) => if (a.x < b.x) a else b) 
upperLeftX: Point = Point(2,5) 

reduceLeft這裏需要的類型(Point, Point) => Point的功能。 (更準確地說(B, Point) => BB有下界Point。在方法reduceLeftScaladoc

+0

這將返回一個點,但是在我的例子,我試圖返回一個int(最小的x座標爲精確)。我相信我的問題在於某種程度上是由於編譯器對於它應該返回的類型感到困惑。 更改您的代碼返回一個Int(這是我需要的): val upperLeftX = poly.points.reduceLeft((a:Point,b:Point)=> if(ax klactose 2010-05-20 06:27:24

+0

只需試試這一個然後:'val upperLeftX = poly.points.reduceLeft((a,b)=> if(ax 2010-05-20 06:32:04

+1

for scala2.8: val upperLeftX = poly.points.map(_。x).min – Eastsun 2010-05-20 06:32:04

2

另一種替代方法是poly.points.foldLeft(Int.MaxValue)((b, a) => Math.min(b, a.x)),它也應該與Scala 2.7.x一起使用。相比reduceLeft版本的差異

  • 你有一個初始值(在我們的例子Int.MaxValue,任何真實的數據將小於或等於本)
  • 有元素的類型之間沒有約束結果的類型,如reduceLeft的下限約束 儘管如此,Eastsun的解決方案更加優雅。

順便說一句,如果你已經有案例類,你可以省略新的關鍵字,並且可以在伴隨對象中使用自動生成的工廠方法。所以創建多邊形的線變爲val poly = Polygon(Point(2,5), Point(7,0), Point(3,1)),這有點容易閱讀。

+0

謝謝,我會記住關於新關鍵字的信息 – klactose 2010-05-20 07:27:04

+0

@Rahul:感謝您的更正。我很快找到了,但找不到它:-) – 2010-05-20 10:49:40

1

我看到大家似乎都鎖定到第二片斷,所以我會回答第一個:

val upperLeftX = poly.points.reduceLeft(Math.min(_.x, _.x)) 

你打算是指這樣的:

val upperLeftX = poly.points.reduceLeft((a, b) => Math.min(a.x, b.x)) 

然而,這不是下劃線是如何工作的。下劃線有很多含義,但其中兩個在這裏相關。

首先,它可能意味着一個局部的功能應用。例如,Math.min(_, 0)部分適用的參數min,並返回適用其餘的功能。換句話說,它相當於x => Math.min(x, 0),忽略了類型註釋。無論如何,這個意義只有申請如果下劃線是全部由自己在參數中的一個(或多個)的地方。

然而,這是不是在你的情況爲例,因爲你的底線後加了.x。如果下劃線出現在任何類型的表達式中(例如您的示例中的方法調用),則該下劃線是匿名函數中參數的佔位符。

在這第二層意思是尤爲重要的是瞭解匿名函數的邊界。具體來說,匿名函數將由最內括號或括號括起來的括號或任何逗號分隔。現在

,應用該規則的第一個片段的表達意味着剪斷由編譯器這樣的看出:

val upperLeftX = poly.points.reduceLeft(Math.min(a => a.x, b => b.x)) 

所以,這裏有兩個問題。首先,你將兩個函數傳遞給min而不是兩個雙打。其次,因爲min不期望接收函數,所以編譯器無法推斷出這些函數的類型可能是什麼。因爲你沒有提供有關的各類ab以上的任何信息,它抱怨說。

如果你沒有提供這種類型的錯誤信息會是這樣的:

<console>:6: error: type mismatch; 
found : Int 
required: ?{val x: ?}