Есть ли способ вызвать процедуру по ее имени в переменной String в Аде, как это делает Python:
def _ssh(hostname, port):
pass
def _telnet(hostname, port):
pass
def _mosh(hostname, port):
pass
protocols = {
'ssh': _ssh,
'mosh': _mosh,
'telnet': _telnet
}
# call your function by string
hostname = 'localhost'
port = '22'
protocol = 'ssh'
result = protocols[protocol](hostname, port)





Насколько я знаю, это невозможно, поскольку Ада не хранит функции и процедуры в хэш-карте, как это делает Python. Вы все еще можете предоставить функцию, принимающую строку в качестве аргумента и возвращающую доступ к функции, которую вы можете вызвать впоследствии, но я не уверен, что вы пытаетесь это сделать.
Хорошо, я понимаю, но это не было указано в вашем первоначальном вопросе.
Что ж, это немного работы, так как у вас нет удобного сокращения для создания карт (также известных как словари). Это делает работу:
with Ada.Containers.Indefinite_Ordered_Maps;
with Ada.Text_IO; use Ada.Text_IO;
procedure Alubio is
Нам нужен указатель на подпрограмму для создания экземпляра Map
type Handler is access procedure (Hostname : String; Port : Integer);
Карта из строки в указатель на подпрограмму. Он должен быть «неопределенным», потому что тип String является неопределенным (не имеет фиксированного размера), и его нужно «упорядочить», потому что мы не хотим утруждать себя объявлением хеш-функций и т. д.
package Maps is new Ada.Containers.Indefinite_Ordered_Maps
(Key_Type => String,
Element_Type => Handler);
Мне нравится объявлять подпрограммы перед их определением, но здесь это не обязательно.
procedure Ssh (Hostname : String; Port : Integer);
procedure Mosh (Hostname : String; Port : Integer);
procedure Telnet (Hostname : String; Port : Integer);
Карта
Map : Maps.Map;
Демонстрационные подпрограммы
procedure Ssh (Hostname : String; Port : Integer) is
begin
Put_Line ("ssh, " & Hostname & Port'Image);
end Ssh;
procedure Mosh (Hostname : String; Port : Integer) is
begin
Put_Line ("mosh, " & Hostname & Port'Image);
end Mosh;
procedure Telnet (Hostname : String; Port : Integer) is
begin
Put_Line ("telnet, " & Hostname & Port'Image);
end Telnet;
begin
Настроить карту
Map.Insert ("ssh", Ssh'Access);
Map.Insert ("mosh", Mosh'Access);
Map.Insert ("telnet", Telnet'Access);
Вызывать подпрограммы через карту. Не совсем уверен, зачем нужен .all (разыменование указателя на подпрограмму), часто не понимаешь: здесь без него компилятор говорит «недопустимая процедура или вызов входа», указывая на Map.
Map ("ssh").all ("s", 1);
Map ("mosh").all ("m", 2);
Map ("telnet").all ("t", 3);
end Alubio;
Выход:
$ ./alubio
ssh, s 1
mosh, m 2
telnet, t 3
Это был мой первый подход. Я вызываю процедуру в защищенном объекте, используя тип защищенной процедуры доступа, хранящийся на карте. Но я делаю этот вызов внутри другой процедуры в том же защищенном объекте и получаю программную ошибку во время выполнения. Я подозреваю, что здесь есть ограничение блокировки, но я не могу этого понять. Я знаю, что это другой вопрос. Я пытаюсь найти другой подход, такой как сохранение строки вместо типа доступа.
Возможно, если бы вы показали нам свой код (как вы действительно должны это сделать на SO), мы могли бы помочь лучше. Или рассказал нам о своей реальной проблеме... звучит так, как будто вы уже знали, что я показал, поэтому я зря тратил время, что не побуждает меня смотреть глубже. Тем не менее, может ли быть так, что компилятор не может сказать, что фактическая вызываемая процедура фактически находится в том же PO?
Возможно, вы нарушаете 9.5.1 15 RM, что вызывает Program_Error: внешний вызов защищенной подпрограммы (или внешней очереди) с тем же целевым объектом, что и у защищенного действия?
Я открою еще один вопрос о вызове защищенных процедур с использованием типов доступа, так как это другой вопрос/тема. В этом вопросе я хочу знать только разные способы вызова процедуры, используя ее имя в String. Вы внесли свой вклад с одним совершенно правильным решением. Может быть, есть еще.
Простой способ — использовать перечисляемый тип и оператор case.
type Protocol is (ssh, mosh, telnet);
затем с переменной given_protocol : Protocol :
case given_protocol is
when ssh => Ssh (Hostname, Port);
when mosh => Mosh (Hostname, Port);
when telnet => Telnet (Hostname, Port);
end case;
Это позволяет избежать типов доступа и карт.
Вы получаете given_protocol из строки, используя атрибут 'Value: given_protocol := Protocol'Value (given_string).
Еще одно хорошее решение. Знаете ли вы какую-нибудь библиотеку для создания простых интерфейсов командной строки, таких как маршрутизаторы Cisco?
Это верное решение, как и решение Саймона. Но это не совместимо с моей реальной проблемой вызова защищенной процедуры из типа доступа внутри другой защищенной процедуры в том же объекте.