包允许多个init的设计决定是什么?

845 views
Skip to first unread message

平民四月份

unread,
Oct 10, 2012, 1:41:41 AM10/10/12
to golang...@googlegroups.com
刚才在群里讨论,全局变量的初始化顺序是确定的,而当引入了init过后,这个问题就有点细致了,假设有一个包叫example,它包含三个文件: a.go, b.go, c.go.

//a.go
var g_Int int
...


// b.go
func init() {

  g_Int++ 
  println(g_Int)
}
...


// c.go
func init() {
  
  g_Int++
  println(g_Int)
}

按照spec的说法,在同一个包内的多个init的调用顺序是不确定的,那么在b.go中打印出的值可能为1也可能为2,同理c.go中的init,耍如果一个包中只允许一个init存在,则不会出现这种中途不一致的情况,请问允许多个init的设计决定是什么?
--
 Face the sea, for the spring flowers blossoming




minux

unread,
Oct 10, 2012, 1:54:30 AM10/10/12
to golang...@googlegroups.com


On Oct 10, 2012 1:42 PM, "平民四月份" <lew...@gmail.com> wrote:
>
> 刚才在群里讨论,全局变量的初始化顺序是确定的,而当引入了init过后,这个问题就有点细致了,假设有一个包叫example,它包含三个文件: a.go, b.go, c.go.
>
> //a.go
> var g_Int int
> ...
>
>
> // b.go
> func init() {
>
>   g_Int++ 
>   println(g_Int)
> }
> ...
>
>
> // c.go
> func init() {
>   
>   g_Int++
>   println(g_Int)
> }
>
> 按照spec的说法,在同一个包内的多个init的调用顺序是不确定的,那么在b.go中打印出的值可能为1也可能为2,同理c.go中的init,耍如果一个包中只允许一个init存在,则不会出现这种中途不一致的情况,请问允许多个init的设计决定是什么?

因为包可以包含多个文件,如果不允许多个init()那么每个文件
就不再那么独立了(无法在声明全局变量的附近初始化变量)

Oling Cat

unread,
Oct 10, 2012, 1:56:11 AM10/10/12
to golang...@googlegroups.com
但这样不也引入了一点不确定性么?

2012/10/10 minux <minu...@gmail.com>

--
官网: http://golang-china.org/
IRC: irc.freenode.net #golang-china
@golangchina

minux

unread,
Oct 10, 2012, 3:07:59 AM10/10/12
to golang...@googlegroups.com


On Oct 10, 2012 1:56 PM, "Oling Cat" <olin...@gmail.com> wrote:
> 但这样不也引入了一点不确定性么?
如果需要相互依赖的初始化,不要用init().

// fileA.go
var globalA = makeA()

// fileB.go
var globalB = makeBFromA(globalA)

init()不应该像lz那样用。

规定init()的调用顺序意义不大,而且多个文件里的人init()
的顺序是不好定义的(试试写一个就知道了),引入这么多复
杂性意义不大。

Xing Xing

unread,
Oct 10, 2012, 3:49:18 AM10/10/12
to golang...@googlegroups.com
于 Wed, 10 Oct 2012 13:56:11 +0800
Oling Cat <olin...@gmail.com> 写道:

> 但这样不也引入了一点不确定性么?

这个不确定性是可以通过合理的代码布局避免的。
或者隐含这样一个规则:每个文件中的 init
仅仅负责这个文件内声明的全局变量的初始化。

换句话说,做到每个 init 的顺序无关。如果顺序有关的话,就放到一个 init
里处理。

>
> 2012/10/10 minux <minu...@gmail.com>
>
> >
> > On Oct 10, 2012 1:42 PM, "平民四月份" <lew...@gmail.com> wrote:
> > >
> > > 刚才在群里讨论,全局变量的初始化顺序是确定的,而当引入了init过后,这个问题就有点细致了,假设有一个包叫example,它包含三个文件:
> > >

Oling Cat

unread,
Oct 10, 2012, 3:52:50 AM10/10/12
to golang...@googlegroups.com
谢谢minux大和mike大解惑,我也觉得应该不会有人在实际中这么写= =||

2012/10/10 Xing Xing <mike...@gmail.com>

chai2010

unread,
Oct 10, 2012, 4:05:30 AM10/10/12
to golang...@googlegroups.com
设计再好的语言也可以写出垃圾代码来.
像这类不确定又没有太多实际意义的语法尽量回避就好了.

跑下题, <Programming In Go> 中有个关于init执行顺序的图很不错(P224):

内嵌图片 1
prog_startup_seq.jpg

Liigo Zhuang

unread,
Oct 10, 2012, 4:11:04 AM10/10/12
to golang...@googlegroups.com

同一个pkg允许多个init函数并存,本身就是不靠谱的设计,完全是没有必要的,也与golang一贯的设计准则不符。不知道是哪个家伙一拍脑门就定了。

prog_startup_seq.jpg

shiwei xu

unread,
Oct 10, 2012, 4:13:26 AM10/10/12
to golang...@googlegroups.com
我反对这个看法。我觉得是非常贴心的设计。避免了C++那种用全局对象构造函数来做初始化的变态做法。
许式伟
prog_startup_seq.jpg

chai2010

unread,
Oct 10, 2012, 4:18:50 AM10/10/12
to golang...@googlegroups.com
在 2012年10月10日 下午4:11,Liigo Zhuang <com....@gmail.com>写道:

同一个pkg允许多个init函数并存,本身就是不靠谱的设计,完全是没有必要的,也与golang一贯的设计准则不符。不知道是哪个家伙一拍脑门就定了。

本意是每个文件可以有一个init函数. 
如果规定每个pkg只能一个init, 那这个init该放在哪个文件中呢?
prog_startup_seq.jpg

minux

unread,
Oct 10, 2012, 4:31:28 AM10/10/12
to golang...@googlegroups.com


On Oct 10, 2012 4:11 PM, "Liigo Zhuang" <com....@gmail.com> wrote:
> 同一个pkg允许多个init函数并存,本身就是不靠谱的设计,完全是没有必要的,也与golang一贯的设计准则不符。不知道是哪个家伙一拍脑门就定了。

拜托您下次过来黑Golang请好好准备好您的理由。

您这句话把"同一个pkg允许多个init函数并存"换成某个
语言L的某个特性F,然后把golang替换成L,然后这句话
可以说任何语言L的任何特性F是有问题的。

要想继续讨论,请说明为什么不靠谱,没啥没必要,
golang的设计风格是什么,哪个不符合? 给点细节,
别用这么空洞抽象的说辞。

yan

unread,
Oct 10, 2012, 6:52:33 AM10/10/12
to golang...@googlegroups.com
恩,我想
下面这个链接也许有点用, 多个(好多个。。。) init在一个包的例子
http://code.google.com/p/go-charset/source/browse/#hg%2Fdata // 源码位


然后上面那个包的使用文档
http://go.pkgdoc.org/code.google.com/p/go-charset/charset


用于注册某些处理器

恩,当包A
import "pkgB"
import _ "pkgC"


包B是个比较抽象的东西,它约定一些接口,并实现一些逻辑,
然后有个Register函数,用来注册一些处理器(这些处理器符合约定的接口)

包C则是处理器的包,使用了包B的Register函数去注册他的处理器
而,包C里面的处理器不止一个,对此,包C将每个处理器单独一个文件
并在每个文件里面使用init函数去调用包B的Register函数来注册自身这个处理器
这样子,可以很方便的管理每个处理器(不要的时候可以直接删除)


然后,在包A中,你可以方便的替换处理器,或者添加新的处理器,
而,你代码里面的调用,只是调用包B的接口
import "pkgB"
import _ "pkgC" // (导入的时候记得加个 _ )
// 突然你发现包C的效率比较低,并且找到一个新的包D,它的效率比较高
// 那么,你只要注释掉 包C的导入,
// 然后导入包D,这样你不用修改你代码里面的任何其他名称
// 你代码里面的逻辑是通过pkgB.Xxx进行的



On Wed, 2012-10-10 at 16:13 +0800, shiwei xu wrote:
> 我反对这个看法。我觉得是非常贴心的设计。避免了C++那种用全局对象构造函
> 数来做初始化的变态做法。
>
> 在 2012年10月10日 下午4:11,Liigo Zhuang <com....@gmail.com>写道:
> 同一个pkg允许多个init函数并存,本身就是不靠谱的设计,完全是没
> 有必要的,也与golang一贯的设计准则不符。不知道是哪个家伙一拍脑
> 门就定了。
>
> 在 2012-10-10 下午4:05,"chai2010" <chais...@gmail.com>写
> 道:
>
> 设计再好的语言也可以写出垃圾代码来.
> 像这类不确定又没有太多实际意义的语法尽量回避就好了.
>
>
> 跑下题, <Programming In Go> 中有个关于init执行顺序的图
> 很不错(P224):
>
>

yan

unread,
Oct 10, 2012, 6:57:54 AM10/10/12
to golang...@googlegroups.com
On Wed, 2012-10-10 at 18:52 +0800, yan wrote:
> 恩,我想
> 下面这个链接也许有点用, 多个(好多个。。。) init在一个包的例子
> http://code.google.com/p/go-charset/source/browse/#hg%2Fdata // 源码位
> 置
>
> 然后上面那个包的使用文档
> http://go.pkgdoc.org/code.google.com/p/go-charset/charset
>
>
> 用于注册某些处理器
>
> 恩,当包A
> import "pkgB"
> import _ "pkgC"
>
>
> 包B是个比较抽象的东西,它约定一些接口,并实现一些逻辑,
> 然后有个Register函数,用来注册一些处理器(这些处理器符合约定的接口)
>
> 包C则是处理器的包,使用了包B的Register函数去注册他的处理器
> 而,包C里面的处理器不止一个,对此,包C将每个处理器单独一个文件
> 并在每个文件里面使用init函数去调用包B的Register函数来注册自身这个处理器
> 这样子,可以很方便的管理每个处理器(不要的时候可以直接删除)
>
>
下面这段跑题了。。。
*******************************************************
> 然后,在包A中,你可以方便的替换处理器,或者添加新的处理器,
> 而,你代码里面的调用,只是调用包B的接口
> import "pkgB"
> import _ "pkgC" // (导入的时候记得加个 _ )
> // 突然你发现包C的效率比较低,并且找到一个新的包D,它的效率比较高
> // 那么,你只要注释掉 包C的导入,
> // 然后导入包D,这样你不用修改你代码里面的任何其他名称
> // 你代码里面的逻辑是通过pkgB.Xxx进行的
>
***********************************************************

dworld

unread,
Oct 10, 2012, 11:54:33 PM10/10/12
to golang...@googlegroups.com
实际工作中的确有这个需求, 每个文件都有需要初始化的部分

Liigo Zhuang

unread,
Jan 20, 2013, 11:58:30 PM1/20/13
to golang...@googlegroups.com

五毛分子,迫不及待的跳出来护主。而且你也没说出什么“靠谱”的理由,一味的人身攻击。什么叫“黑golang”?莫名其妙。批评它“不靠谱”还不准许?用“护主”形容你真是恰到好处。

下面我来说说它“不靠谱”的理由:golang连函数重载都不支持,多个同名的init函数并存本身就是怪胎; golang连一个未被使用的变量声明都不能容忍,却生生允许多个重复的init; 只要一个init就足够达到目的,多了明显就是画蛇添足,还无谓的引入了无解的“初始化顺序”问题,把原本简单的事情复杂化。各种突兀、不合逻辑。理由早就准备好了:“完全是没有必要的”,上面只是展开叙述。

golang嘛,只不过是一门冰冷的编程工具,犯得着满腔热血的护它、黑它么?什么都说不过一个理字。一味护主比真心黑更可怕。最后实在说不过了,无非丢来一句“不喜欢别用”!────依然是护主的心态。可他知道主子是一定拒绝长进的么。

--

Ruiqi Hong

unread,
Jan 21, 2013, 12:21:36 AM1/21/13
to golang...@googlegroups.com
三个月前的邮件都被翻出来了,汗~~
如果一个pkg是有N个文件构成的,每个文件都有自己的初始化任务,如果不允许多个init,那怎么改
比如A文件需要初始化一个变量a,B需要初始化一个变量b
不允许多个init的情况下,把变量a的初始化写到B文件里么
那么哪天在A文件里把a删除了,还要去改B文件?


--

Ruiqi Hong

unread,
Jan 21, 2013, 12:23:30 AM1/21/13
to golang...@googlegroups.com
那干脆一个包的import也写到一个文件里好了,多省事

steve wang

unread,
Jan 21, 2013, 12:26:01 AM1/21/13
to golang...@googlegroups.com
你不要再这里胡闹了,胡乱进行人身攻击。
你说的所谓“理由”和你说golang“不靠谱”的结论根本没有任何联系。你这样的攻击“逻辑”对于任何语言都适用。
对于一些语言的特性,真的是不喜欢就别用,比如我不喜欢python的缩进我就不用;或者你也可以自己fork去改造,比如dragonflybsd。但是请尊重原语言的设计者和开发者。minux也是我见过的少有的非常平和以理服人的技术大牛,我对他的技术和人品和热情,都是非常的佩服。

Chen Yufei

unread,
Jan 21, 2013, 12:27:41 AM1/21/13
to golang...@googlegroups.com
On 2013年1月21日Monday at 下午1:21, Ruiqi Hong wrote:
> 三个月前的邮件都被翻出来了,汗~~

我直接建了个删除他邮件的 filter。

Chen Yufei

unread,
Jan 21, 2013, 12:41:37 AM1/21/13
to golang...@googlegroups.com
On 2013年1月21日Monday at 下午1:26, steve wang wrote:
> 你不要再这里胡闹了,胡乱进行人身攻击。
> 你说的所谓“理由”和你说golang“不靠谱”的结论根本没有任何联系。你这样的攻击“逻辑”对于任何语言都适用。
> 对于一些语言的特性,真的是不喜欢就别用,比如我不喜欢python的缩进我就不用;或者你也可以自己fork去改造,比如dragonflybsd。但是请尊重原语言的设计者和开发者。minux也是我见过的少有的非常平和以理服人的技术大牛,我对他的技术和人品和热情,都是非常的佩服。

同样支持和佩服 minux。

我把 minux 的邮箱放在邮件列表的 filter 里,他的邮件都是直接放入 inbox。
看他在 golang-nuts 和 golang-china 上的回复学到了不少东西。
>
> On Monday, January 21, 2013 12:58:30 PM UTC+8, Liigo Zhuang wrote:
> > 五毛分子,迫不及待的跳出来护主。而且你也没说出什么“靠谱”的理由,一味的人身攻击。什么叫“黑golang”?莫名其妙。批评它“不靠谱”还不准许?用“护主”形容你真是恰到好处。
> > 下面我来说说它“不靠谱”的理由:golang连函数重载都不支持,多个同名的init函数并存本身就是怪胎; golang连一个未被使用的变量声明都不能容忍,却生生允许多个重复的init; 只要一个init就足够达到目的,多了明显就是画蛇添足,还无谓的引入了无解的“初始化顺序”问题,把原本简单的事情复杂化。各种突兀、不合逻辑。理由早就准备好了:“完全是没有必要的”,上面只是展开叙述。
> > golang嘛,只不过是一门冰冷的编程工具,犯得着满腔热血的护它、黑它么?什么都说不过一个理字。一味护主比真心黑更可怕。最后实在说不过了,无非丢来一句“不喜欢别用”!────依然是护主的心态。可他知道主子是一定拒绝长进的么。
> > 在 2012-10-10 下午4:31,"minux" <minu...@gmail.com (javascript:)>写道:
> > >
> > > On Oct 10, 2012 4:11 PM, "Liigo Zhuang" <com....@gmail.com (javascript:)> wrote:
> > > > 同一个pkg允许多个init函数并存,本身就是不靠谱的设计,完全是没有必要的,也与golang一贯的设计准则不符。不知道是哪个家伙一拍脑门就定了。
> > >
> > > 拜托您下次过来黑Golang请好好准备好您的理由。
> > > 您这句话把"同一个pkg允许多个init函数并存"换成某个
> > > 语言L的某个特性F,然后把golang替换成L,然后这句话
> > > 可以说任何语言L的任何特性F是有问题的。
> > > 要想继续讨论,请说明为什么不靠谱,没啥没必要,
> > > golang的设计风格是什么,哪个不符合? 给点细节,
> > > 别用这么空洞抽象的说辞。
> > >
> > > --
> > > 官网: http://golang-china.org/
> > > IRC: irc.freenode.net (http://irc.freenode.net) #golang-china
> > > @golangchina
> >
>
> --
> --
> 官网: http://golang-china.org/
> IRC: irc.freenode.net (http://irc.freenode.net) #golang-china
> @golangchina
>
>
>



chai2010

unread,
Jan 21, 2013, 12:42:12 AM1/21/13
to golang中文小组
可以整一本<The GOLANG HATERS Handbook>.



在 2013年1月21日下午12:58,Liigo Zhuang <com....@gmail.com>写道:
--
--
官网: http://golang-china.org/
IRC: irc.freenode.net #golang-china
@golangchina
 
 
 

vuleetu

unread,
Jan 21, 2013, 2:24:56 AM1/21/13
to golang...@googlegroups.com
真不知道你用过init函数没, init在多个源码中各自做自己的初始化工作,使得代码书写更加优雅。


download.go:

func init() {                                                                                                                                                 
    web.Get("/files/(.+)", HandleDownload)                                                                                                                    
}                                                                                                                                                             
                                                                                                                                                              
func HandleDownload(ctx *web.Context, fileid string){                                                                                                         
   //
}

upload.go:

func init() {                                                                                                                                                 
    web.Put("/files/(.+)", HandleUpload)                                                                                                                    
}                                                                                                                                                             
                                                                                                                                                              
func HandleUpload(ctx *web.Context, fileid string){                                                                                                         
   //
}

main.go:

func main() {
  web.Get("(.*)", NotFound)
  web.Run(":80")
}

func NotFound(ctx *web.Context, path string) {
   // page not found
}


你看,每个文件只负责自己工作,是不是感觉很干净,如果什么时候我加一个功能或者删除一个功能,直接增加或者删除文件来即可。


如果你确实想某一个初始化工作在所有的init之前被初始话,你可以使用匿名全局变量:

var _ = DoSomeInit()


func DoSomeInit() bool {
   // init here
}


2012/10/10 Liigo Zhuang <com....@gmail.com>
prog_startup_seq.jpg

Risingv

unread,
Jan 22, 2013, 1:09:53 AM1/22/13
to golang...@googlegroups.com
minux没有对你人身攻击,至多说成语气激烈一些。
人身攻击是从你开始的,还有你主奴思想太重了。
函数重载只是提供语法上的便利,语义上并没有什么狠实质的东西。
从可读性考虑,只要函数名有相同的前缀或后缀都可表达它们是做一件事情的函数
go的一大特性是飞快的编译速度,而为了这一点点语法上的便利,却大大提高编译器设计的复杂度,是不符合go的设计目标的。
至于多个init在一个package你觉得不合理,你大可以写成一个,对于有争议的东西大可以让程序员自己去选择,写多个init的程序员只要心中了解去避免顺序依赖就行了,并不是太难的事情。就像go同时支持面向过程和面向对象,如果使用时,两种风格混搭使用可能会产生不太好维护的设计,但这不是语言的错误,但如果不提供选择的自由,那么就是语言的错误。
编程的东西,更像哲学,很多问题只有不同观点学说,却没有标准答案。你可以捍卫自己信仰,却不可以杜绝别人捍卫自己信仰的权力。尽量陈述事实是最好的,引经据典,对大家也都有裨益。如果说服不了别人,明智一点言罢即可,多说无益,甚至自找不快


在 2013年1月21日下午12:58,Liigo Zhuang <com....@gmail.com>写道:

--
--
官网: http://golang-china.org/
IRC: irc.freenode.net #golang-china
@golangchina
 
 
 



--
Life is in chaos, keep struggling.
Personal blog: risingv.in

晓强李

unread,
Jan 31, 2013, 5:16:27 AM1/31/13
to golang...@googlegroups.com
关于这点我比较赞成chai2010的说法,不过我觉得允许多个Init的意义在于团队协作,一个package可能比较大,很有可能会多人协同开发,这时候每个人的工作应该是一个package中相对独立的功能,所以可以分切为多个go文件(而且即使不是多人协同开发也应该把同一个package中相对独立的功能划分开来,这样将来修改的时候不会影响到别的部分,而彻底的划分必然牵涉到初始化也划分开.),每个人负责自己这片相对独立的功能的初始化行为. 我理解应该是这样的,欢迎拍砖.

在 2012年10月10日星期三UTC+8下午4时11分10秒,Liigo Zhuang写道:
Reply all
Reply to author
Forward
0 new messages