Ada:如何访问 Vector 元素? [英] Ada: How to get Access to Vector element?

查看:31
本文介绍了Ada:如何访问 Vector 元素?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个东西的集合,我故意想在堆上分配并通过引用"访问它们:

I have a collection of things, which I deliberately want to allocate on the heap and access them 'by reference':

with Ada.Text_IO; use Ada.Text_IO;
with Ada.Containers.Indefinite_Hashed_Maps;
with Ada.Containers; use Ada.Containers;

procedure Main is
    
    type Thing_Key is new Integer;
    
    type Thing is record
        Key  : Thing_Key;
        Data : Integer;
    end record;
    
    type Thing_Access is access all Thing;
    
    function Image (T : Thing) return String is
      (T.Key'Image & '(' & T.Data'Image & ')');
    
    function "=" (A, B : Thing) return Boolean is
      (A.Key = B.Key);
    
    function Thing_Hash (K : Thing_Key) return Hash_Type is
      (Hash_Type (K));

    package Thing_Map is new
      Ada.Containers.Indefinite_Hashed_Maps
         (Key_Type        => Thing_Key,
     Element_Type    => Thing,
     Hash            => Thing_Hash,
     Equivalent_Keys => "=");
    use Thing_Map;
    
    Map : Thing_Map.Map;
    C : Cursor;
    P : Thing_Access;
begin
    P := new Thing '(Key => 1, Data => 2);  -- on the heap
    
    Map.Insert (P.Key, P.all);
    Put_Line (Image (P.all)); -- '1( 2)', as expected

    P.Data := 99;
    Put_Line (Image (P.all)); -- '1( 99)', as expected

    C := Map.Find (1); -- Get cursor to thing
    
    -- Set P to point at the thing at the cursor?
    
    -- Following lines don't compile
    P := Map (C)'Access; -- access-to-variable designates constant
    P := Map (C).Reference; -- undefined selector "Reference" for overloaded prefix
    P := Map (C).Get_Element_Access; -- undefined selector "Get_Element_Access" for overloaded prefix
    P := Map.Reference (C); -- no visible interpretation of "Reference" matches expected type "Thing_Access"
end Main;

从游标中获取指针的语法是什么?

What is the syntax to get a pointer from a cursor?

推荐答案

我假设您只想将元素存储在堆上,以便通过引用访问它们以进行操作.但是,在使用 Ada 容器时不需要这样做.所有容器都有某种通过引用访问元素的方法(通过一些 Constant_ReferenceReference 函数,由于 Variable_Indexing 通常可以省略这些函数)在容器类型上定义的方面;例如,参见 第 6.3 节 在 Ada 2012 基本原理中,和/或@Timur Samkharadze 的回答).

I assume that you only want to store elements on the heap in order to access them by reference for manipulation. However, you don't need to do that when using Ada containers. All containers have some way of accessing the elements by reference readily available (via some Constant_Reference or Reference function that can typically be omitted because of the Variable_Indexing aspect defined on the container type; see, for example, section 6.3 in the Ada 2012 rationale, and/or the answer of @Timur Samkharadze).

如果您想将密钥存储为元素的一部分,那么我认为使用散列集可能更合适(参见 RM A.18.7RM A.18.8learn.adacore.com).可以通过函数 Reference_Preserving_Key 引用访问散列集中的元素(另请参见 RM 96.10 (3).

If you want to store the key as part of the element, then I think it might be more appropriate to use a hashed set (see RM A.18.7, RM A.18.8 and on learn.adacore.com). An element in a hashed set can be accessed by reference via the function Reference_Preserving_Key (see also RM 96.10 (3)).

以下是两个示例:第一个示例显示如何更新 Hashed_Map 中的元素,第二个示例显示如何更新 Hashed_Set 中的元素,均使用一个键:

Below are two examples: the first example shows how to update an element in a Hashed_Map and the second example shows how to update an element in a Hashed_Set, both using a key:

ma​​in.adb (Hashed_Map)

with Ada.Text_IO;    use Ada.Text_IO;
with Ada.Containers; use Ada.Containers;
with Ada.Containers.Hashed_Maps;

procedure Main is

   type Thing_Key is new Integer;

   type Thing is record
      Key  : Thing_Key;
      Data : Integer;
   end record;

   function Image (T : Thing) return String is
     ("Key = " & T.Key'Image & ", Value = " & T.Data'Image);

   function Hash (K : Thing_Key) return Hash_Type is (Hash_Type (K));

   package Things is new Ada.Containers.Hashed_Maps
     (Key_Type       => Thing_Key,
      Element_Type   => Thing,
      Hash           => Hash,
     Equivalent_Keys => "=");

   Map : Things.Map;

begin
   
   --  Inserting 4 elements.  Note that the key is now stored twice: once in
   --  the map's key index (its hash, to be more precise), and once in the item
   --  itself (unhashed).  You must now ensure that the key value in the
   --  element does not accidentally get out-of-sync with the hashed key in the
   --  map's key index (e.g. when you update the stored element).  Of course,
   --  you could also you just omit the key in the element itself if possible
   --  given your use-case.
   
   Map.Insert (Key => 1, New_Item => (Key => 1, Data => 10));
   Map.Insert (Key => 2, New_Item => (Key => 2, Data => 20));
   Map.Insert (Key => 3, New_Item => (Key => 3, Data => 30));
   Map.Insert (Key => 4, New_Item => (Key => 4, Data => 40));

   for T of Map loop
      Put_Line (Image (T));
   end loop;
   New_Line;
   
   --  Update element with key 3.
   --
   --  Note that the following expressions are all equivalent:
   --
   --     Map.Reference (3).Element.all.Data := 300;   --  Original expression
   --     Map.Reference (3).Element.Data := 300;       --  Omit "all" due to implicit dereferencing of access types in Ada.
   --     Map.Reference (3).Data := 300;               --  Omit "Element" due to the "Implicit_Dereferencing" aspect on the "Hashed_Maps.Reference_Type".
   --     Map (3).Data := 300;                         --  Omit "Reference" due to the "Variable_Indexing" aspect on the "Hashed_Maps.Map" type.
   --
   Map (3).Data := 300;   

   --  Example if you really need a pointer to element with key 3.
   declare
            
      type Thing_Access is not null access all Thing;
      type Thing_Constant_Access is not null access constant Thing;      
      
      --  Element is     mutable via P , i.e.  P.Data := 301 (OK)
      --  Element is not mutable via CP, i.e. CP.Data := 302 (Error)
      
      P  : Thing_Access          := Map.Reference (3).Element;
      CP : Thing_Constant_Access := Map.Constant_Reference (3).Element;
      
   begin
      null;
   end;

   for T of Map loop
      Put_Line (Image (T));
   end loop;
   New_Line;

end Main;

ma​​in.adb (Hashed_Set)

with Ada.Text_IO;    use Ada.Text_IO;
with Ada.Containers; use Ada.Containers;
with Ada.Containers.Hashed_Sets;

procedure Main is

   type Thing_Key is new Integer;

   type Thing is record
      Key  : Thing_Key;
      Data : Integer;
   end record;

   function Image (T : Thing) return String is
     ("Key = " & T.Key'Image & ", Value = " & T.Data'Image);

   function Key  (T : Thing)     return Thing_Key is (T.Key);
   function Hash (T : Thing)     return Hash_Type is (Hash_Type (T.Key));
   function Hash (K : Thing_Key) return Hash_Type is (Hash_Type (K));

   package Things is new Ada.Containers.Hashed_Sets
     (Element_Type        => Thing,
      Hash                => Hash,
      Equivalent_Elements => "=");

   package Things_Keys is new Things.Generic_Keys
     (Key_Type        => Thing_Key,
      Key             => Key,
      Hash            => Hash,
      Equivalent_Keys => "=");

   Set : Things.Set;

begin
   
   --  Inserting 4 elements.  Note that the key is stored only in the element.
   
   Set.Insert ((Key => 1, Data => 10));
   Set.Insert ((Key => 2, Data => 20));
   Set.Insert ((Key => 3, Data => 30));
   Set.Insert ((Key => 4, Data => 40));

   for T of Set loop
      Put_Line (Image (T));
   end loop;
   New_Line;

   --  Update the element.  See also RM 96.10 (3).  Opposed to most other
   --  containers, you cannot omit "Reference_Preserving_Key" as the "Set" type
   --  does not have a "Variable_Indexing" aspect specifying "Reference_Preserving_Key".
   --  Hence, you need write it out explicitly.   
   
   Things_Keys.Reference_Preserving_Key (Set, 3).Data := 300;

   --  Example if you really need a pointer to element with key 3.
   declare
            
      type Thing_Access is not null access all Thing;
      type Thing_Constant_Access is not null access constant Thing;      
      
      --  Element is     mutable via P , i.e.  P.Data := 301 (OK)
      --  Element is not mutable via CP, i.e. CP.Data := 302 (Error)
      
      P  : Thing_Access          := Things_Keys.Reference_Preserving_Key (Set, 3).Element;  
      CP : Thing_Constant_Access := Things_Keys.Constant_Reference (Set, 3).Element;
      
   begin
      null;
   end;

   for T of Set loop
      Put_Line (Image (T));
   end loop;
   New_Line;

end Main;

输出(两者相同)

Key =  1, Value =  10
Key =  2, Value =  20
Key =  3, Value =  30
Key =  4, Value =  40

Key =  1, Value =  10
Key =  2, Value =  20
Key =  3, Value =  300
Key =  4, Value =  40

这篇关于Ada:如何访问 Vector 元素?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆