元组

元组是未命名但有序值的分组,可能是不同类型的。 元组可以是引用类型或结构。

语法

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

函数 fstsnd (仅引用元组)分别返回元组的第一个和第二个元素。

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 和 afloatstring(例如(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 元组,并双向互作。

另请参阅