Show/Hide Toolbars

XSharp

元组(Tuple)一般数据类型

 

元组是一种在轻量级数据结构中将多个数据元素分组的数据结构。元组可以作为一种简便的方法来表示多个数据元素,将它们作为参数传递或作为返回值接收,而无需声明一个完整的新类或结构来保存数据集。

 

例如,下面的代码使用通用的 System.Collections.Generic.Tuple 类型从函数中接收多个值,而无需声明多个 REF/OUT 参数或创建一个新的专用类型来保存它们:

USING System.Collections.Generic
 
FUNCTION GetCustomerData() AS Tuple<STRING, INT, LOGIC>
  LOCAL oCustomer AS Tuple<STRING, INT, LOGIC>
  oCustomer := Tuple<STRING, INT, LOGIC>{"Nikos", 47, TRUE}
RETURN oCustomer
 
FUNCTION Start() AS VOID
  LOCAL oCustomer AS Tuple<STRING, INT, LOGIC>
  oCustomer := GetCustomerData()
  ? "Customer name:", oCustomer:Item1
  ? "Age:", oCustomer:Item2
  ? "Is active:", oCustomer:Item3

TUPLE 关键字

 

X# 还支持专用关键字 TUPLE,它为元组的声明和处理提供了更简便的语法。使用 TUPLE 关键字语法可以更简单地编写上述代码:

 

FUNCTION GetCustomerData() AS TUPLE(STRING, INT, LOGIC)
  LOCAL oCustomer AS TUPLE(STRING, INT, LOGIC) // 定义元组
   // 元组项目类型必须与元组定义中的类型一致
  oCustomer := TUPLE{"Nikos", 47, TRUE}
RETURN oCustomer

FUNCTION Start() AS VOID
  LOCAL oCustomer AS (STRING, INT, LOGIC)
  // 甚至可以省略元组定义中的 TUPLE 关键字!
  oCustomer := GetCustomerData()
  ? "Customer name:", oCustomer:Item1
  ? "Age:", oCustomer:Item2
  ? "Is active:", oCustomer:Item3

请注意,使用 TUPLE 关键字时,编译器会在内部使用 System.ValueTuple 类型,而不是通用类型 System.Collections.Generic.Tuple。此外,在定义元组时,可以省略 TUPLE 关键字,从而使用更类似于 c# 的语法(type1、type2、...)

已命名的图元

专用的 TUPLE 关键字语法还支持为元组项指定自定义名称,而不是使用 Item1、Item2 等通用名称。这样,代码的可读性就会大大提高,并接近于使用单独的新类来处理数据时的效果:

FUNCTION Start() AS VOID
  LOCAL oCustomer AS TUPLE(Name AS STRING, Age AS INT, IsActive AS LOGIC)
  // 为元组中的每个项目提供名称
  oCustomer := GetCustomerData()
  ? "Customer name:", oCustomer:Name
  ? "Age:", oCustomer:Age
  ? "Is active:", oCustomer:IsActive

为了使代码更加一目了然,命名元组也可以通过使用命名参数来实例化:

FUNCTION GetCustomerData() AS Tuple(STRING, INT, LOGIC)
  // 用自定义项目名称定义命名元组
  LOCAL oCustomer AS Tuple(Name AS STRING, Age AS INT, IsActive AS LOGIC)
  // 在元组实例化中包括元组项目名称
  oCustomer := TUPLE{Name := "Nikos", Age := 47, IsActive := TRUE}
RETURN oCustomer

用 VAR 定义元组

使用 VAR 关键字还可以同时定义元组和实例化元组:

 

FUNCTION Start() AS VOID
  VAR oTuple := TUPLE{"Nikos", 47, FALSE}
  ? oTuple:Item1, oTuple:Item2, oTuple:Item3 // "Nikos", 47, FALSE

 

在这种情况下,每个元组项的数据类型是根据代码中提供的项类型推断出来的。在上述示例中,项目类型为(STRING、INT、LOGIC)。

 

具有相同项目类型的元组可以互相赋值(从而将项目值从源元组复制到目标元组),对于使用 LOCAL 或 VAR 定义的元组也是如此:

FUNCTION Start() AS VOID
  VAR oTuple := TUPLE{"Nikos", 47, FALSE}
  LOCAL oNew AS TUPLE(STRING, INT, LOGIC)
 
  oNew := oTuple
  ? oNew:Item1, oNew:Item2, oNew:Item3 // "Nikos", 47, FALSE

使用 VAR 关键字定义元组时,还可以提供项目名称:

FUNCTION Start() AS VOID
  VAR oTuple := TUPLE{Name := "Nikos", Age := 47, IsActive := FALSE}
  ? oTuple:Name, oTuple:Age, oTuple:IsActive // "Nikos", 47, FALSE

最后,在使用 VAR 定义元组时,如果使用标识符来定义项值,而不是使用字面值,那么每个项都会自动根据标识符名称获得一个名称:

CLASS CustomerInfo
  EXPORT Description := "Customer description" AS STRING
END CLASS
 
FUNCTION Start() AS VOID
  LOCAL name := "Unknown Customer" AS STRING
  LOCAL oInfo := CustomerInfo{} AS CustomerInfo
 
  VAR oTuple := TUPLE{name, oInfo:Description}
  ? oTuple:name // "未知客户"
  ? oTuple:description // "客户描述"

元组析构

使用 (var1, var2, ...)语法,可以在一行代码中将元组分解为多个普通变量:

FUNCTION Start() AS VOID
  LOCAL oCustomer AS TUPLE(Name AS STRING, Age AS INT)
  oCustomer := TUPLE{"Nikos", 47}
 
  LOCAL name AS STRING
  LOCAL age AS INT
 
  (name, age) := oCustomer
  ? name, age // "Nikos", 47

也可以使用针对元组的特殊 LOCAL 语法,在一行中定义局部变量并将其赋值给元组项值:

FUNCTION Start() AS VOID
  LOCAL oCustomer AS TUPLE(Name AS STRING, Age AS INT)
  oCustomer := TUPLE{"Nikos", 47}
 
  LOCAL (name AS STRING, age AS INT) := oCustomer
  ? name, age // "Nikos", 47
  // 您也可以在不使用 LOCAL 关键字的情况下析构到现有的局部变量中:
  (name, age) := oCustomer

此外,VAR 关键字也可用于元组析构,在这种情况下,变量类型是从元组项类型中推断出来的:

FUNCTION Start() AS VOID
  LOCAL oCustomer AS TUPLE(Name AS STRING, Age AS INT)
  oCustomer := TUPLE{"Nikos", 47}
 
  VAR (name, age) := oCustomer
  ? name, age // "Nikos", 47