我想知道是否有任何语言允许命名元组。即:具有不同类型和可配置名称的多个变量的对象。
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的答案。
答案 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)
我知道;
两者都可以在.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#当然不会。