元组是未命名但有序值的分组,可能是不同类型的。 元组可以是引用类型或结构。
语法
(element, ... , element)
struct(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)
如果要避免通常函数语法隐含的函数参数隐式 curry,元组还可以用作函数参数。
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.
将元组用作参数会禁用 currying。 有关详细信息,请参阅 函数中的“部分参数应用程序”。
元组类型的名称
写出作为元组的类型的名称时,可以使用符号 *
分隔元素。 对于由 aint
、a 和 afloat
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 的早期版本,编译器将使用 2.0 版本的 F# 核心库的版本 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 元组,并双向互作。