<p>I'm faily new to go and was wondering which one of these is more idomatic.
It just wanted to build a simple CRUD application using <a href="https://github.com/jmoiron/sqlx" rel="nofollow">sqlx</a>.</p>
<pre><code>type Project struct {
Id int `db:"id"`
Title string `db:"title"`
}
</code></pre>
<p>Option 1:</p>
<pre><code>func (p *Project) Get(id int) error {
return db.Get(p, "SELECT * FROM projects WHERE id = $1", id)
}
p := Project{}
p.Get(1)
</code></pre>
<p>Option 2:</p>
<pre><code>func GetProject(id int) (Project, error) {
p := Project{}
err := db.Get(&p, "SELECT * FROM projects WHERE id = $1", id)
return p, err
}
p, _ := GetProject(1)
</code></pre>
<p>I assume something like this would be alright but I wasn't sure about the one above:</p>
<pre><code>p := Project{Title: "Project"}
p.Save() // Writes the newly created Project to the database
</code></pre>
<p>Thanks in advance :)</p>
<hr/>**评论:**<br/><br/>daveddev: <pre><p>Instead of a global, try wrapping the db and add methods to that struct.</p>
<pre><code>type RealDB struct {
*sqlx.DB
}
func (db *RealDB) ProjectByID(id int) (*Project, error)
</code></pre>
<p>Create an interface with the related methods.</p>
<pre><code>type MainDB interface {
ProjectByID(int) (*Project, error)
}
</code></pre>
<p>The db can then be mocked for testing by implementing the interface.</p>
<pre><code>func (db *MockDB) ProjectByID(id int) (*Project, error) {
return &Project{ID: id}, nil
}
</code></pre>
<p><a href="http://www.alexedwards.net/blog/organising-database-access" rel="nofollow">http://www.alexedwards.net/blog/organising-database-access</a></p></pre>flippeeer: <pre><p>Thank you, that was very helpful. </p></pre>tv64738: <pre><blockquote>
<p>func (db <em>sqlx.DB) ProjectByID(id int) (</em>Project, error)</p>
</blockquote>
<p>That ain't gonna work. You need to define a type to add methods to it.</p></pre>daveddev: <pre><p>I spotted that and edited the example just before you replied. Good catch, though.</p></pre>divan0: <pre><p>Basically, you're questioning 'methods vs functions' thing. I believe, it was well covered by Steve Francia (@spf13) in his talk "7 common mistakes in Go".
<a href="http://spf13.com/presentation/7-common-mistakes-in-go-2015/" rel="nofollow">http://spf13.com/presentation/7-common-mistakes-in-go-2015/</a></p>
<p>To be short, if you simply need to populate Project structure with data from the external storage - you don't really have a state. It's just data moving from outside to your variable. Use function (it's option 2 in your example)</p>
<p>Note, that 'function' in its turn, can be a method of another type. For example:</p>
<pre><code>project, err := db.Project(1)
</code></pre></pre>aaaqqq: <pre><p>Not a Go expert & not sure which one's more idiomatic, but I'd prefer option 2 as it is more readable and could be used without first declaring a project instance.</p></pre>dlsniper: <pre><p>Option 2 would be better because then the concerns of each functionality are separated. It looks like Project is used a model and I would expect another piece of the application to handle the lifecycle of it.</p>
<p>Same goes for the save functionality, Save(project *Project) error</p>
<p>It's also worth noting that in Go it's preferred to say Get and Save and omit the "target" (Project)</p></pre>flippeeer: <pre><p>Thanks for your answer.
Should I create an interface and let all my models implement the Get and Save method to "omit the target"?
Or do you have another idea how that could be done?</p></pre>
这是一个分享于 的资源,其中的信息可能已经有所发展或是发生改变。
入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889
- 请尽量让自己的回复能够对别人有帮助
- 支持 Markdown 格式, **粗体**、~~删除线~~、
`单行代码`
- 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
- 图片支持拖拽、截图粘贴等方式上传