Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/backbone.js/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Go 戈朗构造概论_Go - Fatal编程技术网

Go 戈朗构造概论

Go 戈朗构造概论,go,Go,我有另外两个对象实现的结构。在这种情况下,A型和B型回购。这里有一些初始化代码,用椭圆表示。初始化代码在两个构造函数之间完全重复,虽然我只有两个dbRepo,但这并不是什么大问题,但随着我创建更多的构造函数,我会更加担心这种不好的做法。有没有办法用接口来概括这一点 type dbRepo struct { foo string bar string } type typeARepo dbRepo type typeBRepo dbRepo func newTypeARepo(

我有另外两个对象实现的结构。在这种情况下,A型和B型回购。这里有一些初始化代码,用椭圆表示。初始化代码在两个构造函数之间完全重复,虽然我只有两个
dbRepo
,但这并不是什么大问题,但随着我创建更多的构造函数,我会更加担心这种不好的做法。有没有办法用接口来概括这一点

type dbRepo struct {
    foo string
    bar string
}

type typeARepo dbRepo
type typeBRepo dbRepo

func newTypeARepo(foo, bar string) {
    ...
}

func newTypeBRepo(foo, bar string) {
    ...
}

您可以使用初始化代码编写一个函数:

func newDbRepo(foo, bar string) dbRepo {
        // ...
}
然后可以将其与类型转换一起使用:

a := typeARepo(newDbRepo("foo", "bar"))
b := typeBRepo(newDbRepo("foo", "bar"))

我个人在Go中观察到的实践(也是《有效的Go》或《Go入门教程》中推荐的做法)只是定义一个
NewdbRepo
函数,并将其用于所有实例化。它的实现看起来像

func NewdbRepo(f, b string) *dbRepo {
    return &dbRepo{ foo:f, bar:b}
}

实际上,您不能像在大多数C语言中那样定义构造函数,所以您只需要提供一个包范围的方法来为您进行构造。此外,如果您没有使用复合文本(我在NewdbRepo实现中使用的初始化样式),那么您可能会发现仅此一种就足够简洁,满足您的需要

在执行初始化的类型上定义一个未报告的func,然后可以创建几个调用它的构造函数,例如:

func (db *dbRepo) init(){
    if len(db.foo) > 0 {
        //do foo init
    }
    if len(db.bar) > 0 {
        // do bar init
    }
    // do generic init
}

func NewRepo(foo, bar string) *dbRepo {
    repo := &dbRepo{foo: foo, bar: bar}
    repo.init()
    return repo
}

func NewFooRepo(foo string) *dbRepo {
    repo := &dbRepo{foo: foo}
    repo.init()
    return repo
}

您的代码示例看起来不像在go中要做的事情。但是,可以肯定的是,您是否可以开发一些关于您的用例的内容?例如,为什么dbRepo有两个子类型?如何或在何处决定构造类型a或B?有两个子类型,因为它们各自具有不同的函数,将根据它们所属的repo类型对其进行调用。例如,调用用户数据库而不是项目数据库。基于存储库,我将有不同的查询和功能。创建和赋值在其他地方的主函数中完成。所有这些都大致遵循Go中干净的体系结构。我认识到,传统意义上的构造函数是不可能存在的,但在我看来,一个构建并返回结构的函数就像一个漂亮的构造函数一样!我离题了!我可以这样做,然后在
NewTypeARepo()
func中使用类型断言来实现所需的结果。像这样的工厂函数不是构造函数。它是一个工厂函数(就像在其他语言中一样)。构造函数要求您调用它,从而防止您分配未初始化(错误)的零值结构。此外,文本“NewdbRepo”的“dbRepo”部分没有显式链接到类型“dbRepo”。如果您使用一些自动重构工具将“dbRepo”重命名为“databaseRepo”,那么他们将无法知道“NewdbRepo”也需要重构。在重构大型项目时,这可能会产生很大的问题。@eshalev如果您阅读了答案,它会非常清楚地解释所有这些。Go中没有构造函数,如前所述“你不能像在大多数C语言中那样定义构造函数,所以你只需要提供一个包范围内的方法来为你进行构造”,同样如前所述,这种模式是关于该语言的文档中所展示的。不,构造函数并不“要求您调用它”,这是一种语言的规则,与“构造函数”无关,后者是一个定义更为松散的概念,不同语言的行为也不同。以C#为例,对于一个实例,您不需要定义构造函数来使用
new
关键字来实例化类型。其次,您可以使用“静态初始化”来创建实例,而无需调用任何构造函数。事实上,这些模式在OO语言中比定义和调用构造函数的严格要求要常见得多,这在现代开发中是毫无用处的,Go完全省略了这一特性就证明了这一点。这并不是要求库作者定义构造函数。它是关于要求库用户使用构造函数的:假设您正在使用一个很酷的新库。您希望构造一个新的Cow对象。在c#中,您可以立即知道是否以及如何初始化它。事实上,IDE会自动向您推荐它。如果你不这样做,编译器会抓住你的。在Go中,编译器不仅不会捕捉到您,而且除了阅读文档之外,您也无法确定需要调用什么。如果不这样做,则只能在运行时捕获错误。