#arrays #string #ada
#массивы #строка #ada
Вопрос:
Итак, я впервые пишу в Ada и должен создать этот предварительно заполненный массив строк, чтобы я мог использовать случайный метод и каждый раз вызывать другое значение.
poolOfWords: constant array(1..50) of string := ("gum","sin","for","cry","lug","bye","fly",
"ugly", "each","from","work","talk","with","self", "pizza","thing","feign","friend",
"elbow","fault", "dirty","budget","spirit","quaint","maiden","escort","pickax",
"example","tension","quinine","kidney","replica","sleeper", "triangle","kangaroo",
"mahogany","sergeant","sequence","moustache","dangerous","scientist",
"different","quiescent", "magistrate","erroneously","loudspeaker",
"phytotoxic","matrimonial","parasympathomimetic","thigmotropism");
Но когда я пытаюсь скомпилировать, я получаю эту ошибку: «неограниченный тип элемента в объявлении массива».
Я погуглил по всему Интернету и не смог найти решение этой проблемы. Я даже пытался использовать unbounded_string, но это не сработало. Он отлично работает, когда я предварительно заполняю массив целых чисел с плавающей запятой, но когда дело доходит до строк, он не работает.
Может кто-нибудь помочь мне и объяснить, что происходит и как это решить? Я действительно не хочу объявлять массив, а затем заполнять каждый из 50 индексов один за другим.
Комментарии:
1. Основная проблема очевидна: строки имеют разные размеры, поэтому их нельзя хранить в одном массиве. Определите «не сработало так хорошо» для unbounded_string . Возможно, это лучшее решение здесь (хотя bounded_string, ограниченный длиной самого длинного элемента, также был бы хорошим вариантом). Используйте любой из них, проработайте их трудности и спросите (с более подробной информацией), если вы застряли.
2. @BrianDrummond но если я использую unbounded_string , выдается сообщение об ошибке, в котором говорится, что я пытаюсь присвоить строку массиву unbounded_string , и я думаю , что решением этого было бы использовать To_Unbounded_String() в каждом элементе предварительно заполненного массива… Верно?
3. Да. Вы можете переименовать To_Unbounded_String в » «, чтобы упростить себе жизнь.
4. Потрясающе! Большое вам спасибо, ребята!!!
5.
function " " (Source : String) return Unbounded_String renames To_Unbounded_String;
. Вы также можете сократитьUnbounded_String
, чтобы сделать вашу жизнь еще проще (пример здесь: github.com/zertovitch/hac/blob/master/src/hal.ads )
Ответ №1:
Ваша проблема связана с тем фактом, что String
в Ada это неограниченный тип. Это означает, грубо говоря, что вам нужно указать «что-то», чтобы иметь полезный тип. В случае String
вам нужно указать длину строки, поскольку a String
— это просто массив Character
. Если вы скажете что-то вроде
X : String;
компилятор жалуется, поскольку он не знает длину X
и не знает, сколько памяти нужно зарезервировать X
. Вам нужно сказать что-то вроде
X : String(1..6);
или что-то вроде
X : String := "foobar";
Обратите внимание, что во втором случае вам не нужно указывать диапазон индексов, поскольку компилятор может вывести его из того факта, что вы используете 6- Character
строку для инициализации X
.
Это объясняет, почему запрещено объявлять массив just String
. Когда вы объявляете массив, компилятору необходимо знать размер каждой записи (все записи должны иметь одинаковый размер, это делает доступ к случайной записи массива очень эффективным). Если вы объявите массив just String
, компилятор не будет знать, сколько памяти выделить для каждой записи, поскольку длина не указана.
Обратите внимание, что вместо этого это сработало бы (отказ от ответственности: у меня сейчас нет компилятора Ada, поэтому я не могу проверить код)
subtype ZIP_Code is String (1..5);
type ZIP_Code_Array is array(Positive range <>) of ZIP_Code;
поскольку теперь компилятор знает размер каждой записи a ZIP_Code_Array
(5 Character
).
Однако в вашем случае все строки имеют разные размеры. Я вижу два возможных решения
- Если максимальная длина известна заранее, вы можете использовать
subtype
подход, показанный выше, и дополнить строки пробелами. Это зависит от вашего контекста, является ли это подходящим решением или нет - Подход, который я обычно использую, заключается в создании массива
Unconstrained_String
, который я инициализирую следующим образомfunction " "(X: String) return Unbounded_String renames To_Unbounded_String; poolOfWords: constant array(1..50) of Unbounded_String := ( "gum", "sin", "for", -- and so on... );
Обратите renames
внимание на то, что определяет унарный
как псевдоним для To_Unbounded_String
. Это просто синтаксический сахар, который позволяет вам писать "gum"
вместо To_Unbounded_String("gum")
. Кто-то съеживается от такого синтаксического сахара (и я тоже не в восторге), но в данном случае я думаю, что это того стоит, поскольку это делает код «легче». Было бы неплохо иметь определение унарного
рядом с его использованием, просто для ясности.
Альтернативой использованию Unbounded_String
является использование универсального пакета Bounded_Strings
и определение poolOfWords
в виде массива Bounded_String
. A Bounded_String
может содержать строки переменной длины, если длина меньше, чем привязка, указанная при создании экземпляра Bounded_Strings
пакета. Для преобразования туда и обратно String
вы можете использовать тот же «трюк с переименованием».
Мое личное предпочтение отдается Unbounded_String
, если только у меня нет какой-то особой причины, которая заставляет меня использовать Bounded_String
.
Ответ №2:
Другой вариант — использовать стандартные контейнеры Ada. Например:
Package String_Holder is new Ada.Containers.Indefinite_Holders(
"=" => Ada.Strings.Equal_Case_Insensitive,
Element_Type => String
);
Function " "( Right : String_Holder.Holder ) return String
renames String_Holder.Element;
Function " "( Right : String ) return String_Holder.Holder
renames String_Holder.To_Holder;
Позволяет хранить в держателе значения типа разного размера String
, чтобы вы могли отказаться от какой-либо зависимости Ada.Strings.Unbounded_String
и использовать что-то вроде:
poolOfWords: constant array(Positive range <>) of String_Holder.Holder :=
"gum", "sin", "for", "cry", -- ...
"Stuff"
);
Функция Get_Word(индекс : положительный) возвращает строку
( poolOfWords(индекс)) с Pre => Index в диапазоне poolOfWords;
В качестве альтернативы, вы могли бы использовать Ada.Containers.Indefinite_Vectors
примерно так:
Package String_Vector is new Ada.Containers.Indefinite_Vectors(
"=" => Ada.Strings.Equal_Case_Insensitive,
Index_Type => Positive,
Element_Type => String
);
хотя в Ada 2012 есть одна проблема с этим: вы не можете инициализировать такой вектор непосредственно в объявлении, но можете инициализировать его с помощью вызова функции:
Function Populate return String_Vector.Vector is
Begin
Return Result : String_Vector.Vector do
Result.Append( "some" );
Result.Append( "data" );
Result.Append( "HERE" );
End Return;
End Populate;
Возможность сказать X : String_Vectors.Vector := ("this", "that", "the other")
находится в Ada 2020 .