【问题标题】:How can I use a HashMap of List of String in Vala?如何在 Vala 中使用字符串列表的 HashMap?
【发布时间】:2014-06-06 01:14:13
【问题描述】:

我正在尝试在 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 内存管理/引用计数方面做错了吗?

【问题讨论】:

    标签: vala


    【解决方案1】:

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

    1. 使用 libgee 中的容器之一,该容器支持具有相同键的多个值,例如 Gee.MultiMap。如果你在 Vala 编译器中工作(我猜你是,因为你是 CodeVisitor 的子类),这不是一个选项,因为 gee Vala 附带的内部副本不包括 MultiMap。
    2. 替换散列表中的GLib.List 实例。不幸的是,这可能意味着每次都复制整个列表,即使这样,正确地进行内存管理也会有点棘手,所以如果我是你,我会避免这样做。
    3. 使用 GLib.List 以外的其他内容。如果我是你,我会这样做。

    编辑:我最近将 GLib.GenericSet 添加到 Vala 作为 GHashTable 的替代绑定,所以现在最好的解决方案是使用 GLib.HashTable&lt;string, GLib.GenericSet&lt;string&gt;&gt;,假设你可以依赖 vala > = 0.26。

    如果我是你,我会使用GLib.HashTable&lt;string, GLib.HashTable&lt;unowned string, string&gt;&gt;

    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 如果不是因为它们在使用 C API 时非常常见,我们可能早就在 Vala 中将它们标记为已弃用。

    【讨论】:

    • 这是一个很棒的答案。感谢您花时间了解我的问题并提供建议的代码示例。当我得到它的工作时,我会报告。
    • 您的建议与描述的完全一样。再次感谢!
    【解决方案2】:

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

    我还建议使用 libgee。它比GLib.ListGLib.HashTable 具有更好的泛型处理能力。

    【讨论】:

    • 感谢您的回答。我感觉自己做错了什么,但不知道如何重新组织代码。即使我让它工作,我也无法解释为什么。我会看一下 libgee,看看我是否可以包含它。
    猜你喜欢
    • 1970-01-01
    • 2022-07-01
    • 2020-06-27
    • 2011-10-12
    • 2012-01-29
    • 2017-05-10
    • 1970-01-01
    • 2016-11-09
    • 1970-01-01
    相关资源
    最近更新 更多