Signaturas (F#)
Un archivo de signatura contiene información sobre las signaturas públicas de un conjunto de elementos de programa de F#, tales como tipos, espacios de nombres y módulos. Se puede utilizar para especificar la accesibilidad de estos elementos de programa.
Comentarios
Para cada archivo de código de F#, puede haber un archivo de signatura, que es un archivo que tiene el mismo nombre que el archivo de código pero con la extensión .fsi en lugar de .fs. Los archivos de signatura también se pueden agregar a la línea de comandos de compilación si se utiliza la línea de comandos directamente. Para distinguir entre los archivos de código y los de signaturas, los archivos de código se denominan a veces archivos de implementación. En un proyecto, el archivo de signatura debe preceder al archivo de código asociado.
Un archivo de signatura describe los espacios de nombres, módulos, tipos y miembros del archivo de implementación correspondiente. La información de un archivo de signatura se utiliza para especificar a qué elementos del código del archivo de implementación correspondiente se puede obtener acceso desde el código situado fuera del archivo de implementación, y qué elementos son internos del archivo de implementación. Los espacios de nombres, módulos y tipos que se incluyen en el archivo de signatura deben ser un subconjunto de los espacios de nombres, módulos y tipos que se incluyen en el archivo de implementación. Con algunas excepciones que se abordan más adelante en este tema, los elementos de lenguaje que no se incluyen en el archivo de signatura se consideran privados en el archivo de implementación. Si no se encuentra ningún archivo de signatura en el proyecto o en la línea de comandos, se utiliza la accesibilidad predeterminada.
Para obtener más información acerca de la accesibilidad predeterminada, vea Control de acceso (F#).
En un archivo de signatura, no se repite la definición de los tipos y las implementaciones de cada método o función. En lugar de ello, se utiliza la signatura de cada método y función, que actúa como una especificación completa de la funcionalidad implementada por un módulo o fragmento de espacio de nombres. La sintaxis de una signatura de tipo es igual que la utilizada en declaraciones de método abstractas en interfaces y clases abstractas, y también la muestran IntelliSense y el intérprete de F#, fsi.exe, al mostrar la entrada compilada correctamente.
Si no hay información suficiente en la signatura de tipo para indicar si un tipo está sellado o si se trata de un tipo de interfaz, hay que agregar un atributo que indique la naturaleza del tipo al compilador. Los atributos que se utilizan para este fin se describen en la tabla siguiente.
Atributo |
Descripción |
---|---|
[<Sealed>] |
Para un tipo que no tiene ningún miembro abstracto o que no se debe extender. |
[<Interface>] |
Para un que es una interfaz. |
El compilador genera un error si los atributos no son coherentes entre la signatura y la declaración del archivo de implementación.
La palabra clave val se utiliza para crear una signatura para un valor o valor de función. La palabra clave type introduce una signatura de tipo.
Se puede generar un archivo de signatura mediante la opción del compilador --sig. En general, no se escribe manualmente en los archivos .fsi. En lugar de ello, los archivos .fsi se generan mediante el compilador, se agregan al proyecto si lo hay y se editan quitando los métodos y las funciones que no se desea que estén accesibles.
Hay varias reglas para las signaturas de tipo:
Las abreviaturas de tipo en un archivo de implementación no pueden corresponderse con un tipo sin abreviatura en un archivo de signatura.
Los registros y las uniones discriminadas deben exponer todos sus campos y constructores o ninguno de ellos, y el orden en la signatura debe coincidir con el orden en el archivo de implementación. Las clases pueden revelar algunos, todos o ninguno de sus campos y métodos en la signatura.
Las estructuras y clases que tienen constructores deben exponer las declaraciones de sus clases base (la declaración inherits). Asimismo, las clases y estructuras que tienen constructores deben exponer todos sus métodos abstractos y declaraciones de interfaz.
Los tipos de interfaz deben revelar todos sus métodos e interfaces.
A continuación se exponen las reglas correspondientes a las signaturas de valores:
Los modificadores de accesibilidad (public, internal, etc.) y los modificadores mutable e inline de la signatura deben coincidir con los de la implementación.
El número de parámetros de tipo genérico (ya se realice su inferencia implícitamente o se declaren explícitamente) deben coincidir; también deben coincidir los tipos y las restricciones de tipo de los parámetros de tipo genérico.
Si se utiliza el atributo Literal, debe aparecer en la signatura y en la implementación, y se debe usar el mismo valor literal para ambos.
El modelo de parámetros (también denominado aridad) de las signaturas y las implementaciones debe ser coherente.
En el ejemplo de código siguiente se muestra un ejemplo de un archivo de firma que tiene signaturas de espacios de nombres, módulos, valores de función, tipos, junto con los atributos adecuados. También se muestra el archivo de implementación correspondiente.
// 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
En el siguiente código, se muestra el archivo de implementación.
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