Я пытаюсь обновить элемент в векторе. У меня довольно много проблем, которые я не знаю, как решить. Когда я использую Replace_Element, все работает, но я хочу использовать правильную процедуру.
Это мой код:
with Ada.Containers.Vectors;
procedure Test_Update is
type Node is record
Parent : Integer := -1;
Size : Integer := -1;
end record;
function TestUpdate(n : Node; val : Integer) return Node is
begin
n.Size := n.Size + val;
return n;
end TestUpdate;
package NodeVector is new
Ada.Containers.Vectors
(
Index_Type => Natural,
Element_Type => Node
);
Nodes : NodeVector.vector;
Current_Node : Node;
begin
Current_Node.Size := 10;
Nodes.Append(Current_Node);
NodeVector.Update_Element(Nodes, 0, TestUpdate'Access(5));
--NodeVector.Update_Element(Nodes, 0, TestUpdate'Access);
end Test_Update;
Вот ошибки, которые я получаю, и я знаю, что их вызывает, но не знаю, как их исправить:
test_update.adb:11:09: error: assignment to "in" mode parameter not allowed
test_update.adb:28:59: error: unexpected argument for "Access" attribute
Когда я использую код в комментариях и удаляю второй параметр функции, он все равно не работает.
Быстрый поиск в Интернете приведет вас к... A.18.2 Пакет-контейнеры. Векторы (или, если вы используете GNAT Studio: щелкните правой кнопкой мыши «Векторы» в «Ada.Containers.Vectors», затем выберите «Перейти к объявлению»). Тогда вы найдете это:
procedure Update_Element
(Container : in out Vector;
Index : in Index_Type;
Process : not null access procedure
(Element : in out Element_Type));
У вас тут много всего намешано. Во-первых, если вы посмотрите на ответ Zerte более внимательно, чем раньше, вы заметите, что ваша операция TestUpdate вообще не соответствует этому аргументу Process. Он ожидает процедуру (у вас есть функция), и параметр процедуры "in out", а вы используете "in" и у вас есть дополнительный параметр. Вы должны исправить это в первую очередь
Если вы хотите использовать Update_Element (я не рекомендую его для вашего конкретного случая), вам нужно изучить «Вложенные подпрограммы». Вот пример того, как изменить операцию TestUpdate для работы с Update_Element:
procedure TestUpdate(V : in out NodeVector.Vector; val : Integer) is
procedure Actual_Update(N : in out Node) is
begin
n.Size := n.Size + val;
end Actual_Update;
begin
V.Update_Element(V.Last,Actual_Update'Access);
end TestUpdate;
Обратите внимание, как процедура Actual_Update на самом деле соответствует аргументу процесса контракта операции Update_Element. Кроме того, поскольку Actual_Update является вложенным, он имеет доступ к аргументу Val из TestUpdate.
Полный пример:
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Containers.Vectors;
procedure Test_Update is
type Node is record
Parent : Integer := -1;
Size : Integer := -1;
end record;
package NodeVector is new
Ada.Containers.Vectors
(
Index_Type => Natural,
Element_Type => Node
);
Nodes : NodeVector.vector;
Current_Node : Node;
procedure TestUpdate(V : in out NodeVector.Vector; val : Integer) is
procedure Actual_Update(N : in out Node) is
begin
n.Size := n.Size + val;
end Actual_Update;
begin
V.Update_Element(V.Last,Actual_Update'Access);
end TestUpdate;
begin
Current_Node.Size := 10;
Nodes.Append(Current_Node);
TestUpdate(Nodes, 5);
end Test_Update;
С векторами вы также можете просто индексировать вещи напрямую. После добавления элемента вы можете использовать <vector_name>.Last, чтобы получить курсор (индекс) для последнего элемента... того, который вы только что добавили. Пример:
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Containers.Vectors;
procedure Test_Update is
type Node is record
Parent : Integer := -1;
Size : Integer := -1;
end record;
package NodeVector is new
Ada.Containers.Vectors
(
Index_Type => Natural,
Element_Type => Node
);
Nodes : NodeVector.vector;
Current_Node : Node;
procedure Using_Cursors
(V : in out NodeVector.Vector;
N : Node;
Value : Integer)
is begin
Nodes.Append(N);
Nodes(Nodes.Last).Size := Nodes(Nodes.Last).Size + Value;
end Using_Cursors;
begin
Current_Node.Size := 10;
Using_Cursors(Nodes,Current_Node,5);
end Test_Update;
Спасибо за такой полный ответ. Я думал, что функция — это разновидность процедуры, и вообще понятия не имел, как сделать что-то подобное. Я хочу добавить, что когда я пытался получить доступ к элементу напрямую, используя код, аналогичный последнему примеру, он сказал, что «левая часть присваивания должна быть переменной». Кроме того, вы сказали, что не рекомендуете использовать Update_Element; Вы рекомендуете вместо этого использовать Replace_Element?
@Josh Эта ошибка в переменной связана с тем, что вы использовали параметр режима «in» вместо «in out». Параметры, которые находятся только в режиме «в», по существу являются постоянными и «неизменяемыми». Параметры, которые "in out" могут быть изменены, считаются "переменными". Он жаловался, потому что вы пытались изменить постоянный параметр.
Я рекомендую просто использовать операции индексирования (например, внизу моего ответа), если вам не нужно использовать Update_Element. Вызовы части Update_Element могут быть несколько неуклюжими как для правильного использования, так и для чтения. Replace_Element тоже подойдет, если это делает то, что вы хотите. Вы также можете получить к ним доступ через вызовы функций NodeVector.Element. Вы также можете выполнить цикл for of, если элементы уже находятся в векторе, прежде чем вам нужно будет их обновить.
Да, я нашел это, но я очень новичок и понятия не имею, как использовать эту информацию. Вот как я нашел процедуру в первую очередь, но я не знаю, как работает параметр Process.