Цейлона имеет несколько различных концепций для вещей, которые могли бы все рассматриваться каким-то массив: List
, Tuple
, Sequence
, Sequential
, Iterable
, Array
, Collection
, Category
и т. Д. Чем они отличаются от этих типов и когда я должен их использовать?разница между List, кортежи, последовательность, последовательный, Iterable, Array и т.д. Цейлоном
разница между List, кортежи, последовательность, последовательный, Iterable, Array и т.д. Цейлоном
ответ
Лучшее место, чтобы начать узнавать об этих вещах на базовом уровне - это Ceylon tour. И место, чтобы узнать об этих вещах в глубину, - это module API. Также может быть полезно посмотреть на source files for these.
Как и все хорошие современные языки программирования, первые несколько интерфейсов являются супер абстрактными. Они построены вокруг одного официального участника и обеспечивают их функциональность через кучу дефолтных и фактических членов. (В языках программирования, созданных до Java 8, вы, возможно, слышали эту называемую «черту», чтобы отличить их от традиционных интерфейсов, которые имеют только формальные элементы и не функциональности.)
Категории
Давайте начнем говорить об интерфейсе Category
. Он представляет типы, которые вы можете спросить: «содержит ли этот сборник этот объект», но вы не можете быть в состоянии вывести кого-либо из членов из коллекции. Это формальный член:
shared formal Boolean contains(Element element)
Примером может служить совокупность всех факторов большое количество-можно эффективно проверить, если любое целое число является фактором, но не эффективно получить все факторы.
Iterable
Подтип Category
является интерфейсом Iterable
. Он представляет типы, из которых вы можете получить каждый элемент по одному, но не обязательно индексировать элементы. Элементы могут не иметь четко определенного порядка. Элементы могут даже не существовать, но генерируются «на лету». Коллекция может даже быть бесконечно длинной! Официальным членом является:
shared formal Iterator<Element> iterator()
Примером может служить поток символов, например, стандартный. Другим примером может служить диапазон целых чисел, предоставляемых циклу for, для которого больше памяти эффективнее генерировать числа по одному.
Это особый тип на Цейлоне и может быть сокращен {Element*}
или {Element+}
в зависимости от того, может ли итерируемый быть пустым или определенно не пуст, соответственно.
Коллекция
Один из подтипов Iterable
«s является интерфейсом Collection
. Он имеет одного официального участника:
shared formal Collection<Element> clone()
Но это не имеет большого значения. Важно то, что определяет Collection
эта строка в документации:
Все
Collection
s необходимы для поддержки четко определенного понятия значение равенства, но определение равенства зависит от вида коллекции.
В принципе, Collection
- это сборник, структура которого хорошо определена, чтобы быть равнозначной друг другу и клонироваться. Это требование для четко определенной структуры означает, что это последний из супер абстрактных интерфейсов, а остальные будут похожи на более знакомые коллекции.
Список
Один из подтипов Collection
«s является интерфейсом List
. Он представляет собой коллекцию, элементы которой мы можем получить по индексу (myList[42]
). Используйте этот тип, когда ваша функция требует, чтобы массив извлекал вещи, но не имеет значения, является ли он изменяемым или неизменным. Она имеет несколько формальных методов, но важно одно приходит от другого его надтипа Correspondence
:
shared formal Item? get(Integer key)
Sequential, последовательность, Пусто
Наиболее важный из подтипов List
«s является интерфейсом Sequential
. Он представляет собой неизменный List
. Цейлон любит этот тип и строит много синтаксиса вокруг него. Он известен как [Element*]
и Element[]
. Он имеет ровно два подтипа:
Empty
(ака[]
), который представляет пустые коллекцииSequence
(ака[Element+]
), который представляет собой непустые коллекции.
Поскольку коллекции неизменны, есть много вещей, которые вы можете сделать с ними, что вы не можете сделать с изменчивыми коллекциями. Во-первых, многочисленные операции могут завершиться неудачно с null
в пустых списках, например reduce
и first
, но если вы первый test that the type is Sequence
, вы можете гарантировать, что эти операции всегда будут успешными, потому что коллекция не может стать пустой позже (в конце концов, они неизменяемы).
Кортеж
Особенное подтип Sequence
является Tuple
, первый истинный класс, перечисленные здесь. В отличие от Sequence
, где все элементы ограничены одним типом Element
, у Tuple
есть тип для каждого элемента. Он получает специальный синтаксис на Цейлоне, где [String, Integer, String]
является неизменным списком ровно трех элементов с точно такими же типами именно в этом порядке.
Массив
Другой подтип List
является Array
, а также истинный класс. Это знакомый Java-массив, изменяемый список элементов фиксированного размера.
drhagen уже ответил на первую часть вашего вопроса очень хорошо, поэтому я просто немного расскажу о второй части: когда вы используете какой тип?
В целом: При написании функции принимайте наиболее общий тип, который поддерживает необходимые операции. Пока что так очевидно.
Category
очень абстрактно и редко полезно.
Iterable
следует использовать, если вы ожидаете какой-то поток элементов, которые вы только собираетесь перебрать (или использовать операции потока, как filter
, map
и т.д.).
Другая вещь, чтобы рассмотреть о Iterable
является то, что он имеет некоторый дополнительный синтаксис сахара в именованных аргументов:
void printAll({Anything*} things, String prefix = "") {
for (thing in things) {
print(prefix + (thing?.string else "<null>"));
}
}
printAll { "a", "b", "c" };
printAll { prefix = "X"; "a", "b", "c" };
Любой параметр типа Iterable
может подаваться в виде списка разделенных запятыми аргументов в конце списка названных аргументов. То есть,
printAll { "a", "b", "c" };
эквивалентно
printAll { things = { "a", "b", "c" }; };
Это позволяет изготовить выражения DSL-стиле; у tour есть несколько приятных примеров.
Collection
, как Correspondence
, довольно абстрактно и по моему опыту редко используется напрямую.
звучит так, как будто это должен быть часто используемый тип, но на самом деле я не помню его много. Я не знаю, почему. Я, кажется, пропустил это и объявил свои параметры как Iterable
или Sequential
.
Sequential
и Sequence
, когда вы хотите, неизменный, список фиксированной длины. Он также имеет некоторый синтаксический сахар: вариативные методы, такие как void foo(String* bar)
, являются ярлыками для параметра Sequential
или Sequence
. Sequential
также позволяет сделать использовать nonempty
оператор, который часто работает хорошо в сочетании с first
и rest
:
String commaSeparated(String[] strings) {
if (nonempty strings) {
value sb = StringBuilder();
sb.append(strings.first); // known to exist
for (string in strings.rest) { // skip the first one
sb.append(", ").append(string);
// we don’t need a separate boolean to track if we need the comma or not :)
}
return sb.string;
} else {
return "";
}
}
Я обычно использую Sequential
и Sequence
, когда я собираюсь перебора всех (что может быть дорогостоящим для общего Iterable
), хотя List
может быть лучшим интерфейсом для этого.
Tuple
никогда не должны использоваться в качестве Tuple
(за исключением редких случаев, когда вы абстрагируясь над ними), но с [X, Y, Z]
синтаксическими часто бывает полезным. Вы часто можете уточнить член Sequential
на Tuple
в подклассе, e. г. суперкласс имеет <String|Integer>[] elements
, который, как известно, в одном подклассе [String, Integer] elements
.
Array
Я никогда не пользовался как тип параметра, редко только как класс для создания и использования.