【问题标题】:How to organize Go code in packages如何在包中组织 Go 代码
【发布时间】:2016-02-15 20:27:38
【问题描述】:

我正在尝试使用 Go 实现联合查找算法。我想使用一个结构UnionFind 来实施不同的策略,例如快速查找快速联合加权快速联合,见下文。我把代码放到一个包里unionfind

package unionfind

type Unionfind struct {
    elements []int
}

func makeUnionfind(n int) Unionfind {
    elements := make([]int, n)
    for idx := range elements {
        elements[idx] = idx
    }
    return Unionfind{elements}
}

接下来我为不同的策略创建函数,从quick find 开始。下面的示例不起作用。但是我不知道策略特定代码放在哪里,如何命名包以及如何导入通用结构类型。

// create a separate package for each strategy?
package quickfind

// import the structure locally?
import ufp "./unionfind"

// prefer methods over functions for convenience?
func (uf *ufp.Unionfind) union(a int, b int) {
    aroot := uf.elements[a]
    broot := uf.elements[b]
    for k, v := range uf.elements {
        if v == aroot {
            uf.elements[k] = broot
        }
    }
}

func (uf *ufp.Unionfind) connected(a int, b int) bool {
    return uf.elements[a] == uf.elements[b]
}

我应该如何组织我的代码以使 快速查找 算法正常工作,但将 UnionFindstructure 分开?

【问题讨论】:

  • 你确定这些是源文件的保存版本吗?该错误表明quickfind.go 文件显示package quickfind(实际上,您似乎将同一个文件粘贴了两次。什么是quickfind.go?)
  • 你不能在同一个文件夹中有两个包。请阅读golang.org/doc/code.html
  • @sschmeck:您的问题的完整答案是阅读How to Write Go Code 上的文档,链接在这里和两个重复的答案。您的错误的直接答案与其他错误相同,您不能在单个目录中有多个包声明。您遇到的另一个问题是您无法在另一个包的类型上定义方法。方法集是类型的一部分,类型是在“包”中定义的。 (你也有一个永远不应该使用的相对导入)
  • @sschmeck 我建议从一个更简单的程序开始并阅读一些教程。封闭问题的评论部分不是这种建议的最佳位置。这是围棋书列表github.com/dariubs/GoBooks
  • @sschmeck:我不明白这个问题(因为您已经知道可以导出类型)。分享,你的意思是修改吗? Go 是一种静态类型语言,不能直接扩展导入的类型。您可以在包中本地实现接口,例如,参见sort package,或者加密哈希函数如何全部返回hash.Hash 接口。 (您可能想访问更适合对话的论坛,例如邮件列表。)

标签: go code-structure


【解决方案1】:

首先要做的是清楚地解释您的问题。例如,

我想在 Go 中实现几种替代的联合查找算法。例如,quick-fund、quick-union、加权QU、路径压缩、加权+路径。请参阅Union-Find Algorithms, Princeton UniversityChapter one of Algorithms in Java by Sedgwick


类似的可能是 Go crypto 包,它实现了许多替代加密哈希函数。

【讨论】:

  • 你怎么知道我在读 Sedgewick ;-) 谢谢你的链接。顺便说一句:我认为算法不如我希望结构以不同方式使用这一事实重要。
【解决方案2】:

您将无法对所有联合查找实现使用相同的结构。例如,加权快速联合除了元素之外还需要树大小的数组。

您在这里想要实现的是以不同的方式实现相同的操作。这就是 Go 中的接口。

另外使用包导入的别名来节省一些击键不是一个好习惯。相反,最好想出好名称,例如包名称及其交互/结构/函数名称。

我会将所有算法组织在一个包中,结构如下:

package algorithms

type UnionFind interface {
    Union(a int, b int)
    Connected(a int, b int) bool
}

func QuickFind(n int) UnionFind {
    return &quickFind{......}
}

func QuickUnion(n int) UnionFind {
    return &quickUnion{......}
}

type quickUnion struct {
    ....
}

func (qu *quickUnion) Union(a int, b int) {
    ...
}

func (qu *quickUnion) Connected(a int, b int) bool {
    ...
}

type quickFind struct {
    ....
}

func (qf *quickFind) Union(a int, b int) {
    ...
}

func (qf *quickFind) Connected(a int, b int) bool {
    ...
}

【讨论】:

  • 我实现了你的方法。如有必要,您可以将Unionfind struct 用作嵌入类型。单个包的主要好处是您可以在不导出函数的情况下共享函数。
【解决方案3】:

我修改了我的代码以获得可行的解决方案。

  • 为通用类型Unionfind提供库/包unionfind
  • 快速查找算法放入自己的包'quickfind'和自己的文件夹中
  • 导入unionfind默认方式使用GOPATH
  • 用函数替换方法

第一个文件是algorithms/unionfind/unionfindtype.go

package unionfind

type Unionfind struct {
    Elements []int
}

func MakeUnionfind(n int) Unionfind {
    elements := make([]int, n)
    for idx := range elements {
        elements[idx] = idx
    }
    return Unionfind{elements}
}

第二个文件是algorithms/unionfind/quickfind/quickfind.go

package quickfind

import ufp "algorithms/unionfind"

func union(uf *ufp.Unionfind, a int, b int) {
    aroot := uf.Elements[a]
    broot := uf.Elements[b]
    for k, v := range uf.Elements {
        if v == aroot {
            uf.Elements[k] = broot
        }
    }
}

func connected(uf *ufp.Unionfind, a int, b int) bool {
    return uf.Elements[a] == uf.Elements[b]
}

感谢 JimB 和 fl0cke 的建议。

【讨论】:

    猜你喜欢
    • 2019-08-21
    • 2022-12-22
    • 2011-08-08
    • 1970-01-01
    • 2014-09-25
    • 1970-01-01
    • 1970-01-01
    • 2012-12-13
    • 1970-01-01
    相关资源
    最近更新 更多