元组
元组是一组未命名但有序的值,值的类型可能不同。 元组可以是引用类型或结构。
语法
(element, ... , element)
struct(element, ... ,element )
备注
上述语法中的每个 element 都可以是任何有效的 F# 表达式。
示例
元组的示例包括相同或不同类型的对、三元组等。 以下代码演示了一些示例。
(1, 2)
// Triple of strings.
("one", "two", "three")
// Tuple of generic types.
(a, b)
// Tuple that has mixed types.
("one", 1, 2.0)
// Tuple of integer expressions.
(a + 1, b + 1)
// Struct Tuple of floats
struct (1.025f, 1.5f)
获取单个值
可以使用模式匹配来访问和分配元组元素的名称,如以下代码所示。
let print tuple1 =
match tuple1 with
| (a, b) -> printfn "Pair %A %A" a b
还可以使用 let
绑定在 match
表达式外部通过模式匹配来析构元组:
let (a, b) = (1, 2)
// Or as a struct
let struct (c, d) = struct (1, 2)
或者,可以对作为函数输入的元组进行模式匹配:
let getDistance ((x1,y1): float*float) ((x2,y2): float*float) =
// Note the ability to work on individual elements
(x1*x2 - y1*y2)
|> abs
|> sqrt
如果只需要元组的一个元素,可以使用通配符(下划线)避免为不需要的值创建新名称。
let (a, _) = (1, 2)
将引用元组中的元素复制到结构元组也很简单:
// Create a reference tuple
let (a, b) = (1, 2)
// Construct a struct tuple from it
let struct (c, d) = struct (a, b)
函数 fst
和 snd
(仅限引用元组)分别返回元组的第一个和第二个元素。
let c = fst (1, 2)
let d = snd (1, 2)
没有返回三元组第三个元素的内置函数,但你可以按下面所示轻松编写一个。
let third (_, _, c) = c
通常,最好使用模式匹配来访问单个元组元素。
使用元组
元组提供一种从函数返回多个值的便捷方式,如以下示例所示。 此示例执行整数除法运算,并将运算的舍入结果作为元组对的第一个成员返回,余数作为该对的第二个成员返回。
let divRem a b =
let x = a / b
let y = a % b
(x, y)
如果要避免隐式扩充常用函数语法所隐含的函数参数,元组也可以用作函数参数。
let sumNoCurry (a, b) = a + b
借助定义函数 let sum a b = a + b
的常用语法,可以定义一个函数,该函数是函数第一个参数的部分应用,如以下代码所示。
let sum a b = a + b
let addTen = sum 10
let result = addTen 95
// Result is 105.
使用元组作为参数会禁用扩充。 有关详细信息,请参阅函数中的“参数的部分应用”。
元组类型的名称
写出作为元组的类型的名称时,使用 *
符号来分隔元素。 对于由 int
、float
和 string
组成的元组,例如 (10, 10.0, "ten")
,类型将编写如下。
int * float * string
请注意,在为结构元组类型创建类型别名时,必须使用外括号。
type TupleAlias = string * float
type StructTupleAlias = (struct (string * float))
与 C# 元组的互操作
C# 中的元组是结构,相当于 F# 中的结构元组。 如果需要与 C# 互操作,则必须使用结构元组。
这很容易做到。 例如,假设你必须将元组传递给 C# 类,然后使用它的结果(也是一个元组):
namespace CSharpTupleInterop
{
public static class Example
{
public static (int, int) AddOneToXAndY((int x, int y) a) =>
(a.x + 1, a.y + 1);
}
}
然后,在 F# 代码中,你可以将结构元组作为参数传递,并将结果用作结构元组。
open TupleInterop
let struct (newX, newY) = Example.AddOneToXAndY(struct (1, 2))
// newX is now 2, and newY is now 3
引用元组和结构元组之间的转换
引用元组和结构元组具有完全不同的基础表示形式,因此它们不能隐式转换。 也就是说,以下代码将无法编译:
// Will not compile!
let (a, b) = struct (1, 2)
// Will not compile!
let struct (c, d) = (1, 2)
// Won't compile!
let f(t: struct(int*int)): int*int = t
你必须对一个元组进行模式匹配,并用构成部分构造另一个元组。 例如:
// Pattern match on the result.
let (a, b) = (1, 2)
// Construct a new tuple from the parts you pattern matched on.
let struct (c, d) = struct (a, b)
引用元组的编译形式
本部分说明编译时元组的形式。 除非你的目标是 .NET Framework 3.5 或更低版本,否则无需阅读此处的信息。
元组被编译成某种泛型类型的对象,这些对象(全部命名为 System.Tuple
)将在 arity 或类型参数数量上重载。 当你通过另一种语言(例如 C# 或 Visual Basic)查看元组类型时,或者当你使用不了解 F# 构造的工具时,元组类型就会以这种形式出现。 Tuple
类型是在 .NET Framework 4 中引入的。 如果你的目标是 .NET Framework 的早期版本,编译器会使用 F# 核心库 2.0 版本中的 System.Tuple
版本。 此库中的类型仅用于面向 .NET Framework 2.0、3.0 和 3.5 版本的应用程序。 类型转发用于确保 .NET Framework 2.0 和 .NET Framework 4 F# 组件之间的二进制兼容性。
结构元组的编译形式
结构元组(例如 struct (x, y)
)在本质上不同于引用元组。 它们被编译成 ValueTuple 类型,由 arity 或类型参数数量重载。 它们等效于 C# 元组和 Visual Basic 元组,并且可以双向互操作。