<p>Hello all, I am using Go to do homework in a database class rather than my usual Python as a way to learn Go. So I've learned how to scan data from a query directly into a struct using sqlx, but I have a question on the structs themselves. The example database has these tables: Pets, Customers, Visits, Owner History. (It's a vet if you havn't guessed) So I have made a struct for each table so I can pull the data from the query and so on. The goal of the program is to give a simple UI to get data from the database, so for example, you could choose "Select all data in Pets table" from a menu and it executes that query and prints the results. Am I going to have to write a different function for each table for every different scenario, or could I have a single selectAll function that takes a table's name as an argument that can use a different type of struct depending on the table that is being queried? My first thought was to use some sort of inheritance and have a generic Data struct and have all of the others inherit from it, that way I could do something like:</p>
<pre><code>var d Data
if table == "Pets"{
d = Pet{}
}
</code></pre>
<p>Is something like that Possible or am I going about this the wrong way? The actual homework of setting up the UI does not confuse me, I just know that there is a better way than writing the same functions for each data type over and over again.</p>
<hr/>**评论:**<br/><br/>lobster_johnson: <pre><p>That's not possible. Go doesn't have inheritance, and polymorphism is limited to interfaces. Go also doesn't have algebraic data types.</p>
<p>In cases like this, where you have "pure data" structs with little in the way of actual behaviour associated with them, you can sort of cheat with interfaces. For example:</p>
<pre><code>type Record interface{
isRecord()
}
type Pet struct {
Name string
Weight float64
}
func (Pet) isRecord() {}
type Customer struct {
Name string
}
func (Customer) isRecord() {}
</code></pre>
<p>The <code>isRecord</code> is really just a dummy method so you can get <em>some</em> type safety at runtime; only <code>Pet</code> and <code>Customer</code> will be compatible with a variable or argument of type <code>Record</code>.</p>
<p>Now you can have:</p>
<pre><code>func FetchAllRecords() []Record
</code></pre>
<p>...which can return a mix of pets and customers if it wants to. You need a type switch to identify what you get back:</p>
<pre><code>for _, record := range FetchAllRecords() {
switch r := record.(type) {
case Pet:
// is a Pet
case Customer
// is a Customer
}
}
</code></pre>
<p>It's not ideal, but it does the job.</p>
<p>Another method is to not do this, but instead have things like:</p>
<pre><code>func FetchAllPets() []Pet
func FetchAllCustomers() []Customer
// etc.
</code></pre>
<p>Of course, it's tedious to write the serialization/deserialization code for every possible table, and a common way to avoid such boilerplate is to generate the code.</p>
<p>Instead of reinventing the wheel, you should take a look at existing ORMs. <a href="https://github.com/jinzhu/gorm" rel="nofollow">Gorm</a> is supposed to be good.</p></pre>
这是一个分享于 的资源,其中的信息可能已经有所发展或是发生改变。
入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889
- 请尽量让自己的回复能够对别人有帮助
- 支持 Markdown 格式, **粗体**、~~删除线~~、
`单行代码`
- 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
- 图片支持拖拽、截图粘贴等方式上传