【转】Tuple元组

Tuple,是函数式编程的概念之一,早见于Elang、F#等动态语言。不过,我第一次听说Tuple还早在2005年园子的Ninputer大牛提出在.NET 2.0实现Tuple的基本想法,我们可以通过以下地址仰慕当时的历史片段: 
探讨.NET 2.0中Tuple的实现方法 
由此可见,Tuple不是.NET 4.0的创造发明,但却是C#趋于函数式编程概念的必要补充。那么,我们首先来看看,什么是Tuple?

Tuple为何物?

什么是Tuple,在汉语上我们将其翻译为元组。Tuple的概念源于数学概念,表示有序的数据集合。在.NET中Tuple被实现为泛型类型,n-Tuple表示有n个元素的Tuple,集合的元素可以是任何类型,例如定义一个3-Tuple表示Date(Year, Month, Day)时可以定义为:

// Release : code01, 2009/05/29
// Author  : Anytao, http://www.anytao.com
var date = Tuple.Create<int, int, int>(2009, 5, 29);

通过Tuple.Create<int, int, int>将定义一个Tuple<int, int, int>实例,该实例实现三个数据成员:

对于Tuple的具体解析我们随后分析,当下仅了解一个大致。

我们可以有两个方面的理解,在.NET中关于Tuple我们有如下的定义:

  • 广义上, Tuple就是一种数据结构,通常情况下,其成员的类型及数据是确定的。
  • 狭义上,凡是实现了ITuple接口的类型,都是Tuple的实例。在.NET 4.0 BCL中,预定义了8个Tuple类型。例如最简单的Tuple定义为:
public class Tuple<T1> : IStructuralEquatable, IStructuralComparable, IComparable, ITuple
{
}

其他所有的Tuple类型都实现了ITuple接口,该接口被定义为:

interface ITuple
{
    int Size { get; }

    int GetHashCode(IEqualityComparer comparer);
    string ToString(StringBuilder sb);
}

在该接口中,定义了一个只读属性Size、两个覆写方法GetHashCode和ToString,实现该接口的Tuple八大金刚如下:

public class Tuple<T1>
public class Tuple<T1, T2>
public class Tuple<T1, T2, T3>
public class Tuple<T1, T2, T3, T4>
public class Tuple<T1, T2, T3, T4, T5>
public class Tuple<T1, T2, T3, T4, T5, T6>
public class Tuple<T1, T2, T3, T4, T5, T6, T7>
public class Tuple<T1, T2, T3, T4, T5, T6, T7, TRest>

注:Size属性、ToString(StringBuilder sb)方法,均被实现为显示接口方法,所以只能以接口实例访问,不过ITuple本身被定义internal,意味着我们无法在程序中访问ITuple,何意何解尚不明确。

在下面的定义中,我们将Custom Request封装为Tuple:

// Release : code02, 2009/05/29
// Author  : Anytao, http://www.anytao.com
public class MyRequest
{
    public Tuple<string, Uri, DateTime> GetMyRequest()
    {
        return Tuple.Create<string, Uri, DateTime>("anytao.com", new Uri("http://anytao.net/"), DateTime.Now);
    }
}

为什么要用Tuple呢?这是个值得权衡的问题,上述MyRequest类型中通过3-Tuple对需要的Request信息进行封装,我们当然也可创建一个新的struct来封装,两种方式均可胜任。然则,在实际的编程实践中,很多时候我们需要一种灵活的创建一定数据结构的类型,很多时候新的数据结构充当着“临时”角色,通过大动干戈新类型完全没有必要,而Tuple既是为此种体验而设计的。例如:

  • Point {X, Y},可以表示坐标位置的数据结构。
  • Date {Year, Month, Day},可以表示日期结构;Time {Hour, Minute, Second},可以表示时间结构;而DateTime {Date, Time}则可以实现灵活的日期时间结构。
  • Request {Name, URL, Result},可以表示Request的若干信息。
  • 。。。,随需而取。

Tuple inside

为了对Tuple一探究竟,我们使用Reflector工具打开神秘之门,就实现而言,Tuple类型略显单薄,并没有什么“神奇”的设计,以Tuple<T1, T2>而言,我们可以看到其部分实现:

[Serializable]
public class Tuple<T1, T2> : IStructuralEquatable, IStructuralComparable, IComparable, ITuple
{
    // Fields
    private T1 m_Item1;
    private T2 m_Item2;

    // Methods
    public Tuple(T1 item1, T2 item2)
    {
        this.m_Item1 = item1;
        this.m_Item2 = item2;
    }

    string ITuple.ToString(StringBuilder sb)
    {
        sb.Append(this.m_Item1);
        sb.Append(", ");
        sb.Append(this.m_Item2);
        sb.Append(")");
        return sb.ToString();
    }

    int ITuple.Size
    {
        get
        {
            return 2;
        }
    }

    // Properties
    public T1 Item1
    {
        get
        {
            return this.m_Item1;
        }
    }

    public T2 Item2
    {
        get
        {
            return this.m_Item2;
        }
    }

    //More and more...
}

其他的Tuple类型也大致如此,所以我们易于知晓Item1、Item2、…、ItemN是如何被定义的,同时也纳闷Size属性将何去何从,也打消了我们期望通过foreach来遍历Tuple元素的可能,未来如何,只有期待。

不过,对于Tuple而言,因为其元素数量的有限性,虽然能够满足大部分的需求,当时动态体验是我们越来越期望的编程体验。同时,尤其注意public class Tuple<T1, T2, T3, T4, T5, T6, T7, TRest> 引发的可能ArgumentException,例如:

// Release : code03, 2009/05/31
// Author  : Anytao, http://www.anytao.com
var t8 = Tuple.Create<int, int, int, int, int, int, int, int>(1, 2, 3, 4, 5, 6, 7, 8);
Console.WriteLine(t8.Rest);

将引发异常:

Unhandled Exception: System.ArgumentException: The last element of an eight element tuple must be a Tuple.

提示我们最后的TRest应该为Tuple,所以修改程序为:

// Release : code04, 2009/05/31
// Author  : Anytao, http://www.anytao.com
var trest = Tuple.Create<int>(8);
var t8 = Tuple.Create<int, int, int, int, int, int, int, Tuple<int>>(1, 2, 3, 4, 5, 6, 7, trest);
Console.WriteLine(t8.Rest);

则没有任何问题,究其原因我们很容易从Tuple<T1, T2, T3, T4, T5, T6, T7, TRest>构造方法中找到答案:

public Tuple(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6, T7 item7, TRest rest)
{
    if (!(rest is ITuple))
    {
        throw new ArgumentException(Environment.GetResourceString("ArgumentException_TupleLastArgumentNotATuple"));
    }
    this.m_Item1 = item1;
    this.m_Item2 = item2;
    this.m_Item3 = item3;
    this.m_Item4 = item4;
    this.m_Item5 = item5;
    this.m_Item6 = item6;
    this.m_Item7 = item7;
    this.m_Rest = rest;
}

TRest类型参数必须被实现为ITuple,否则引发异常。TRest在某种程度上为元素的扩展带来点方便,但是我仔细想来,总觉此处TRest的设计有点多此一举,既然是类型参数,T1、T2、…、TN其实均可为ITuple实例,何必非拘泥于最后一个。

优略之间

当前,.NET 4.0预定义的Tuple类型仅有8个,所以我们应考虑对于Tuple提供适度扩展的可能, 然而遗憾的是ITuple类型被实现为internal,所以我们无法继承ITuple,只好自定义类似的实现:

优势所在:

  • 为方法实现多个返回值体验,这是显然的,Tuple元素都可以作为返回值。
  • 灵活的构建数据结构,符合随要随到的公仆精神。
  • 强类型。

不足总结:

  • 当前Tuple类型的成员被实现为确定值,目前而言,还没有动态决议成员数量的机制,如果你有可以告诉我:-)
  • public class Tuple<T1, T2, T3, T4, T5, T6, T7, TRest>,可能引发ArgumentException
时间: 2024-10-05 10:05:01

【转】Tuple元组的相关文章

tuple元组(C++11及以后,如C++14)

类tuple与array最本质的区别当数tuple元组元素类型可以不一样,而统一数组array的元素类型必须一样. 本文主要举例: tuple_size Example 123456789101112131415161718192021222324252627 // tuple example #include <iostream> // std::cout #include <tuple> // std::tuple, std::get, std::tie, std::ignor

Python之路【第二篇】:Python基础(2)-Tuple元组

#!/usr/bin/env python3# -*- coding: utf-8 -*-#Author:Jam #0.元组'''元组和列表类似,不同之处在于元组的元素不能修改元组使用小括号,列表使用方括号元组创建很简单,只需要在括号中添加元素,并使用逗号隔开即可''' #实例:tup1 = ('Google','Runoob',1997,2000)tup2 = (1,2,3,4,5)tup3 = 'a','b','c','d' #创建空元组tup1 = () #元组中只包含一个元素时,需要在元

.NET 4新特性--Tuple元组

.NET 4定义了8个Tuple类,和一个静态Tuple类 ---------------------------------------------------------------------返回多个值 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ConsoleApplication2

python里list列表,tuple元组内部功能介绍

list列表 append            #在列表尾部追加元素 clear                #把列表清空 count               #统计元素出现的次数 extend             #合并两个列表或者元组与列表合并,对原来列表的扩展 index                #获取元素的下标,索引 insert                #插入元素,可以自己指定插入位置 pop                   #删除某个元素,默认删除最后一个

C++11 tuple元组

C++11 tuple 元组 tuple容器(元组), 是表示元组容器, 是不包含任何结构的,快速而低质(粗制滥造, quick and dirty)的, 可以用于函数返回多个返回值; tuple容器, 可以使用直接初始化, 和"make_tuple()"初始化, 访问元素使用"get<>()"方法, 注意get里面的位置信息, 必须是常量表达式(const expression); 可以通过"std::tuple_size<declty

tuple元组创建单元素

创建tuple单元素,一定要在结尾时添加一个逗号(,)解:如果不加逗号,哪怕是使用tuple()正确的创建元组,也会有歧义,它会把创建tuple元组的单元素,当成一个普通的输出语句结果列:如下,错误的方式,得到的结果不是tuple()元组类型 tup = ('a')print(tup) 正确的创建tuple单元素的方式 tup = ('a',)print(tup) 原文地址:https://www.cnblogs.com/mumu555/p/10929277.html

C#关键字扫盲——Tuple(元组类) 、ValueTuple(值元组)

原文:C#关键字扫盲--Tuple(元组类) .ValueTuple(值元组) 版权声明:本文为博主原创文章,随意转载. https://blog.csdn.net/Michel4Liu/article/details/79750877 Tuple.ValueTuple 当方法返回值大于一个时我们有时用out或结构体或类来处理,今天介绍一个简便的多返回值方式. ValueTuple 是 Tuple的扩展,本文只针对最新的ValueTuple 做讲解,Tuple有很多不便之处,总之过时的就让他过去

[Python3]Tuple(元组)

概述 元组,使用小括号()来标识,其特点是:元组中的元素不可修改 下面我们看下如何创建元组的示例: tuple1 = (u'DeepTest', u'开源优测', u'1') tuple2 = (1, 2, 3, 4, 5) tuple3 = ("a", "b", "c", "d", "e") 内置函数 Python中常用的内置函数有: len用于计算元组元素的个数 max返回元组中元素最大值 min返回元

python——tuple元组

>>> dir(tuple) ['__add__', '__class__', '__contains__', '__delattr__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__getslice__', '__gt__', '__hash__', '__init__', '__iter__', '__le__', '__le

c++11——tuple元组

tuple是一个固定大小的不同类型值的集合,是泛化的 std::pair.可以当做一通用的结构体使用,不需要创建结构体而又获取结构体的特征,在某些情况下可以取代结构体,使程序简洁.直观. 创建tuple 1. make_tupe tuple<const char*, int> tp = make_tuple(sendPack, nSendSize);//构造tuple 2. tie 函数(创建一个元组的左值引用) auto tp = std::tie(1, "aa", 2.