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