如何在Vala中使用String列表的HashMap?

时间:2014-06-06 01:14:13

标签: vala

我正在尝试在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);
        }
    }

请注意,我将字符串值添加到与字符串键关联的列表中。如果列表不存在,我创建它。

假设我使用相同的cs三次运行代码。基于一些printf调试,似乎只创建了一个列表,但每次都是空的。我希望列表的大小为0,然后是1,然后是1。在Vala内存管理/引用计数方面,我做错了吗?

2 个答案:

答案 0 :(得分:3)

GLib.List是问题所在。 GLib.ListGLib.SList上的大多数操作都返回修改后的指针,但哈希表中的值未被修改。有点难以解释为什么这是一个问题,以及为什么GLib以这种方式工作,而不是潜入C。你在这里有一些选择。

  1. 使用libgee中的一个容器,它使用相同的键支持多个值,例如Gee.MultiMap。如果您正在处理Vala编译器中的某些事情(我猜你是,因为你是CodeVisitor的子类),这不是一个选项,因为gee Vala的内部副本发货没有包含MultiMap。
  2. 替换哈希表中的GLib.List实例。不幸的是,这可能意味着每次都要复制整个列表,即使这样,内存管理也会有点棘手,所以如果我是你,我会避免使用它。
  3. 使用GLib.List以外的内容。如果我是你,这就是我的方式。
  4. 编辑:我最近将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.ListGLib.SList,即便如此,通常最好避免使用它们。 TBH我们可能会在很久以前将它们标记为Vala,如果不是因为它们在使用C API时非常常见。

答案 1 :(得分:2)

当用作参数时,Vala的new可能有点奇怪。我建议将新列表分配给临时列表,将其添加到列表中,然后让它超出范围。

我还建议使用libgee。它比GLib.ListGLib.HashTable更好地处理泛型。