16

我想知道是否有任何语言允许命名元组。即:具有多个不同类型和可配置名称的变量的对象。

例如:

public NamedTuple<double:Speed, int:Distance> CalculateStuff(int arg1, int arg2)

var result = CalculateStuffTuple(1,2);

Console.WriteLine("Speed is: " + result.Speed.ToString())
Console.WriteLine("Distance is: " + result.Distance.ToString())

我可以想象动态如何支持这样的功能。我通常使用的静态语言(如 c#)可以做一个字典,但这不是类型安全的,除非所有项目都是相同的类型。或者您可以使用 Tuple 类型,但这意味着您有固定的成员名称(Var1、Var2 等)。

您也可以编写一个小的自定义类,但这是我想避免的情况。

我可以想象一种宏处理语言可以用静态语言为你编写类似的脚本,但我不知道这种语言。

这来自我对这个关于返回类型的问题的回答。

4

12 回答 12

40

老问题,但我认为需要更好的解决方案。

您可以利用 Tuple 类型获取命名参数,但将其包装在自定义命名类型中,该类型将 .Item1、.Item2 等包装在有意义的属性名称中。

我也讨厌元组具有使代码不可读的未命名参数这一事实,但不能忽略它节省的时间必须自己实现 IComparable、IStructuralEquatable 等,以便您可以安全地将结构用作字典键,例如.

我认为这是一个非常愉快的妥协:

public class Velocity : Tuple<double, double, string>
{
    public Velocity(double Speed, double Direction, string Units) : base(Speed, Direction, Units) { }
    public double Speed { get { return this.Item1; } }
    public double Direction { get { return this.Item2; } }
    public string Units { get { return this.Item3; } }
}

现在代替这个垃圾:

Tuple<double, double, string> myVelocity = new Tuple<double, double, string>(10, 2.34, "cm/s");
System.Diagnostics.Debug.Print("Speed: " + myVelocity.Item1);
System.Diagnostics.Debug.Print("Direction: " + myVelocity.Item2);
System.Diagnostics.Debug.Print("Units: " + myVelocity.Item3);

你可以这样做:

Velocity myVelocity2 = new Velocity(10, 2.34, "cm/s");
System.Diagnostics.Debug.Print("Speed: " + myVelocity2.Speed);
System.Diagnostics.Debug.Print("Direction: " + myVelocity2.Direction);
System.Diagnostics.Debug.Print("Units: " + myVelocity2.Units);

而且您仍然可以从所有美妙的元组功能中受益,这些功能可以让您将其用作字典等中的复杂键。

唯一的缺点是,如果您只计划在单个方法的范围内使用此元组,则必须在该方法的包含类的范围内声明一个类型。对于大多数应用程序,我认为这不是问题。

于 2012-08-08T16:37:30.633 回答
18

在 C# 中,您有匿名类型;这些是相似的,但有其自身的局限性:

var result = new { Speed = 12.4, Distance = 8, Caption = "car 1" };

但是,很难将这些作为调用者来使用,除非您使用“示例转换”(脆弱)、反射或dynamic. 这三个中,最后一个是最可口的。

dynamic result = GetSomething();
Console.WriteLine(result.Speed);
Console.WriteLine(result.Distance);

在大多数情况下,使用常规类会更好——但这种方法确实有一些实际用途;例如,看看它们如何在 ASP.NET MVC 中用于简单方便地传递配置信息(否则需要字典)。有点像 jQuery 如何允许您将选项作为属性传递给对象。

于 2009-09-29T04:29:23.207 回答
6

Eiffel 允许命名元组。

于 2009-09-30T16:46:10.770 回答
6

现在从 C# 7 开始支持

(double speed, int distance) CalculateStuff(int arg1, int arg2)

var result = CalculateStuff(1,2);

Console.WriteLine("Speed is: " + result.speed.ToString())
Console.WriteLine("Distance is: " + result.distance.ToString())

请参阅:https ://blogs.msdn.microsoft.com/dotnet/2017/03/09/new-features-in-c-7-0/

于 2016-04-14T21:34:21.730 回答
5

我知道;

  • Python(动态、强类型)
  • Eiffel(静态,字符串类型)

两者都可以在.net中使用

还有可能是 Lisp,你可以用 Lisp 做任何事情。

于 2012-02-03T11:55:15.567 回答
3

你的意思是,像 Python 的collections.namedtuple之类的东西?好吧,Python(当前版本,2.6 和 3.1)支持它们;-)。但说真的,我不知道将它们作为内置的静态类型语言。

于 2009-09-29T03:21:29.897 回答
3

我不确定这是否正是您要查找的内容,但是在 Haskell 中,您可以拥有具有指定名称和类型的记录:

data Movement = Movement { speed :: Double, distance :: Int } deriving (Show)

main = do
    print $ Movement 3.14 100
    print Movement {distance = 5, speed = 2.1}
    print Movement {speed = 9, distance = -4}

输出:

移动{速度 = 3.14, 距离 = 100}
移动{速度 = 2.1, 距离 = 5}
移动 {速度 = 9.0, 距离 = -4}

但从技术上讲,它不是tuple。Haskell确实有元组,但据我所知,它们不能命名。

这也与任何 C 派生语言中的简单结构相差无几。也许我错过了问题中的某些内容。

于 2009-09-29T03:34:26.687 回答
2

在 C# 中使用结构或类有什么问题?

public class SpeedDistance{
  public double Speed;
  public int Distance;
}
于 2009-09-29T03:23:04.270 回答
2

存在几种这样的语言。这种命名元组的词是“记录”。ML 语言家族有这样的记录,以及相应的类型。具体语言包括:SML、OCaml,以及重要的 F#。此链接解释了 F# 中的记录:http ://en.wikibooks.org/wiki/F_Sharp_Programming/Tuples_and_Records#Defining_Records

于 2013-01-23T10:45:25.593 回答
1

Swift 允许命名元组。您可以编写如下内容:

let interval = (start: 0, end: 10)
let start = interval.start

它们实际上是匿名结构。

于 2015-08-04T07:48:03.833 回答
0

谢谢阿兰。_ 这是我如何使用你的小费的。

轮播的动态图像加载器

<div id="owl" class="owl-carousel owl-theme">
    @foreach (var image in Model.Sketches)
    {
        <div class="item" >
            <a href="@image.SketchHref" id="a_@image.SketchNumber" target="_blank" >
                <img id="sketch_@image.SketchNumber" class="lazyOwl" style="border:1px solid #d1c7c7;outline : 0;max-height:350px;max-width:400px;" 
                    title="click for full size" alt="@image.SketchName" data-src="@image.SketchHref" /></a>
                    <div style="text-align:left;height:auto;vertical-align:bottom;padding:2px;font-size:1em;color:#DF3A01;">Sketch @image.SketchNumber of @Model.Sketches.Count()</div>
        </div>
    }
    </div>

对于 C#

    public List<Sketches> Sketches 
    {
        get
        {
            List<Sketches> hrefs = new List<Sketches>();

/* 图像名称匹配文件夹位置示例:1234101005_001.Gif 等于 "c:\images\1234\10\1005_BLD\" */

            var sketchFolder = Regex.Replace(some_image, @"(\d{4})(\d{2})(\d{4})", @"c:\Sketches\$1\$2\$3\_BLD");
            var sketchHref = Regex.Replace(some_image, @"(\d{4})(\d{2})(\d{4})", @"/sketches/$1/$2/$3/_BLD");
            Int16 i = 0;

            if (System.IO.Directory.Exists(sketchFolder))
            {
                List<string> gifs = GetGifs(sketchFolder);

                gifs.ForEach(delegate(String gif)
                {
                    string s = sketchHref + "/" + gif;
                    string f = sketchFolder + "/" + gif;

                    if (System.IO.File.Exists(f))
                    {
                        Sketches sketch = new Sketches(s, (++i).ToString(), gif);
                        hrefs.Add(sketch);
                    }
                    else // gif does not exist
                    {
                        Sketches sketch = new Sketches("placeholder.png", (++i).ToString(), gif);
                        hrefs.Add(sketch);
                    }
                });
            }
            else // folder does not exist
            {
                Sketches sketch = new Sketches("placeholder.png", (++i).ToString(), "");
                hrefs.Add(sketch);
            }
            return hrefs;
        }
    }

public class Sketches : Tuple<string, string, string>
{
    public Sketches(string SketchHref, string SketchNumber, string SketchName) : base(SketchHref, SketchNumber, SketchName) { }
    public string SketchHref { get { return this.Item1; } }
    public string SketchNumber { get { return this.Item2; } }
    public string SketchName { get { return this.Item3; } }
}
于 2015-06-24T14:39:27.400 回答
-1

我不确定你需要这个做什么 - 元组只是一个保存不同类型数据的结构。如果你真的想要命名属性,你将不得不创建一个自定义类型或动态创建一个匿名类型。

我不知道有任何静态类型的语言会支持这一点,但 C# 肯定不支持。

于 2009-09-29T03:21:00.287 回答