允许命名元组的语言

时间:2009-09-29 03:16:17

标签: c# return-value tuples

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

E.g:

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#)可以做一个字典,但除非所有项目属于同一类型,否则这不是类型安全的。或者你可以使用元组类型,但这意味着你有成员的固定名称(Var1,Var2等)。

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

我可以想象一个宏处理语言可以用静态语言编写类似的东西,但我不知道这种语言。

这来自我this question about return types的答案。

12 个答案:

答案 0 :(得分:40)

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

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

我也讨厌Tuples有未命名的参数使代码无法读取这一事实,但不能忽略它自己实现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);

您仍然可以从所有精彩的元组功能中受益,这些功能可以让您将其用作词典中的复杂键等。

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

答案 1 :(得分: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如何允许您将选项作为对象的属性传递。

答案 2 :(得分:6)

Eiffel允许命名元组。

答案 3 :(得分: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/

答案 4 :(得分:5)

我知道;

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

两者都可以在.net

中使用

也许是Lisp,你可以用Lisp做任何事情。

答案 5 :(得分:3)

你的意思是,像Python的collections.namedtuple?好吧,Python(当前版本,2.6和3.1)支持它们;-)。但严重的是,我不知道有一种静态类型的语言将它们作为内置函数。

答案 6 :(得分: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}

输出:

Movement {speed = 3.14, distance = 100}
Movement {speed = 2.1, distance = 5}
Movement {speed = 9.0, distance = -4}

但它在技术上不是元组。 Haskell 确实有元组,但据我所知它们并不是可以命名的。

这与任何C派生语言中的简单结构相距不远。也许我错过了一些问题。

答案 7 :(得分:2)

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

public class SpeedDistance{
  public double Speed;
  public int Distance;
}

答案 8 :(得分:2)

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

答案 9 :(得分:1)

Swift允许命名元组。你可以这样写:

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

它们实际上是匿名结构。

答案 10 :(得分:0)

谢谢Alain。这是我如何使用你的小费。

旋转木马的动态图像加载器

<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等于&#34; c:\ images \ 1234 \ 10 \ 1005_BLD \&#34; * /

            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; } }
}

答案 11 :(得分:-1)

我不确定你需要什么 - 元组只是一个包含不同类型数据的结构。如果您真的想要命名属性,则必须动态创建自定义类型或创建匿名类型。

我不知道任何支持这种情况的静态类型语言,但C#当然不会。