灵活类型

灵活的类型注释指示参数、变量或值具有与指定类型兼容的类型,其中兼容性由类或接口的面向对象的层次结构中的位置确定。 灵活类型特别适用于类型层次结构中较高类型的自动转换,但仍希望使功能能够处理层次结构中的任何类型或实现接口的任何类型的类型。

语法

#type

注解

在前面的语法中, 类型 表示基类型或接口。

灵活类型等效于具有约束的泛型类型,该约束将允许的类型限制为与基类型或接口类型兼容的类型。 也就是说,以下两行代码是等效的。

#SomeType

'T when 'T :> SomeType

灵活类型在多种情况下非常有用。 例如,如果具有较高顺序函数(采用函数作为参数的函数),则函数返回灵活类型通常很有用。 在以下示例中,将灵活类型与序列参数 iterate2 结合使用,使更高顺序函数能够处理生成序列、数组、列表和任何其他可枚举类型的函数。

请考虑以下两个函数,其中一个函数返回序列,另一个函数返回灵活类型。

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])

作为另一个示例,请考虑 Seq.concat 库函数:

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

可以将以下任一可枚举序列传递给此函数:

  • 列表列表
  • 数组列表
  • 列表数组
  • 序列数组
  • 可枚举序列的任何其他组合

以下代码用于 Seq.concat 演示可以使用灵活类型支持的方案。

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

输出如下所示。

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; ...]

在 F# 中,与其他面向对象的语言一样,有一些上下文中,实现接口的派生类型或类型会自动转换为基类型或接口类型。 这些自动转换发生在直接自变量中,但不是当类型处于从属位置时(例如函数类型的返回类型或类型参数)的一部分。 因此,在应用灵活类型表示法的类型是更复杂的类型的一部分时,这种表示法主要有用。

另请参阅