我正在尝试在Vala中使用字符串列表的HashMap,但似乎对象生命周期正在咬我。这是我目前的代码:
public class MyClass : CodeVisitor {
GLib.HashTable<string, GLib.List<string>> generic_classes = new GLib.HashTable<string, GLib.List<string>> (str_hash, str_equal);
public override void visit_data_type(DataType d) {
string c = ...
string s = ...
if (! this.generic_classes.contains(c)) {
this.generic_classes.insert(c, new GLib.List<string>());
}
unowned GLib.List<string> l = this.generic_classes.lookup(c);
bool is_dup = false;
foreach(unowned string ss in l) {
if (s == ss) {
is_dup = true;
}
}
if ( ! is_dup) {
l.append(s);
}
}
请注意,我将字符串值添加到与字符串键关联的列表中。如果列表不存在,我创建它。
假设我使用相同的值c
和s
三次运行代码。基于一些printf调试,似乎只创建了一个列表,但每次都是空的。我希望列表的大小为0
,然后是1
,然后是1
。在Vala内存管理/引用计数方面,我做错了吗?
答案 0 :(得分:3)
GLib.List
是问题所在。 GLib.List
和GLib.SList
上的大多数操作都返回修改后的指针,但哈希表中的值未被修改。有点难以解释为什么这是一个问题,以及为什么GLib以这种方式工作,而不是潜入C。你在这里有一些选择。
Gee.MultiMap
。如果您正在处理Vala编译器中的某些事情(我猜你是,因为你是CodeVisitor的子类),这不是一个选项,因为gee Vala的内部副本发货没有包含MultiMap。GLib.List
实例。不幸的是,这可能意味着每次都要复制整个列表,即使这样,内存管理也会有点棘手,所以如果我是你,我会避免使用它。 编辑:我最近将GLib.GenericSet添加到Vala作为GHashTable的替代绑定,因此现在最好的解决方案是使用GLib.HashTable<string, GLib.GenericSet<string>>
,假设您可以使用取决于vala&gt; = 0.26。
如果我是你,我会使用GLib.HashTable<string, GLib.HashTable<unowned string, string>>
:
private static int main (string[] args) {
GLib.HashTable<string, GLib.HashTable<unowned string, string>> generic_classes =
new GLib.HashTable<string, GLib.HashTable<unowned string, string>> (GLib.str_hash, GLib.str_equal);
for (int i = 0 ; i < 3 ; i++) {
string c = "foo";
string s = i.to_string ();
unowned GLib.HashTable<unowned string, string>? inner_set = generic_classes[c];
stdout.printf ("Inserting <%s, %s>, ", c, s);
if (inner_set == null) {
var v = new GLib.HashTable<unowned string, string> (GLib.str_hash, GLib.str_equal);
inner_set = v;
generic_classes.insert ((owned) c, (owned) v);
}
inner_set.insert (s, (owned) s);
stdout.printf ("container now holds:\n");
generic_classes.foreach ((k, v) => {
stdout.printf ("\t%s:\n", k);
v.foreach ((ik, iv) => {
stdout.printf ("\t\t%s\n", iv);
});
});
}
return 0;
}
使用具有相同值的键和值的哈希表似乎很苛刻,但这实际上也是C中的常见模式,并且特别受GLib的哈希表实现支持。
故事的道德:除非你真的知道自己在做什么,否则不要使用GLib.List
或GLib.SList
,即便如此,通常最好避免使用它们。 TBH我们可能会在很久以前将它们标记为Vala,如果不是因为它们在使用C API时非常常见。
答案 1 :(得分:2)
当用作参数时,Vala的new
可能有点奇怪。我建议将新列表分配给临时列表,将其添加到列表中,然后让它超出范围。
我还建议使用libgee。它比GLib.List
和GLib.HashTable
更好地处理泛型。