在TDictionary中记录

3

我该如何在 TDictionary 中使用 record

TMyRec = record
    a: Integer;
    b: Integer;
end;

...

dictionary = TDictionary<String, TMyRec>.create();

...

dictionary[key].a := 30;<<<

编译器报错:"左侧无法赋值"。如何在不创建单独的函数写myFunc(a, b: Integer): TMyRec的情况下解决这个问题?


你尝试过将整个字典赋值给 dictionary[key] := someRec; 吗? - Kromster
与 https://dev59.com/ynRB5IYBdhLWcg3wcm6d 相关的编程内容。 - Kromster
3个回答

4

dictionary[key]返回字典中记录的一个副本。编译器防止修改该副本,因为那没有任何意义。

顺便说一下,旧版本的程序会接受你的代码,但会很困惑,因为对记录的修改会丢失。你会进行赋值操作,但是由于你所赋的是一个无名的本地变量,所以没有任何改变。

显然,你打算修改收藏中保存的记录。为了实现这一点,你需要将整个记录分配给一个本地变量。从收藏中读取记录到本地变量中。修改本地变量。将更新后的值写回收藏中。像这样:

var
  rec: TMyRec;
...
rec := dictionary[key];
rec.a := 30;
dictionary[key] := rec;

其中一个令人沮丧的方面是,尽管我们知道第二个查找将找到与第一个相同的记录,但代码需要执行两次字典查找。即使是强大的Spring4d字典也无法使用单个查找完成此操作。


如果字典可以返回存储记录的指针,那么就不需要进行双重查找,这是有可能的。但据我所知,我所了解的字典都不支持这一点,并且使用泛型编码可能也不是那么容易。 - Rudy Velthuis
顺便提一下,一个字典可以缓存上次搜索的键,如果下一次搜索使用相同的键,则不需要进行新的查找。在这种情况下,毕竟是使用相同的键两次。 - Rudy Velthuis
@RudyVelthuis,我认为这不是我的做法。我会有一个类似于更新方法的东西,procedure UpdateValue(const Key: TKey; const UpdateProc: TUpdateProc<TValue>); 其中 TUpdateProc 通过 var 传递一个 TValue。我一直在与 Stefan 在 spring4d 字典的上下文中讨论这个问题。 - David Heffernan
你可以都拥有。针对特殊场景的特定更新方法和作为“隐藏”功能的缓存。后者的缺点是字典将始终需要检查键是否相同,以便使用缓存。根据使用情况,您将通过该检查失去更多周期,而不是通过命中缓存获得更多收益。也许有第三种选择,即返回指向项目的引用的方法? - GolezTrol
@GolezTrol:那个“第三个选项”是我的第一个选择。其他的东西,比如UpdateValue之类的,或者缓存,确实可能比指向存储项的简单指针慢(不一定要是记录)。我想所有三种方法的结合体都很好,这样你就可以选择最适合情况的方法了。 - Rudy Velthuis

3
David Heffernan的回答是你需要的,但我想再提供一个额外的警告。记录可以像类一样具有属性、getter和setter,如果你的记录具有这样的属性,你的代码将编译通过,但它仍然不会改变实际的记录值。
TMyRec = record
private
  FA : integer;
  procedure SetA(const Value: integer);
  function GetA : integer;
public
  { Warning: When used on result from dictionary lookup, only the COPY will be 
    altered, not the actual record in the dictionary! }
  property A : integer read GetA write SetA; 
end;

2
这并不回答所提出的问题。它应该是一个评论吗? - David Heffernan

1
一个非常简单的解决方法是使用记录的List属性。
你可以这样说:
dictionary.list[key].a := 30;
这将通过List属性访问支持TList的动态数组。编译器已经支持直接访问动态数组。
如果您可以登录quality.embarcadero.com,您可以看到完整的讨论,该问题被提出为:RSP-23136: We should be able to assign a value to one element in a list of records - 发布于2018年12月18日,解决于2019年11月21日。
该问题在评论中关闭:
“这个按预期工作。提供了替代编码风格。”

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接