Compartir a través de


Tipos flexibles (F#)

Una anotación de tipo flexible indica que un parámetro, una variable o un valor tiene un tipo compatible con el tipo especificado, donde la compatibilidad viene determinada por la posición en una jerarquía orientada a objetos de clases o interfaces. Los tipos flexibles resultan útiles específicamente cuando no se produce la conversión automática a los tipos que se encuentran por encima en la jerarquía de tipos, pero se desea habilitar la funcionalidad para que funcione con cualquiera de los tipos de la jerarquía o con cualquier tipo que implemente una interfaz.

#type

Comentarios

En la sintaxis anterior, type representa un tipo base o una interfaz.

Un tipo flexible equivale a un tipo genérico que tiene una restricción que limita los tipos permitidos a los tipos que son compatibles con el tipo base o de interfaz. Es decir, las siguientes dos líneas de código son equivalentes.

#SomeType

'a when 'a :> SomeType

Los tipos flexibles son útiles en varios tipos de situaciones. Por ejemplo, cuando se tiene una función de orden superior (una función que toma una función como argumento), suele resultar útil que la función devuelva un tipo flexible. En el ejemplo siguiente, el uso de un tipo flexible con un argumento de secuencia en iterate2 permite que la función de orden superior funcione con funciones que generan secuencias, matrices, listas y cualquier otro tipo enumerable.

Fíjese en las dos funciones las siguientes: una de ellas devuelve una secuencia; la otra, un tipo flexible.

let iterate1 (f : unit -> seq<int>) =
    for e in f() do printfn "%d" e
let iterate2 (f : unit -> #seq<int>) =
    for e in f() do printfn "%d" e

// Passing a function that takes a list requires a cast.
iterate1 (fun () -> [1] :> seq<int>)

// Passing a function that takes a list to the version that specifies a 
// flexible type as the return value is OK as is.
iterate2 (fun () -> [1])

La función de biblioteca Seq.concat representa otro ejemplo:

val concat: sequences:seq<#seq<'T>> -> seq<'T>

Puede pasar cualquiera de las secuencias enumerables siguientes a esta función:

  • Una lista de listas

  • Una lista de matrices

  • Una matriz de listas

  • Una matriz de secuencias

  • Cualquier otra combinación de secuencias enumerables

En el código siguiente se utiliza Seq.concat para mostrar los escenarios que se pueden admitir mediante los tipos flexibles.

let list1 = [1;2;3]
let list2 = [4;5;6]
let list3 = [7;8;9]

let concat1 = Seq.concat [ list1; list2; list3]
printfn "%A" concat1

let array1 = [|1;2;3|]
let array2 = [|4;5;6|]
let array3 = [|7;8;9|]

let concat2 = Seq.concat [ array1; array2; array3 ]
printfn "%A" concat2

let concat3 = Seq.concat [| list1; list2; list3 |]
printfn "%A" concat3

let concat4 = Seq.concat [| array1; array2; array3 |]
printfn "%A" concat4

let seq1 = { 1 .. 3 }
let seq2 = { 4 .. 6 }
let seq3 = { 7 .. 9 }

let concat5 = Seq.concat [| seq1; seq2; seq3 |]

printfn "%A" concat5

La salida es la siguiente.

seq [1; 2; 3; 4; ...]
seq [1; 2; 3; 4; ...]
seq [1; 2; 3; 4; ...]
seq [1; 2; 3; 4; ...]
seq [1; 2; 3; 4; ...]

En F#, al igual que en otros lenguajes orientados a objetos, hay contextos en que los tipos derivados o los tipos que implementan interfaces se convierten automáticamente a un tipo base o tipo de interfaz. Estas conversiones automáticas se producen en argumentos directos, pero no cuando el tipo se encuentra en una posición subordinada, como parte de un tipo más complejo (por ejemplo, un tipo de valor devuelto de un tipo de función, o un argumento de tipo). Así pues, la notación de tipo flexible resulta útil principalmente cuando el tipo al que se aplica forma parte de un tipo más complejo.

Vea también

Referencia

Genéricos (F#)

Otros recursos

Referencia del lenguaje F#