Как обновить элемент в этом векторе?

Я пытаюсь обновить элемент в векторе. У меня довольно много проблем, которые я не знаю, как решить. Когда я использую 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

Когда я использую код в комментариях и удаляю второй параметр функции, он все равно не работает.

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
71
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Быстрый поиск в Интернете приведет вас к... 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));

Да, я нашел это, но я очень новичок и понятия не имею, как использовать эту информацию. Вот как я нашел процедуру в первую очередь, но я не знаю, как работает параметр Process.

Josh 26.12.2022 20:45
Ответ принят как подходящий

У вас тут много всего намешано. Во-первых, если вы посмотрите на ответ 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 26.12.2022 22:27

@Josh Эта ошибка в переменной связана с тем, что вы использовали параметр режима «in» вместо «in out». Параметры, которые находятся только в режиме «в», по существу являются постоянными и «неизменяемыми». Параметры, которые "in out" могут быть изменены, считаются "переменными". Он жаловался, потому что вы пытались изменить постоянный параметр.

Jere 27.12.2022 02:12

Я рекомендую просто использовать операции индексирования (например, внизу моего ответа), если вам не нужно использовать Update_Element. Вызовы части Update_Element могут быть несколько неуклюжими как для правильного использования, так и для чтения. Replace_Element тоже подойдет, если это делает то, что вы хотите. Вы также можете получить к ним доступ через вызовы функций NodeVector.Element. Вы также можете выполнить цикл for of, если элементы уже находятся в векторе, прежде чем вам нужно будет их обновить.

Jere 27.12.2022 02:14

Другие вопросы по теме