Языки, которые позволяют названные кортежи
Мне было интересно, существуют ли какие-либо языки, которые допускают именованные кортежи. Т.е.: объект с несколькими переменными различного типа и настраиваемое имя.
Например:
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())
Я мог бы понять, как динамика может поддерживать такую функцию. Статические языки, которые я обычно плаваю (например, С#), могут выполнять словарь, но это не безопасно, если все элементы одного типа. Или вы можете использовать тип Tuple, но это означает, что у вас есть фиксированные имена членов (Var1, Var2 и т.д.).
Вы также можете написать небольшой пользовательский класс, но эту ситуацию я бы хотел избежать.
Я мог представить, что язык макросов может script что-то вроде этого для вас на статическом языке, но я не знаю такого языка.
Это выходит из моего ответа из этого вопроса о типах возврата.
Ответы
Ответ 1
В С# у вас есть анонимные типы; они похожи, но имеют свои собственные ограничения:
var result = new { Speed = 12.4, Distance = 8, Caption = "car 1" };
Однако использовать их в качестве вызывающего абонента трудно, если только вы не используете "cast by example" (хрупкое), отражение или dynamic
. Из трех последних наиболее аппетитно.
dynamic result = GetSomething();
Console.WriteLine(result.Speed);
Console.WriteLine(result.Distance);
В большинстве случаев было бы лучше просто использовать обычный класс, но этот подход имеет практическое применение; например, посмотрите, как они используются в ASP.NET MVC для простой и удобной передачи информации о конфигурации (что в противном случае требовало бы словаря). Немного похоже на то, как jQuery позволяет передавать параметры как свойства объекта.
Ответ 2
Старый вопрос, но мне нужно лучшее решение, я думаю.
Вы можете получить именованные параметры, используя тип 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);
И вы по-прежнему пользуетесь всеми замечательными функциями набора, которые позволяют использовать его как сложный ключ в словарях и т.д.
Единственным недостатком является то, что если вы планировали использовать этот кортеж только в рамках одного метода, вам нужно объявить тип в рамках этого метода, содержащего класс. Для большинства приложений я не думаю, что проблема.
Ответ 3
Eiffel позволяет названные кортежи.
Ответ 4
Я знаю
- Python (динамический, сильный ввод текста)
- Eiffel (статический ввод строки)
Оба могут использоваться в .net
И, вероятно, Lisp, вы можете сделать что угодно с Lisp.
Ответ 5
Теперь это поддерживается, начиная с С# 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/
Ответ 6
Вы имеете в виду что-то вроде Python collections.namedtuple? Ну, Python (текущие версии, 2.6 и 3.1) поддерживает их;-). Но серьезно, я не знаю, какой статически типизированный язык имел их как встроенный.
Ответ 7
Я не уверен, что это именно то, что вы ищете, но в 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-производном языке. Возможно, я пропустил что-то в этом вопросе.
Ответ 8
Что не так с использованием структур или классов в С#?
public class SpeedDistance{
public double Speed;
public int Distance;
}
Ответ 9
Несколько таких языков существуют. Слово для такого названного кортежа - это "запись". Семейство языков ML имеет такие записи вместе с соответствующими типами. Конкретные языки включают: SML, OCaml и, что важно, F #. Эта ссылка объясняет записи в F #: http://en.wikibooks.org/wiki/F_Sharp_Programming/Tuples_and_Records#Defining_Records
Ответ 10
Swift позволяет использовать названные кортежи. Вы можете написать что-то вроде:
let interval = (start: 0, end: 10)
let start = interval.start
Они представляют собой анонимные структуры.
Ответ 11
Спасибо Alain. Вот как я использовал ваш совет.
Динамический загрузчик изображений для карусели
<div id="owl" class="owl-carousel owl-theme">
@foreach (var image in Model.Sketches)
{
<div class="item" >
<a href="@image.SketchHref" id="[email protected]" target="_blank" >
<img id="[email protected]" 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>
И для С#
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; } }
}
Ответ 12
Я не уверен, для чего вам это нужно - кортеж - это просто структура, которая содержит разные типы данных. Если вам действительно нужны именованные свойства, вам нужно будет создать собственный тип или создать анонимный тип на лету.
Я не знаю ни одного статически типизированного языка, который бы поддерживал это, но С#, конечно же, не делает.