单元素和零元素元组有什么用?

时间:2018-08-07 09:08:44

标签: c# f# tuples c#-7.0

C#7.0引入了值元组以及对它们的一些语言级别支持。它们added the support也包含单元素和零元素元组;但是,我找不到任何可行的方案。

通过ValueTuple.Create重载,我可以创建任何类型的元组,但是C#7.0语法仅允许至少两个元素:

Microsoft (R) Roslyn C# Compiler version 2.8.3.62923
Loading context from 'CSharpInteractive.rsp'.
Type "#help" for more information.
> ValueTuple.Create()
[()]
> ValueTuple.Create(1)
[(1)]
> ValueTuple.Create(1, "x")
[(1, x)]

通过元组语法:

> var t2 = (1, 2);
> var t1 = (1); // t1 is now int (of course)
> ValueTuple<int> t1 = (1);
(1,23): error CS0029: Cannot implicitly convert type 'int' to 'ValueTuple<int>'
> ValueTuple<int> t1 = new ValueTuple<int>(1);
> t1
[(1)]

我认为我找到了this feature was requested所在的线程,但是现在没有代码示例在C#中有效,并且甚至在递归元组模式下都没有在planned features of C# 8.0中找到任何引用。 / p>

在请求线程中提到了功能编程语言。可能有任何功能性语言现在使用它们吗?我不是F#专家,但其元组reference并未提及对单元素和零元素元组的任何使用。

所以TL; DR问题:

  • 是否在任何(可能是功能性的).NET语言中使用了单元素和零元素元组?我的意思不是通过Tuple.Create或构造函数,而是通过本地语言支持。
  • 他们打算在将来的C#版本中使用它吗?
  • 还是为了以防万一,以备将来兼容?

6 个答案:

答案 0 :(得分:11)

0元组有什么用?

2元组或3元组表示一组相关项。 (2D空间中的点数,颜色的RGB值等。)1元组不是很有用,因为可以很容易地用单个int替换它。

0元组似乎毫无用处,因为它绝对不包含任何东西。但是它具有的特性使其在F#等功能语言中非常有用。例如,0元组类型只有一个值,通常表示为()。所有0元组都具有此值,因此本质上是单例类型。在包括F#在内的大多数函数式编程语言中,这称为unit类型。

在C#中返回void的函数将在F#中返回unit类型:

let printResult = printfn "Hello"

在F#交互式解释器中运行该命令,您将看到:

val printResult : unit = ()

这意味着值printResult的类型为unit,并具有值()(空元组,unit类型的唯一值)

函数也可以将unit类型作为参数。在F#中,函数看起来好像没有参数。但实际上,它们只是使用unit类型的单个参数。此功能:

let doMath() = 2 + 4

实际上等同于:

let doMath () = 2 + 4

也就是说,该函数采用类型为unit的一个参数并返回int值6。如果您在定义此函数时查看F#交互式解释器打印的类型签名,会看到:

val doMath : unit -> int

所有函数都将至少使用一个参数并返回一个值,即使该值有时是诸如()之类的“无用”值这一事实,这意味着F#中的函数组合比语言中的编写容易得多没有unit类型。但这是一个更高级的主题,稍后我们将介绍。现在,请记住,当您在函数签名中看到unit或在函数的参数中看到()时,这就是0元组类型,它表示“此函数接受或返回,没有有意义的值。”

答案 1 :(得分:3)

我想不出一个元素元组的用例。编辑-正如所指出的那样,引用的页面提到了一个元素元组作为命名返回参数的方法,尽管这可能是C#特定的,但这听起来实际上很有用。

零元素元组使用功能语言(也称为unit)。这有点像C#中的void,某些(大多数?)功能语言没有。

区别在于()是一个实际值,您可以使用它来处理诸如保持列表,模式匹配等之类的事情。功能语言需要这样做,因为函数必须返回某些内容,并且如果要返回“ nothing”(无),则表示必须通过返回()显式地执行此操作。您还可以编写一个接受unit作为参数的函数,这基本上意味着它是一个延迟执行的值,最有可能产生副作用:

let x = getFromDb() // will read DB
stream.Flush() // will change state

答案 2 :(得分:1)

在C#中不支持o元组(nople)和1元组(oneple)。

但是,在基类库(BCL)上,为了保持连贯性,以防万一将来有人找到它的用途,这里有ValueTupleValueTuple<T>。例如,一种语言具有0元组和1元组的构造。

ValueTuple有一些附加值。来自the documentation

  

ValueTuple结构表示没有元素的元组。它主要用于其静态方法,使您可以创建和比较值元组类型的实例,因此很有用。它的帮助器方法使您可以实例化值元组,而不必显式指定每个值元组组件的类型。通过调用其静态的Create方法,可以创建具有零到八个组成部分的值元组。对于具有八个以上组件的值元组,必须调用ValueTuple构造函数。

答案 3 :(得分:0)

目前,ValueTuple'1仅用于长元组的表示形式,即使1元组没有C#元组语法:ValueTuple<T1, T2, T3, T4, T5, T6, T7, ValueTuple<T8>>是8元组的基础类型。 / p>

对于0元组和ValueTuple'0,我们推测它们可能会出现在未来的场景中(如果我没记错的话,可能是一些递归模式)。

答案 4 :(得分:0)

一个 1 元组可以用作围绕可空值的非空包装器。这在尝试添加到字典时很有用,例如:

void Process<TKey>(TKey[] keys)
{
    var dict = new Dictionary<TKey, Something>();
    var firstKey = keys[0];
    dict[firstKey] = new Something();
    ...
}

如果启用 nullable 将显示警告(创建 dict 时),因为 TKey 可能是可空类型(API 可能愿意接受)和 {{1 }} 不接受 Dictionary<TKey, TValue> ;同时:

null

不会显示警告。

答案 5 :(得分:0)

1-Tuple 可以用作 lambda 的单个参数列表。元组非常适合用作 lambda 参数列表,因为您可以更改它们的结构而不破坏 lambda。您也可以通过这种方式命名 lambda 的参数。但是由于您不能使用 1-Tuple,如果参数数量更改为 1,您必须恢复为常规参数。

例如:

int DoSomething(
   Func<(int First, int Second, int Third), int> function
) =>
   function((1, 2, 3));

// DOESN'T WORK
int DoSomethingElse(
   Func<(int First), int> function
) =>
   function((1));

// does work but not as nice
int DoSomethingElse2(
   Func<int, int> function
) =>
   function(1);
相关问题