2009-09-29 3 views
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 и т. Д.).

Вы также можете написать небольшой пользовательский класс, но это та ситуация, которую я бы хотел избежать.

Я мог представить себе, что язык макросов может писать на вас что-то подобное на статическом языке, но я не знаю такого языка.

Это выходит из моего ответа от this question about return types.

+0

Поэтому я хотел бы избежать пользовательского класса/структуры является то, что я не люблю писать! Не более того. – ligos

+0

В этой строке я не должен включать Tuple. var result = CalculateStuffTuple (1,2); –

ответ

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 позволяет передавать параметры как свойства объекта.

+0

Это похоже на то, что я просил (по крайней мере, в C#). – ligos

-1

Я не уверен, что вам понадобится для этого - кортеж - это просто структура, которая хранит разные типы данных. Если вам действительно нужны именованные свойства, вам придется создавать пользовательский тип или создавать анонимный тип «на лету».

Я не знаю ни одного статически типизированного языка, который бы поддерживал это, но C#, конечно же, этого не делает.

3

Вы имеете в виду, что-то вроде Python's collections.namedtuple? Ну, Python (текущие версии, 2.6 и 3.1) поддерживает их ;-). Но, серьезно, я не знаю, какой статически типизированный язык имел их как встроенный.

2

Что не так с использованием структур или классов в C#?

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

Ну, публичное поле - плохая идея, конечно ... но 'public double Speed ​​{get; set;}' будет делать; -p –

+1

Мне нравятся мои кортежи неизменными. И для этого вместо этого требуются переменные readonly и конструктор, который только начинает становиться слишком длинным. – ligos

+1

Публичные поля в порядке, если и только если это весь класс содержит. Но кортежи также могут иметь много других приятных свойств, которые помогают при переходе в другие библиотеки. Если они записываются с нуля каждый раз, то они не взаимодействуют друг с другом. –

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} 

Но это технически не tuple. У Haskell есть есть кортежи, но они не имеют имени, насколько я знаю.

Это действительно недалеко от простой структуры на любом C-производном языке. Возможно, я пропустил что-то в этом вопросе.

6

Eiffel позволяет названные кортежи.

5

Я знаю;

  • Python (динамическая, строгая типизация)
  • Eiffel (статическая, строка типирование)

Оба они могут быть использованы в .net

И, вероятно, Lisp, вы можете сделать что-нибудь с Лиспе ,

39

Старый вопрос, но я нуждаюсь в лучшем решении.

Вы можете получить именованные параметры, используя тип 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); 

И еще польза из всех замечательных функций, которые позволяют использовать его как сложный ключ в словарях и т. д.

Единственным недостатком является то, что если вы планировали использовать этот кортеж только в рамках одного метода, вы должны объявить тип в пределах класса, содержащего этот метод. Для большинства приложений я не думаю, что это проблема.

+0

Это на самом деле не так уж плохо. Кроме того, я должен иметь кучу маленьких классов, обертывающих «Tuple <>». Но это лучше, чем необходимость повторной реализации IEquatable, IComparable и т. Д. – ligos

+1

Не могу поверить, что я никогда не думал об этом. Супер полезно. –

+0

Просто решение, которое я искал. Большой :) –

2

Несколько таких языков существуют. Слово для такого названного кортежа - это «запись». Семейство языков ML имеет такие записи вместе с соответствующими типами. Конкретные языки включают: SML, OCaml и, что важно, F #. Эта ссылка объясняет записи в F #: http://en.wikibooks.org/wiki/F_Sharp_Programming/Tuples_and_Records#Defining_Records

0

Спасибо 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> 

И для имени изображения 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; } } 
} 
1

Swift позволяет именованные кортежи. Вы можете написать что-то вроде:

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

Это фактически анонимные структуры.

Смежные вопросы