Why should I use an init function rather than just putting it in the main function?

blov · · 500 次点击    
这是一个分享于 的资源,其中的信息可能已经有所发展或是发生改变。
<p>I understand that <a href="https://golang.org/doc/effective_go.html#init" rel="nofollow">the init function</a> executes b/f the main function. I&#39;m struggling on what to actually put in there...instead of putting it in the init function, why not just put it at the beginning of the main function? In the example given on that link all of that can be in the main function. Is it just a matter of preference?</p> <p>yes, my username checks out ;)</p> <hr/>**评论:**<br/><br/>JHunz: <pre><p>If you&#39;re strictly concerned with your main package, then it doesn&#39;t matter very much whether all your setup is in an init function or at the beginning of main. For every other package though, it&#39;s guaranteed setup that is executed exactly once for the package before any other code in the package is executed. So any package that needs some plumbing hooked up before any calls are made to its public functions should put that plumbing in init.</p></pre>ThinkLessStupidMore: <pre><p>that makes sense. thx!</p></pre>ThinkLessStupidMore: <pre><p>Are there any open source repos that do this? I&#39;ve been looking and haven&#39;t come across any (or maybe missed it).</p></pre>natalchile: <pre><p>SQL drivers use <code>init</code> to register themselves: <a href="https://github.com/go-sql-driver/mysql/blob/66312f7fe2678aa0f5ec770f96702f4c4ec5aa8e/driver.go#L165-L167" rel="nofollow">https://github.com/go-sql-driver/mysql/blob/66312f7fe2678aa0f5ec770f96702f4c4ec5aa8e/driver.go#L165-L167</a></p></pre>karnd01: <pre><p>I do it in this repo <a href="https://github.com/go-playground/universal-translator/blob/master/resources/locales/en/main.go" rel="nofollow">https://github.com/go-playground/universal-translator/blob/master/resources/locales/en/main.go</a> it allows a locale to be registered once and only once.</p></pre>cs-guy: <pre><p>Here is an example from one of my packages: <a href="https://github.com/go-stack/stack/blob/master/stack.go#L313" rel="nofollow">https://github.com/go-stack/stack/blob/master/stack.go#L313</a>. In this case an init function isn&#39;t strictly needed because it could also be done by assigning the package var the result of a regular function as done here: <a href="https://github.com/go-stack/stack/blob/master/stack.go#L270" rel="nofollow">https://github.com/go-stack/stack/blob/master/stack.go#L270</a>. But in both cases the need is to cache some information about the runtime environment to avoid looking it up repeatedly later. The ability to do this before the package is used by main avoids more complicated lazy evaluation schemes or other hackery.</p></pre>SSoreil: <pre><p>Check out the image package and the packages for the formats it&#39;s supports. The drivers call a registerformat function of the image package in their init function to add themselves.</p></pre>dlsniper: <pre><p>Please never ever ever advise / do things in init() unless you <strong>really</strong> know what you are doing. The problem with init() is that there&#39;s no control over it and can make testing a pita to use. The only place here init() is ok to do is in package main if you don&#39;t want to test that, otherwise for any package you have, you should do a Initialize() or whatever you want to call it function which could optionally be fitted with a config parameter (maybe as an example: Initialize(conf *config) ).</p></pre>izuriel: <pre><p>&#34;Don&#39;t use what is provided, instead make your own that functions in the exact opposite way.&#34;</p> <p>So now you have to write a flag to prevent initialize toon twice. If you packages zero value wasn&#39;t useful already you better scramble to make it so because someone is going to forget to call initialize. Shying away from tools because &#34;it can be abused&#34; is a very sad attitude to have. Instead of preaching <em>against</em> the tool you should preach <em>how to use it</em> which is a far more valuable standpoint. I&#39;m so sick of everyone being scared to use what is provided because of the potential for not fully understanding it. If someone makes poor decisions writing an init function it&#39;s not Go&#39;s fault, it&#39;s not the compilers fault, it&#39;s not the feature designers fault. It&#39;s the engineers fault for not educating themselves and/or their team not encouraging better practice from them. </p> <p>There is no reason to reimplement init, it&#39;s a lot of work for fewer features and guarantees. If you need configuration to be sent to you init then you probably don&#39;t need a package level init anyways and should build and return a useful struct. </p></pre>weberc2: <pre><blockquote> <p>Shying away from tools because &#34;it can be abused&#34; is a very sad attitude to have.</p> </blockquote> <p>This is precisely the reason I use Go. It foregoes a lot of frequently-abused features (inheritance, exceptions, etc). I favor general tools over specialized tools all else equal, and in the init() case it does seem like all else is equal (though perhaps I&#39;m missing something?).</p></pre>dlsniper: <pre><p>I&#39;m sorry but clearly you have not bumped into people using init() the wrong way, like this for example: <a href="https://play.golang.org/p/XZmc9lNhlz" rel="nofollow">https://play.golang.org/p/XZmc9lNhlz</a> ?</p> <p>Now, I&#39;m happy to improve my Go skills so I look forward on how you&#39;d test sort of situations (without Windows btw). And before you jump up and say but you can split up into OS differentiated files... Yes I know I could do that but that&#39;s a stupid example of something. What if in the init() I would have called an API? Or initialized the connection to the database? Or this would be a package that you&#39;d want to use how do you inject your on values for those variables?</p> <p>Yes, there are examples in the standard library and (almost?) all SQL drivers use <strong>init()</strong> to register themselves but those are clear situations where one <strong>knows</strong> what he/she is doing. Which is what I&#39;ve said in my comment, don&#39;t advise to use init() unless you <strong>really</strong> know what you are doing.</p></pre>synalx: <pre><blockquote> <p>Which is what I&#39;ve said in my comment, don&#39;t advise to use init() unless you really know what you are doing.</p> </blockquote> <p>Someone has asked &#34;how do I use this?&#34; and your answer is &#34;don&#39;t use it unless you already know how&#34; - can you see how that&#39;s pretty unhelpful?</p></pre>natefinch: <pre><p>There are very few places where you need init. By definition, since it has no input or output, it&#39;s usefulness is fairly limited. Also, writing tests for it is somewhere between difficult and impossible. And yes, many people misuse init. </p> <p>I don&#39;t think you should never use it, but consider it very carefully. It is, by definition, all about global state, which is bad. </p> <p>Main is probably the one place you never need it though, since func main works exactly like init, so why have two?</p></pre>weberc2: <pre><p>I agree with you, but I think your bigger beef is with global state. init() is to global state what constructors are to object state. Testing global state is always a pain in the ass, and init() is no exception.</p></pre>FrenchDonkey: <pre><p>Am I wrong? But I was under the impression that the init would get executed only once whereas the main would happen everytime ? In the case of a web server, init would make sure that you have the env setup and the main start the execution ?</p></pre>dlsniper: <pre><p>init() as well as main() are executed once and only once (caveat for init which can have multiple definitions in the same package in which case each definition will be executed only once). main() is the entrypoint in your app, it gets called in order to start the execution of whatever you want to do, be it a simple CLI app or a more complex server / UI app. Once main exits your program will stop execution. In a webserver, the handlers get executed multiple times, but main will always be executed once (and continue to be executed, else the server will stop).</p> <p>You can read about main and init here: <a href="https://golang.org/ref/spec#Package_initialization" rel="nofollow">https://golang.org/ref/spec#Package_initialization</a> </p> <p>I hope this clears up the confusion. </p></pre>alficles: <pre><p>The other answers are basically correct... there&#39;s no technical requirement, assuming you&#39;re in the <code>main</code> package. Nevertheless, there are readability reasons. I often use <code>init()</code> functions to document mandatory initialization (that really shouldn&#39;t or can&#39;t fail) in all in one place. Example:</p> <pre><code>var environmentValue string func init() { var err error environmentValue, err = getValueFromEnvironment() if err != nil { panic(err) } } </code></pre> <p>In this way, the <code>init()</code> function serves the role of an initializer, but with some additional required logic.</p></pre>jasonrichardsmith: <pre><p>I use init whenever I can for initialization. The problem with init is there is no guarantee on when it will be executed against another packages init.</p></pre>

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

500 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传