Вопрос или проблема
Почему диапазоны Swift не являются Comparable
, если их элемент типа T
является сопоставимым? (такими как Int
, String
, Double
и т. д.).
Например:
let rangeFive = 1...10
let rangeSix = 1...10
rangeFive < rangeSix
ИЛИ
let rangeFive = 1...10
let rangeSix = 1...10
rangeFive <= rangeSix
ИЛИ
let rangeFive = 1...10
let rangeSix = 1...10
rangeFive == rangeSix
let minRangeFive = rangeFive.min()
let maxRangeSix = rangeSix.max()
minRangeFive < maxRangeSix
// Ошибка: Бинарный оператор '<' не может быть применен к двум 'ClosedRange<Int>.Element?' (также известный как 'Optional<Int>')
Я попробовал rangeFive == rangeSix
– и это работает, но не с другими операторами сравнения. Почему так получается, что когда типы диапазонов содержат Comparable
данные, все типы диапазонов не являются Comparable
и не соответствуют протоколу Comparable
? Сопоставимые диапазоны Swift не сопоставимы, т.е. «все типы диапазонов не сопоставимы, т.е. не соответствуют требованиям протокола Comparable», в то время как тип данных диапазона partialrangefrom, partialrangeupto, partialrangethrought<T>, где T является сопоставимым типом данных (Int, String, Double), является сопоставимым.
Сделать диапазоны сопоставимыми привело бы к большему количеству путаницы, чем стоит, потому что нет очевидно правильного ответа на вопрос, что значит, что один диапазон больше другого.
Мы можем согласиться с тем, что 1...2
определенно меньше, чем 3...4
, и что 1...
вероятно следует считать меньше, чем 2...
.
Но что насчет перекрывающихся диапазонов?
Должен ли 10...20
быть меньше, чем 10...100
?
Существует несколько способов, как мы могли бы это определить, и у каждого из них есть проблемы:
- Диапазон
a
меньше диапазонаb
, если как его нижние, так и его верхние границы меньше верхних границb
.- Это не работает для перекрывающихся диапазонов, где ни один не меньше и не больше другого. Это нарушает требование Comparable быть тотальным порядком.
- Диапазон
a
меньше диапазонаb
только если его нижняя граница меньше нижней границы другого- Это приводит к другим странным ситуациям, когда
1...10 < 2...9
будет истинным (потому что1 < 2
), но одновременно1...10 > 2...9
также будет истинным (потому что10 > 9
).
- Это приводит к другим странным ситуациям, когда
- Возможно, вы могли бы определить это с точки зрения “центра” диапазона, но:
- Это не работает для бесконечных диапазонов
- Не работает для элементов, среднее которых нельзя вычислить. Например, какова середина диапазона
"foo"..."bar"
?
Равенство не имеет этой проблемы, потому что вы можете просто сравнить границы и получить однозначно правильный ответ. Именно поэтому диапазоны условно Equatable
, но никогда не Comparable
.
Ответ или решение
В языке Swift типы диапазонов (ranges) не соответствуют протоколу Comparable
, даже если их элементы имеютComparable-свойства. Это может вызывать непонимание, особенно когда в диапазоне хранятся сравнимые типы, такие как Int
, String
или Double
. Рассмотрим подробнее причины, по которым диапазоны не могут быть сравнены, и критерии, по которым Swift реализует свои диапазоны.
1. Проблемы с определением порядка
Одной из главных причин, по которой диапазоны не соответствуют протоколу Comparable
, является отсутствие однозначного определения, как можно сравнивать диапазоны друг с другом. Например:
- Два диапазона могут не пересекаться, что позволяет установить порядок, например, диапазон
1...2
меньше диапазона3...4
. - Однако, когда диапазоны перекрываются, становится сложно установить, какой из них больше. Например, диапазон
10...20
и10...100
имеют общую границу, и сложно определить, какой из них «больше» по сравнению с другим.
2. Протокол Comparable
требует строгого порядка
Протокол Comparable
требует, чтобы все значения типа можно было сравнить так, чтобы для любых двух значений a
и b
одно из следующих условий всегда выполнялось: a < b
, a == b
, или a > b
. В случае диапазонов с перекрывающимися значениями это требование не выполняется, так как диапазоны могут не поддаваться строгой сортировке.
3. Альтернативные определения несоответствия
Рассмотрим несколько альтернативных возможностей определения отношений между диапазонами:
-
Сравнение по границам: Если сравнивать нижние и верхние границы диапазонов, то можно столкнуться с ситуациями, когда диапазоны конфликтуют. Например, диапазоны
1...10
и2...9
будут по-разному относиться в зависимости от того, какая граница используется для сравнения:1...10 < 2...9
будет истинно, так как1 < 2
, но и1...10 > 2...9
будет истинно, потому что10 > 9
.
-
Определение по центру диапазона: Другой вариант — рассчитывать "центр" диапазона, но это сложно реализовать для бесконечных диапазонов или для строк, так как невозможно найти среднее значение, например, между
"foo"
и"bar"
.
4. Выравнивание по определению эквивалентности
Проблема, с которой мы сталкиваемся с неравенством, не касается эквивалентности. Для определения равенства диапазонов достаточно сравнить их нижние и верхние границы. Поэтому диапазоны в Swift реализуют протокол Equatable
, позволяя проверять совпадение диапазонов, но никогда не реализуют Comparable
.
Заключение
Таким образом, причина, по которой диапазоны в Swift не соответствуют протоколу Comparable
, заключается в их сложности определения порядка и потенциальной путанице при использовании операторов сравнения. Эквивалентность (равенство) в этом контексте проще определить, так как мы можем опираться на границы диапазонов. Важно понимать это различие, чтобы избежать недоразумений при работе с диапазонами в Swift и соблюдать строгие правила языка.