Help with understanding this Struct/Inheritance problem in golang?

blov · · 479 次点击    
这是一个分享于 的资源,其中的信息可能已经有所发展或是发生改变。
<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&#39;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&#39;s a vet if you havn&#39;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 &#34;Select all data in Pets table&#34; 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&#39;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 == &#34;Pets&#34;{ 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&#39;s not possible. Go doesn&#39;t have inheritance, and polymorphism is limited to interfaces. Go also doesn&#39;t have algebraic data types.</p> <p>In cases like this, where you have &#34;pure data&#34; 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&#39;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&#39;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

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