Подтвердить что ты не робот

Причины для точечной нотации для кортежа

Есть ли какая-либо техническая причина, по которой Rust предназначен для использования точечной нотации для кортежей вместо использования индексной нотации (t[2])?

let t = (20u32, true, 'b')
t.2 // -> 'b'

Точечное обозначение кажется естественным при доступе к свойствам структуры и объекта. Я не мог найти ресурс или объяснение в Интернете.

4b9b3361

Ответ 1

Это решение было принято в RFC 184. Раздел Мотивация содержит сведения:

Прямо сейчас доступ к полям кортежей и кортежей-структур невероятно болезненен: для извлечения значений нужно полагаться только на сопоставление шаблонов. Это стало такой проблемой, что в стандартной библиотеке (core::tuple::Tuple*) было создано двенадцать черт, чтобы упростить доступ к значениям кортежа, добавив методы .valN(), .refN() и .mutN(), чтобы помочь в этом. Но это не очень приятное решение - для этого требуются черты, которые должны быть реализованы в стандартной библиотеке, а не на языке, и для того, чтобы эти свойства были импортированы при использовании. В целом это не проблема, потому что большую часть времени std::prelude::* импортируется, но это все еще хак, который не является реальным решением проблемы. Он также поддерживает только кортежи длиной до двенадцати, что обычно не является проблемой, но подчеркивает, насколько плохо текущая ситуация.

Обсуждение связанного запроса на растяжение также полезно.

Ответ 2

Я не принимал участия в дизайнерских решениях, но здесь моя перспектива:

Кортежи содержат смешанные типы. То есть свойство type_of(t[i]) == type_of(t[j]) не может быть гарантировано.

Однако обычная индексация работает в предположении, что i in t[i] не обязательно должна быть константой времени компиляции, что, в свою очередь, означает, что тип t[i] должен быть однородным для всех возможных i, Это верно во всех других коллекциях ржавчины, которые реализуют индексирование. В частности, типы ржавчины становятся индексируемыми посредством реализации Index, как показано ниже:

pub trait Index<Idx> where Idx: ?Sized {
    type Output: ?Sized;
    fn index(&'a self, index: Idx) -> &'a Self::Output;
}

Итак, если вы хотите, чтобы кортеж выполнял индексирование, какой тип должен Self::Output быть? Единственный способ сделать это: сделать Self::Output перечисление, что означает, что доступ к элементам должен быть обернут вокруг бесполезного предложения match t[i] (или чего-то подобного) на стороне программиста, и вы поймаете типа во время выполнения вместо времени компиляции.

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

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

Ответ 3

Причина использования синтаксиса t.2 вместо t[2] лучше всего объясняется в этом comment:

Синтаксис индексирования везде имеет согласованный тип, но кортеж гетерогенен, поэтому a[0] и a[1] будут иметь разные типы.

Ответ 4

Я хочу дать ответ из своего опыта, используя функциональный язык (Ocaml) для того времени, так как я разместил этот вопрос.

Помимо ссылки @rom1v, синтаксис индексирования, такой как a[0], везде также используется в какой-то структуре последовательности, кортежей которой нет. Например, в Ocaml кортеж (1, "one") имеет тип int * string, который соответствует декартовому произведению в математике (т.е., плоскость R ^ 2 = R * R). Кроме того, доступ к кортежу с индексом nth считается унииоматическим.

Из-за своей полиморфной природы кортеж можно почти мыслить как запись/объект, который часто предпочитает точечную нотацию, такую ​​как a.fieldName, как соглашение о доступе к своему полю (кроме языка, такого как Javascript, который обрабатывает такие объекты, как словари и разрешает доступ к строковым литералам, таким как a["fieldname"]. Единственный язык, который я знаю об использовании синтаксиса индексирования для доступа к полю, - Lua.

Лично я считаю, что синтаксис типа a.(0) имеет тенденцию выглядеть лучше, чем a.0, но это может быть преднамеренно (или нет) неудобно, учитывая, что в большинстве функциональных языков он идеален для сопоставления шаблонов с кортежем вместо обращения к нему его индекс. Поскольку Rust также является обязательным, синтаксис, например a.10, может быть хорошим напоминанием о совпадении шаблонов или "идти использовать структуру" уже.