2016-07-08 57 views
2

我讀馬丁Odersky的有關Scala的類型系統的面試,以下一直說確定型結構在斯卡拉

其中一個方面,其中,Scala是比Java更具有表現力的是,它可以讓你表達這些東西。在Scala中,可能有這樣一種類型:使用close方法的任何參數都不帶參數並返回Unit(與Java中的void類似)。您也可以將其與其他約束條件結合使用。你可以說:任何從特定類繼承的東西,此外還有這些具有這些簽名的特定方法。或者你可以說:從這個類繼承的任何東西都有一個特定類型的內部類。從本質上講,可以通過說明類型中需要的內容來結構化表徵類型,以便可以使用它們。

有人可以在Scala中編寫代碼片段來展示如何在結構上表徵類型?看完後,我有一種感覺,我應該能夠做到以下幾點:

type CanClose { def close: Unit } 
val closeableFile: CanClose = new File() 
val closeableStream: CanClose = new Stream() 
+0

他談論的是結構類型。谷歌的「斯卡拉結構類型」,你會發現更多的信息。 – Jesper

+0

關於你的例子:它應該是'type CanClose = {def close:unit}'(注意'='),如果用'File'表示'java.io.File',它沒有'close '方法。 – Jesper

回答

4

在Scala中,一個類型可以通過它的結構來標識,從而實現了它通常被稱爲鴨子打字的功能。

下面是一個例子

scala> def close(x: { def close: Unit }): Unit = x.close 
warning: there was one feature warning; re-run with -feature for details 
close: (x: AnyRef{def close: Unit})Unit 

scala> class CanBeClosed { 
    | def close: Unit = println("I'm closed now") 
    | } 
defined class CanBeClosed 

scala> class CannotBeClosed { 
    | } 
defined class CannotBeClosed 

scala> close(new CanBeClosed) 
I'm closed now 

scala> close(new CannotBeClosed) 
<console>:13: error: type mismatch; 
found : CannotBeClosed 
required: AnyRef{def close: Unit} 
     close(new CannotBeClosed) 

然而,需要注意的是結構類型是通過運行時反射來實現是很重要的,所以它可以影響性能。

這就是爲什麼你得到的第一個定義警告(你可以沉默通過導入import scala.language.reflectiveCalls警告)

+0

我認爲2.12切換到'MethodHandles'和'invokedynamic',所以性能損失應該幾乎消除。 –

1

馬丁在談論Structural Types。這意味着你可以這樣做:

scala> def anythingThatIsClosable(foo: { def close: Unit }): Unit = foo.close 
anythingThatIsClosable: (foo: AnyRef{def close: Unit})Unit 

scala> class ICanCloseResources { 
    | def close = println("yay closed") 
    | } 
defined class ICanCloseResources 

scala> anythingThatIsClosable(new ICanCloseResources()) 
yay closed 

我們只定義了我們如何指望類型的行爲結構,我們並不需要真正繼承任何通用的接口,像Java需要。

在你的例子中,java.io.File沒有實現close()方法,所以這將不起作用,但任何其他類型堅持該方法簽名將。需要注意的一件重要事情是,在引擎蓋下,這需要Scala推遲到reflection,因此可能會有很高的成本。