簽章 (F#)
簽章檔包含一組 F# 程式項目 (例如型別、命名空間和模組) 的公用簽章資訊,可用於指定這些程式項目的存取範圍。
備註
每個 F# 程式碼檔都可以有一個「簽章檔」(Signature File),這個檔案名稱與程式碼檔名稱相同,但是副檔名為 .fsi 而不是 .fs。如果您直接使用命令列,也可以將簽章檔加入至編譯命令列。為區分程式碼檔和簽章檔,程式碼檔有時也稱為「實作檔」(Implementation File)。在專案中,簽章檔應該在相關聯之程式碼檔案的前面。
簽章檔會描述相對應實作檔中的命名空間、模組、型別和成員。您可以使用簽章檔中的資訊,指定相對應實作檔案中的哪些程式碼部分可以從實作檔外部的程式碼存取,以及哪些部分僅供實作檔內部使用。簽章檔包含的命名空間、模組和型別必須是實作檔中包含之命名空間、模組和型別的子集。除了本主題稍後註明的某些例外,對於實作檔而言,未列在簽章檔中的語言項目會視為私用項目。如果專案或命令列中找不到簽章檔,則會使用預設的存取範圍。
如需預設存取範圍的詳細資訊,請參閱存取控制 (F#)。
在簽章檔中,您不必重複型別定義以及每個方法或函式的實作,而是使用每個方法和函式的簽章,做為模組或命名空間片段所實作之功能的完整規格。型別簽章的語法與介面和抽象類別中抽象方法宣告所使用的語法相同,而且當顯示正確編譯的輸入時,IntelliSense 和 F# 解譯器 fsi.exe 也會顯示此語法。
如果型別簽章中的資訊不足,無法表示型別是否已密封或是否為介面型別時,您必須加入屬性,告知編譯器型別的本質。下表描述做為此用途的屬性。
屬性 |
描述 |
---|---|
[<Sealed>] |
適用於沒有抽象成員或不應擴充的型別。 |
[<Interface>] |
適用於本身為介面的型別。 |
如果簽章和實作檔中宣告之間的屬性不一致,編譯器會產生錯誤。
請使用關鍵字 val 為值或函式值建立簽章。type 關鍵字會加入型別簽章。
您可以使用 --sig 編譯器選項來產生簽章檔。您通常不會手動撰寫 .fsi 檔案,而是使用編譯器產生 .fsi 檔案,將檔案加入至專案 (如果有的話),以及移除不開放存取的方法和函式來編輯檔案。
型別簽章的數個規則如下:
實作檔中的型別縮寫不得符合沒有簽章檔中之縮寫的型別。
記錄和已區分的聯集必須公開其全部的欄位和建構函式,或完全不公開,而且簽章中的順序必須符合實作檔中的順序。類別可以在簽章中顯示其部分或全部的欄位和方法,或完全不顯示。
具有建構函式的類別和結構必須公開其基底類別的宣告 (inherits 宣告)。此外,具有建構函式的類別和結構也必須公開其所有抽象方法和介面宣告。
介面型別必須顯示其所有方法和介面。
值簽章的規則如下:
存取範圍的修飾詞 (public、internal 等等) 以及簽章中的 inline 和 mutable 修飾詞必須符合實作中的修飾詞。
泛型型別參數 (隱含推斷或明確宣告) 的數目必須符合,而且泛型型別參數中的型別和型別條件約束也必須符合。
如果使用 Literal 屬性,它必須同時出現在簽章和實作中,而且兩個都要使用相同的常值。
簽章和實作的參數模式 (也稱為 Arity) 必須一致。
在下列程式碼範例中,會示範如何使用具有命名空間、模組、函式值,以及包含適當屬性之型別簽章的簽章檔案。其中也示範對應的實作檔案。
// Module1.fsi
namespace Library1
module Module1 =
val function1 : int -> int
type Type1 =
new : unit -> Type1
member method1 : unit -> unit
member method2 : unit -> unit
[<Sealed>]
type Type2 =
new : unit -> Type2
member method1 : unit -> unit
member method2 : unit -> unit
[<Interface>]
type InterfaceType1 =
abstract member method1 : int -> int
abstract member method2 : string -> unit
下列程式碼顯示實作檔。
namespace Library1
module Module1 =
let function1 x = x + 1
type Type1() =
member type1.method1() =
printfn "test1.method1"
member type1.method2() =
printfn "test1.method2"
[<Sealed>]
type Type2() =
member type2.method1() =
printfn "test1.method1"
member type1.method2() =
printfn "test1.method2"
[<Interface>]
type InterfaceType1 =
abstract member method1 : int -> int
abstract member method2 : string -> unit