Как проверить ввод? Язык Ada

#exception #input #ada

#исключение #ввод #ada

Вопрос:

Я только начал изучать Ada и не могу понять, как поддерживать работу программы, когда пользовательский ввод выходит за пределы объявленного диапазона переменной. Я хотел бы распечатать информацию о неверном диапазоне ввода, а затем снова запросить ввод у пользователя.

Это мой простой код:

 with Ada.Text_IO;
use Ada.Text_IO;

procedure Main is
     type Score is range 0..100;
      a : Score;
begin
     Put_Line ("Enter value range 0-100: ");
     a := Score'Value(Get_Line);

     if a'Valid then
          Put_Line ("You entered" amp; Score'Image (a));
     else
          Put_Line ("Bad range of input");
     end if;
end Main;
  

Разве я не должен использовать «диапазон» для проверки ввода, а скорее некоторые if с>, < ограничениями?

Мой другой подход заключался в том, чтобы попробовать это с исключениями, но он также не работает так, как я хочу:

   with Ada.Text_IO;
  with Ada.IO_Exceptions;
  use Ada.Text_IO;

  procedure Main is
     type Score is range 0..100;
     a : Score;
  begin
     loop
        begin
        Put_Line ("Enter value range 0-100: ");
        a := Score'Value(Get_Line);
        Put_Line ("You entered" amp; Score'Image (a));
        exit;
        exception
           when Ada.IO_Exceptions.Data_Error =>
              Put_Line("Bad range of input");
        end;
     end loop;
  end Main;
  

Я считаю, что проблема в моем непонимании этого языка, но я надеюсь, что для этого есть какое-то простое решение, спасибо за любую помощь.

Комментарии:

1. Посмотрите на отчет, когда программа завершается сбоем. Может ли быть так, что присвоение a вызывает Constraint_Error, но вы обрабатываете Data_Error ??

2. Да, это Constraint_Error! Я изменил строку, проверяющую исключение, на Ada.IO_Exceptions.Constraint_Error , но теперь я получаю сообщение об ошибке, что Constraint_Error не объявлен в IO_Exceptions. Как я должен его включить?

3. Это в системе, поэтому уже видно. When Constraint_Error =>

4. Спасибо, я этого не знал, это решило мою проблему. Еще раз спасибо 🙂

5. @obeeey просто хотел добавить дополнительную информацию: значение ‘Valid полезно для проверки «непроверенных» операций, где диапазоны и ограничения не всегда проверяются. Как и при использовании Unchecked_Conversion, я склонен переносить свои вызовы в Unchecked_Conversion, чтобы затем вызвать ‘Valid впоследствии, чтобы убедиться, что я не ввел неверные данные. Ada достаточно хорош, чтобы перехватить его позже, но мне нравится улавливать проблемы в источнике, если это возможно.

Ответ №1:

Теперь вы знаете магическое заклинание, которое работает, но я сомневаюсь, что вы понимаете, почему оно работает или почему ваши другие заклинания не сработали. Я расскажу об этом в болезненных педагогических подробностях в надежде, что некоторые из них могут быть полезными или представлять интерес.

В Ada, когда вы объявляете тип, тип является анонимным, а имя ( Score ), которое вы указываете, является именем первого именованного подтипа. Подтип с первым именем может иметь ограничения, которые не применяются к анонимному базовому типу. Для некоторых типов, включая целочисленные типы, можно ссылаться на анонимный базовый тип с 'Base помощью .

Поскольку вы объявили Score using range , это целочисленный тип со знаком, а его базовый тип (примерно) симметричен относительно нуля. Итак, ваше объявление эквивалентно чему-то вроде

 type Score'Base is range -128 .. 127;
subtype Score is Score'Base range 0 .. 100;
  

(это не Ada и не будет компилироваться).

Score'Value возвращает значение Score'Base (ARM 3.5 (53)), поэтому, если вы введете "101" или "-3" , Score'Value оно будет успешным и вернет соответствующее значение. Когда вы присваиваете это значение своей переменной подтипа Score , выполняется проверка того, что значение находится в диапазоне Score ; когда это не удается, Constraint_Error повышается. Если вы вводите недопустимое изображение, например, "200" или "xyz" , Score'Value сбой и повышение Constraint_Error . Итак, у вас есть два вида неправильного ввода, приводящих к двум разным сбоям, оба из которых вызывают одно и то же исключение.

Ваша первая версия не удалась, потому что вы так и не добрались до if инструкции. Ваша вторая версия не удалась, потому Ada.Text_IO.Get_Line что никогда не поднимается Data_Error .

При работе с числовым вводом я советую считывать полную строку в строку, а затем анализировать значения из этой строки, как вы это сделали. Однако 'Value некоторые входные данные, которые вы, возможно, захотите считать допустимыми, будут отклонены. Например, вы можете принять "23 skidoo" и получить из него значение 23. Для этого вы можете создать экземпляр Ada.Text_IO.Integer_IO для своего числового (подтипа) и использовать Get функцию, которая принимает String параметр:

 package Score_IO is new Ada.Text_IO.Integer_IO (Num => Score);
...
Score_IO.Get (From => "23 skidoo", Item => A, Last => Last);
  

будет установлено A значение 23 и Last индекс '3' in From (2).

HTH