Assinaturas (F#)
Um arquivo de assinatura contém informações sobre as assinaturas públicas de um conjunto de F# elementos do programa, como, por exemplo, módulos, tipos e namespaces. Ele pode ser usado para especificar a acessibilidade desses elementos de programa.
Comentários
Para cada F# arquivo de código, você pode ter um arquivo de assinatura, que é um arquivo que tem o mesmo nome que o arquivo de código, mas com o .fsi de extensão em vez de .fs. Arquivos de assinatura também podem ser adicionados à compilação de linha de comando se você estiver usando a linha de comando diretamente. Para diferenciar entre arquivos de código e arquivos de assinatura, arquivos de código às vezes são chamados de arquivos de implementação. Em um projeto, o arquivo de assinatura deve preceder o arquivo de código associado.
Um arquivo de assinatura descreve a namespaces, módulos, tipos e membros no arquivo de implementação correspondente. Use as informações em um arquivo de assinatura, para especificar quais partes do código na implementação correspondente arquivo pode ser acessado a partir do código fora do arquivo de implementação e que partes são internas para o arquivo de implementação. Os namespaces, módulos e tipos que são incluídos no arquivo de assinatura devem ser um subconjunto dos namespaces, módulos e tipos que são incluídos no arquivo de implementação. Com algumas exceções indicadas posteriormente neste tópico, esses elementos de linguagem que não estão listados no arquivo de assinatura são considerados particulares do arquivo de implementação. Se nenhum arquivo de assinatura for encontrado no projeto ou na linha de comando, a acessibilidade padrão é usada.
Para obter mais informações sobre a acessibilidade padrão, consulte Controle de acesso (F#).
Em um arquivo de assinatura, você não se repetem a definição dos tipos e as implementações de cada método ou função. Em vez disso, você deve usar a assinatura para cada método e a função, que atua como uma especificação completa a funcionalidade que é implementada por um fragmento de namespace ou módulo. A sintaxe de uma assinatura de tipo é o mesmo que usados em declarações de método abstract em interfaces e classes abstratas e também é mostrada a por IntelliSense e o FSI. exe F# interpretador quando exibe a entrada compilada corretamente.
Se não há informações suficientes na assinatura de tipo para indicar se um tipo é sealed, ou seja um tipo de interface, você deve adicionar um atributo que indica a natureza do tipo para o compilador. Os atributos que podem ser usados para esse fim são descritos na tabela a seguir.
Atributo |
Descrição |
---|---|
[<Sealed>] |
Para um tipo que não possui nenhum membro abstrato ou que não deve ser estendido. |
[<Interface>] |
Um tipo que é uma interface. |
O compilador produz um erro se os atributos não são consistentes entre a assinatura e a declaração no arquivo de implementação.
Use a palavra-chave val para criar uma assinatura para um valor ou o valor da função. A palavra-chave type apresenta uma assinatura de tipo.
Você pode gerar um arquivo de assinatura usando o --sig opção de compilador. Em geral, você não escreva .fsi arquivos manualmente. Em vez disso, você pode gerar arquivos de .fsi usando o compilador, adicioná-los ao seu projeto, se você tiver um e editá-los, removendo os métodos e as funções que você não deseja que sejam acessíveis.
Existem várias regras para assinaturas de tipo:
Abreviações de tipo em um arquivo de implementação não devem corresponder a um tipo sem uma abreviação em um arquivo de assinatura.
Registros e uniões discriminadas devem expor todos ou nenhum de seus campos e construtores e a ordem na assinatura deve corresponder a ordem no arquivo de implementação. Classes podem revelar alguns, todos ou nenhum de seus campos e métodos na assinatura.
Classes e estruturas que tem construtores devem expor as declarações de suas classes base (o inherits declaração). Além disso, classes e estruturas que tem construtores devem expor todos os métodos abstratos e as declarações da interface.
Tipos de interface devem revelar seus métodos e interfaces.
As regras para assinaturas de valor são os seguintes:
Modificadores de acessibilidade (public, internale assim por diante) e o inline e mutable modificadores na assinatura devem coincidir com aqueles na implementação.
O número de parâmetros de tipo genérico (ou inferido implicitamente ou explicitamente declaradas) deve coincidir, e devem coincidir com os tipos e as restrições de tipo nos parâmetros de tipo genérico.
Se a Literal atributo é usado, ele deve aparecer no tanto a assinatura e a implementação e o mesmo valor literal deve ser usado para ambos.
O padrão de parâmetros (também conhecido como o arity) de assinaturas e implementações devem ser consistentes.
O exemplo de código a seguir mostra um exemplo de um arquivo de assinatura que tenha espaço para nome, módulo, o valor de função e assinaturas de tipo junto com os atributos apropriados. Ele também mostra o arquivo de implementação correspondente.
// 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
O código a seguir mostra o arquivo de implementação.
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