Как мне создать строку из других строк в Ada?
Вопрос
Я хочу вывести строку заголовка в файле журнала, а затем строку "-" перед данными.Чтобы сделать это, я создаю строку заголовка, а затем выводю такое же количество '-'.
Но приведенный ниже код всегда завершается с ошибкой CONSTRAINT_ERROR, потому что сгенерированная строка не состоит из 1024 символов.В Ada для назначения строк требуется точно такая же длина, а не просто достаточная емкость.
Вариант 1) состоит в том, чтобы вычислить точную длину, но это хрупко для будущих изменений.Вариант 2) заключается в использовании чего-то другого, кроме String.
procedure F() is
Msg : String(1..1024);
begin
Open_Log();
Msg := FLS(" Field1", 12) &
"|" & FLS(" Field2", 12) &
"|" & FLS(" Field3", 16);
Log_To_File("# " & Msg);
Log_To_File("# " & Fill_String(Msg'Last, '-'));
end;
Решение
Многим людям, которые привыкли к пошаговому построению строк на языке Си, трудно представить себе строки Ada, которые предполагается, что вы должны инициализировать и использовать как есть.Когда вы учитываете этот факт о строках Ada, решение становится намного проще.Я даже могу отказаться от твоей рутины "Наполнения".
procedure F() is
Msg : constant String
:= FLS(" Field1", 12) &
"|" & FLS(" Field2", 12) &
"|" & FLS(" Field3", 16);
Separator : constant String := (1..Msg'length => '-'); --'
begin
Open_Log();
Log_To_File("# " & Msg);
Log_To_File("# " & Separator);
end;
(Примечание:Комментарий - это способ вернуть SO colorizer в нужное русло)
Если бы вам не нужно было иметь разделитель одинаковой длины, вам даже не нужно было бы объявлять переменную.
Если бы это был я, я бы сделал что-то вроде Log_To_File
следите за длиной и создавайте собственный разделитель нужного размера по запросу.Тогда вы могли бы просто написать:
Open_Log();
Log_To_File ("# " & FLS(" Field1", 12) &
"|" & FLS(" Field2", 12) &
"|" & FLS(" Field3", 16));
Log_Separator_To_File;
Другие советы
Просто объявите Msg как строку вместо String(1 ..1024)
procedure F() is
Msg: String
:= FLS(" Field1", 12) &
"|" & FLS(" Field2", 12) &
"|" & FLS(" Field3", 16);
--// this 'magically' declares Msg as a String(1 .. Something)
--// with the right Something
begin
Open_Log();
Log_To_File("# " & Msg);
Log_To_File("# " & Fill_String(Msg'Last, '-')); --'
end;
Одним из подходов может быть написание функции, которая заполняет строку фиксированной длины входной строкой динамического размера, дополняя ее пробелами:
procedure Pad_String(Str: in String; Dest: out String; Len: out Integer) is
begin
Len := Str'Last - Str'First + 1;
Dest(Dest'First .. Dest'First + Len - 1) := Str(Str'First .. Str'First + Len - 1);
Dest(Dest'First + Len .. Dest'Last) := Fill_String(Dest'Last - Len, ' ');
end Pad_String;
Обработка строк Ada позволяет вам передавать любой буфер фиксированной длины в Dest
и тот 'First
и 'Last
атрибуты будут правильными в теле процедуры.
Тогда ваш код мог бы стать:
procedure F() is
Msg : String(1..1024);
Len : Integer;
begin
Open_Log();
Pad_String( FLS(" Field1", 12) &
"|" & FLS(" Field2", 12) &
"|" & FLS(" Field3", 16),
Msg,
Len);
Log_To_File("# " & Msg(1 .. Len));
Log_To_File("# " & Fill_String(Len, '-'));
end;
Для удобства вы можете использовать функции строкового конструктора в Ada.Strings.Fixed
, Ada.Strings.Bounded
или Ada.Strings.Unbounded
.Они перегружают оператор * для "репликации символа или строки указанное количество раз". Например,
with Ada.Strings.Unbounded; use Ada.Strings.Unbounded;
...
Log_To_File("# " & Length(Msg) * '-');
Я выяснил, как использовать Unbounded_String .Этот тип будет принимать строки другого размера.
Вы не можете создать неограниченную строку с помощью оператора &, если вы не используете неограниченные строки, поэтому используйте функцию To_Unbounded_String .
with Ada.Strings.Unbounded;
procedure F() is
use Ada.Strings.Unbounded;
Msg : Unbounded_String;
begin
Open_Log();
Msg := Ada.Strings.Unbounded.To_Unbounded_String(
FLS(" Field1", 12) &
"|" & FLS(" Field2", 12) &
"|" & FLS(" Field3", 16));
Log_To_File("# " & Ada.Strings.Unbounded.To_String(Msg));
Log_To_File("# " &
Fill_String(Ada.Strings.Unbounded.Length(Msg), '-'));
end;