當前位置:
首頁 > 最新 > Scala 類型的類型

Scala 類型的類型

結構類型(Strucural Types)經常被描述為「類型安全的鴨子類型(duck typing)」,如果你想獲得一個直觀的理解,這是一個很好的比較。

迄今為止,我們在類型方面考慮的都是這樣的問題:「它實現了介面 X 嗎?」,有了「結構類型」,我們就可以深入一步,開始對一個指定對象的結構(因此得名)進行推理。當我們在檢查一個採用了結構類型的類型匹配問題時,我們需要把問題改為:「這裡存在帶有這種簽名的方法嗎?」。

讓我們舉一個很常見的例子,來看看它為什麼如此強大。想像你有很多支持被closed的東西,在 Java 里,通常會實現 介面,以便寫出一些常用的 工具類(事實上,Google Guava就有這樣的一個類)。現在再想像有人還實現了一個 類,但沒有實現 。由於靜態類型的緣故,你的 類庫就會出問題,你就不能傳 的實例給它。讓我們使用結構類型來解決這個問題:

it s body is: { def close(): Unit } class MyOwnCloseable{ def close(): Unit = () } // method taking a Structural Type def closeQuietly(closeable: { def close(): Unit }) = try { closeable.close() } catch { case ex: Exception => // ignore... } // accepts a java.io.File (implements Closeable): closeQuietly(new StringReader("example")) // accepts a MyOwnCloseable closeQuietly(new MyOwnCloseable)

這個結構類型被作為方法的一個參數。基本上可以說,我們對這個類型唯一的期望就是它應該存在內部( )這樣一個方法。它可以擁有更多的方法,因此這裡並不是一個完全匹配,而是這個類型必須定義最小的一組方法,這樣才能有效。

另外需要注意的是,使用結構類型對運行時性能存在很大的負面影響,因為實際上它是通過反射實現的。我們這裡不再通過位元組碼來調研了,記住查看 scala (或 java)類生成的位元組碼是一件很容易的事情,只需使用 :javap in the Scala REPL ,所以你應該自己試一試。

在我們進入下一個話題之前,再來講一種精鍊的使用風格。想像你的結構類型相當的豐富,比如是一個代表某種事物的類型,你可以打開它,使用它,然後必須關閉。通過使用「類型別名」(在另一部分中有詳細描述)與「結構類型」,我們就可以將類型定義與方法分離,做法如下:

type OpenerCloser= { def open(): Unit def close(): Unit } def on(it: OpenerCloser)(fun: OpenerCloser => Unit) = { it.open() fun(it) it.close() }

通過使用這樣一個類型別名, 的部分變得更加清晰了。我極力推薦這種「對更大的結構類型採用類型別名」的做法,同時也最後提醒大家,確認自己是否真的沒有其它辦法了,再決定採用結構類型。你需要多考慮它負面的性能影響。

22. 路徑依賴類型

這個類型(Path Dependent Type)允許我們對類型內部的類型進行「類型檢查」,這看起來似乎比較奇怪,但下面的例子非常直觀:

created from inside of Outer val out2 = new Outer val out2in = new out2.Inner // another instance of Inner, with the enclosing instance out2 // the path dependent type. The "path" is "inside out1". type PathDep1= out1.Inner // type checks val typeChecksOk: PathDep1 = out1in // OK val typeCheckFails: PathDep1 = out2in // :27: error: type mismatch; // found : out2.Inner // required: PathDep1 // (which expands to) out1.Inner // val typeCheckFails: PathDep1 = out2in

這裡你可以理解為「每個外部類都有自己的內部類」。所以它們是不同的類型 — 差異取決於我們使用哪種路徑獲得。

使用這種類型很有用,我們能夠強制從一個具體參數的內部去獲得類型。一個具體的採用該類型的簽名如下:

class Parent{ class Child } class ChildrenContainer(p:Parent){ type ChildOfThisParent= p.Child def add(c: ChildOfThisParent) = ??? }

我們現在使用的路徑依賴類型,已經被編碼到了類型系統的邏輯中。這個容器應該只包含這個 的 對象,而不是任何 。

我們將很快在章節中看到如何引入任何一個 的 對象。

23. 類型投影

類型投影(Type Projections)類似「路徑依賴類型」,它們允許你引用一個內部類的類型。在語法上看,你可以組織內部類的路徑結構,然後通過 符號分離開來。我們先來看看這些路徑依賴類型( 語法)和類型投影( 語法)的第一個且主要的差別:

另一個準確的直覺是相比「路徑依賴」,「類型投影」可以用於「類型層面的編程」,如 (存在類型)Existential Types。

「存在類型」是跟「類型擦除」密切相關的東西。

val thingy: Any = ??, matches all types... what type is a ?! }

因為運行時類型被擦除了,所以我們不知道 的類型。我們知道 List 是一個類型構造器 ,所以肯定有某個類型,它可以用來構造一個有效的 。這個「某個類型」,就是存在類型

Scala 為它提供了一種快捷方式:

假設你在使用一些抽象類型成員,在我們的例子中將會是一些 Monad 。我們想要強制我們的使用者只能使用這個 Monad 中的 實例,因為比如我們的 Monad 只有針對這些類型才有意義。我們可以通過這些存在類型 T的類型邊界來實現:

type Monad[T]forSome{ type T>: Cool }譯者註:

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 推酷 的精彩文章:

無人便利店會開到像7-Eleven一樣嗎?
PHP HTTP 客戶端 Guzzle 原理解析
大數據要怎麼用,12名創業者這樣說
三星Note 8手機渲染圖曝光:顏值超S8
請原諒我噴你,但是你噁心到我了

TAG:推酷 |

您可能感興趣

Perl 數據類型
Redis 數據類型
opencv Mat類型和BYTE*指針類型互轉
scala學習-泛型、界定、形變、this.type、複合類型、抽象類型
Swift 類型轉換
Kotlin 基本數據類型
Chrome 66 新特性:CSS 類型對象模型,非同步剪貼板 API,AudioWorklet,等
Mariadb學習總結(三):數據類型
Hibernate 映射枚舉Enum 類型的屬性
python基礎數據類型
Adobe Reader類型混淆導致代碼執行漏洞分析
Redis五種數據類型詳解
Redis數據類型詳解
solidity之地址類型
EF Core的三種主要關係類型
Facebook創建另類AI,可完美轉換音樂類型
Python數據類型、運算符、變數
Kotlin技術分享:類型的檢查與轉換
「Python」Chapter1 變數和簡單數據類型
鄭爽VS Angel baby 鹿晗VS易烊千璽,同類型綜藝