Вопрос или проблема
Исходя из моего опыта работы с современными языками программирования и сценарного языка, я считаю, что большинство программистов обычно привыкли обращаться к первому элементу массива как к индексу 0 (ноль).
Я уверен, что слышал о языках, отличных от zsh
, которые начинают индексацию массивов с 1 (один); это нормально, так как это равноудобно. Однако, поскольку ранее выпущенные и широко используемые языки сценариев оболочки ksh
и bash
оба используют 0, зачем кому-то было бы изменять эту общепринятую конвенцию?
Кажется, нет никаких существенных преимуществ в использовании 1 как первого индекса; тогда единственное объяснение, которое я могу придумать относительно этой несколько «эксклюзивной функции» для оболочек, будет заключаться в том, что «они просто сделали это, чтобы немного похвастаться своей классной оболочкой».
Тем не менее, я не знаю много о zsh
или его истории, и есть высокая вероятность, что моя тривиальная теория об этом не имеет смысла.
Есть ли объяснение этому? Или это просто вопрос личного вкуса?
- Практически все массивы оболочек (Bourne, csh, tcsh, fish, rc, es, yash) начинаются с 1. ksh — единственное исключение, о котором я знаю (bash просто скопировал ksh).
- Большинство интерпретируемых языков того времени (начало 90-х):
awk
,tcl
по меньшей мере, а также инструменты, обычно используемые из оболочки (cut -f1-3
,head -n 3
,sort -k1,3
,cal 1 2015
,comm -1
) начинаются с 1.sed
,ed
,vi
нумеруют свои строки, начиная с 1… - zsh берет лучшее от оболочки Bourne и csh. Единственный массив оболочки Bourne
$@
начинается с$1
. zsh последовательно обрабатывает$@
(как в Bourne) или$argv
(как в csh). Посмотрите, как запутанно это выглядит вksh
, где${@:0:1}
не даст вам первый позиционный параметр, например. - Оболочка — это пользовательский инструмент перед тем, как стать языком программирования. Для большинства пользователей имеет смысл, чтобы первый элемент был в
$a[1]
. Это также означает, что количество элементов совпадает с последним индексом (в zsh, как и в большинстве других оболочек, кроме ksh, массивы не разреженные). a[1]
для первого элемента согласуется сa[-1]
для последнего.
Так что, на мой взгляд, вопрос должен звучать скорее так: Почему Дэвид Корн решил начать индексацию своих массивов с 0?
Что касается вашего:
“Однако, поскольку ранее выпущенные и широко используемые языки сценариев оболочки ksh и bash оба используют 0”
Обратите внимание, что хотя bash был впервые выпущен за несколько месяцев до zsh (в июне 1989 года по сравнению с декабрем 1990 года), поддержка массивов была добавлена в их соответствующие версии 2.0, но для zsh это было выпущено в 1991 году, тогда как для bash — значительно позже, в 1996 году.
Первой оболочкой Unix, введшей массивы (если вы не хотите считать оболочку Thompson 1970-х с её позиционными параметрами $1
..$2
) была csh в конце 70-х годов, индексы которой начинаются с одного. И её код был свободно доступен, в то время как ksh был собственническим и часто не включался по умолчанию в Unix (продавался отдельно по высокой цене) до конца 80-х годов. Хотя код ksh93 был выпущен как открытый исходный код около 2000 года, код ksh88, до сих пор, никогда не был (хотя не слишком трудно найти исходный код ksh86a и ksh88d на archive.org сегодня, если вам интересно археология).
Я думаю, самое правдоподобное объяснение этому связано с встроенной функцией обратного массива в zsh
Если у вас есть массив из 4 элементов, скажем, myvar=(1 2 3 4)
, и вы хотите получить доступ к 4-му элементу, это будет print $myvar[4]
, верно?
Тем не менее, если вы хотите создать цикл, который перечисляет элементы этого массива в обратном порядке, это просто вопрос использования отрицательных индексов:
print $myvar[-1] # выведет 4
print $myvar[-2] # выведет 3
print $myvar[-3] # выведет 2
print $myvar[-4] # выведет 1
Это должно объяснить, поскольку начиная с нуля, вы не сможете получить доступ к одному из этих элементов, так как -0
не существует.
Вторая причина, стоящая за этим, вероятно, связана с тем, что код на C, относящийся к переменным в zsh, использует int
или double int
для определения индексов массива, и поскольку он использует Двоичное представление со знаком для представления отрицательных чисел, нет способа представить -0
(Подписанный ноль), как это можно сделать с переменными плавающей запятой.
Если вам действительно привычны индексы, начинающиеся с 0, я рекомендую вам использовать опцию KSH_ARRAYS
для исправления этого.
И, воспользовавшись комментарием @cuonglm, функции csh
, реализованные в zsh
, объясняются здесь. Похоже, это не историческая причина, а способ предоставить удобную рабочую среду для тех, кто привык к csh
.
Ответ или решение
Почему первый элемент массива в Zsh индексируется с 1 вместо 0?
Когда речь заходит о языках программирования и сценариев, большинство разработчиков привыкли к тому, что индексация массивов начинается с нуля. Однако в Zsh, как и во многих других командных оболочках, таких как Csh и Tcsh, первый элемент массива индексируется с 1. В этой статье мы подробно рассмотрим причины этого выбора и исторические контексты.
Историческая перспектива и традиция оболочек
Несмотря на то, что такие языки, как Ksh и Bash, индексируют массивы с 0, многие сценарные оболочки, существовавшие до их появления, использовали индексацию с 1. Например, Csh, который был разработан в конце 1970-х, стал первым Unix-скриптовым языком, внедрившим массивы с индексами, начинающимися с единицы. Эта традиция продолжалась и в других оболочках, таких как Fish и Rc.
Таким образом, Zsh выбрала индексацию с 1, чтобы быть согласованной с уже существующими оболочками и использовать подходы, к которым пользователи могли быть привычны. Такой подход также обеспечивает некоторую унификацию с позиционными параметрами, которые в Unix-оболочках начинаются с $1, что делает работу с массивами более интуитивной для пользователя.
Удобство для пользователя
Zsh, как оболочка, нацелена на удобство использования для конечного пользователя, а не исключительно на возможности программирования. Индексация с 1 позволяет пользователям проще управлять элементами массивов: например, если у вас есть массив длиной 4, последний элемент явно обозначается как $myvar[4], в то время как при индексации с 0 его индексом было бы 3. Это делает структуру более простой и понятной, особенно для тех, кто не является опытным программистом.
Отрицательные индексы
Zsh предлагает интересную функциональность с помощью отрицательных индексов. Например, при использовании массива myvar=(1 2 3 4), доступ к элементам можно получить следующим образом:
print $myvar[-1] # выведет 4
print $myvar[-2] # выведет 3
Преимущества отрицательных индексов становятся очевидными, когда нужно обратиться к элементам массива с конца. Если бы индексация начиналась с 0, попытка получить доступ к элементу с индексом -0 привела бы к путанице, так как такая индексация не имеет смысла в контексте отрицательных значений.
Параметры реализации
С точки зрения реализации, Zsh использует целочисленные индексы (int
или double int
), что накладывает ограничения на использование отрицательных значений в контексте массивов. В частности, из-за принципов представления чисел в памяти, использование двухкомплемента для отрицательных чисел исключает возможность создания индекса -0. Это дополнительное ограничение может быть одной из причин выбора индексации с 1.
Заключение
Таким образом, выбор индексации с 1 в Zsh можно объяснить несколькими факторами: исторической традицией в Unix-системах, удобством для конечного пользователя и особенностями реализации. Этот подход делает работу с массивами более интуитивной для большинства пользователей, которые уже знакомы с концепциями оболочек и позиционными параметрами.
Хотя удобство использования и пользовательские привычки являются основными причинами, нельзя забывать и о соображениях реализации — такими особенностями, как ограничение отрицательных индексов, значительно упрощается работа с массивами и позволяет избежать путаницы.
Таким образом, Zsh не просто выбирает альтернативную индексацию, но и делает это с учетом предшествующих практик и пользовательского опыта, что отражает философию облегчения работы с системой.