<p>I have been curious about the possibility of generating type specific, standardized algorithms using go generate and templates without the interface{} nonsense. I finally sat down and wrote some. Though far from a finished work and not very flexible (yet), it turned out to be more useful than I expected. </p>
<p>I decided to slap on some lipstick (README) and a smile (LICENSE) and push it to github. If anyone finds it useful or thinks it might become useful, let me know and I will continue to update it in a more general way than my specific project requires.</p>
<p><a href="https://github.com/dshills/yaggg" rel="nofollow">https://github.com/dshills/yaggg</a> - Yet Another Go Generic Generator</p>
<p>If this is a new concept to anyone reading this here are some cool existing projects:
<a href="http://clipperhouse.github.io/gen/" rel="nofollow">http://clipperhouse.github.io/gen/</a>
<a href="https://github.com/joeshaw/gengen" rel="nofollow">https://github.com/joeshaw/gengen</a></p>
<p>Enjoy...</p>
<hr/>**评论:**<br/><br/>dchapes: <pre><p>IMO in the rare cases where something like this is desirable a better approach
(which I got mostly completed in the past as an exercise)
would be to take fully valid and compiling Go code
(possibly with it's own test cases so you can test your "generic" implementation is correct),
parse it with the existing ast package(s),
change out the types,
and write out the modified source to a new file.</p>
<p>E.g. Take <code>set_stub.go</code> something like
(a silly example with a trivial set implementation):</p>
<pre><code> // +build ignore
package foo
type T int // Placeholder
// T_Set is a set of T
type T_Set map[T]struct{}
func New_T_Set(n int) { return make(T_Set, n) }
// Add adds i to the T_Set.
func (s T_Set) Add(i T) { s[i] = struct{}{} }
// Remove removes i from the T_Set.
func (s T_Set) Remove(i T) { delete(s, i) }
// Has returns true if i is in the T_Set.
func (s T_Set) Has(i T) bool {
var x T // note, useless extra variable just for show
x = T(i)
_, ok := s[x]
return ok
}
</code></pre>
<p>And with a gogenerate line containing something like <code>T=int</code>
produce a file something like this:</p>
<pre><code> package foo
// IntSet is a set of int
type IntSet map[int]struct{}
func NewIntSet(n int) { return make(IntSet, n) }
// Add adds i to the IntSet.
func (s IntSet) Add(i int) { s[i] = struct{}{} }
// Remove removes i from the IntSet.
func (s IntSet) Remove(i int) { delete(s, i) }
// Has returns true if i is in the IntSet.
func (s IntSet) Has(i int) bool {
var x int
x = int(i)
_, ok := s[x]
return ok
}
</code></pre>
<p>(note the extra variable in <code>Has</code> is just to show template re-writing)</p></pre>dshills: <pre><p>Interesting. So you see the advantage of doing it this way is to insure compilable code and an easy way to test? I could certainly see that. I actually use the _test.go to run a full version and then copy it to the templates which seemed a little backwards :P</p>
<p>As I mention in the post I did it as much for a proof of concept as anything else. </p>
<p>Outside of a change in the language spec I would love if someone standardized something like this. It would be great to have a large library of algorithms available written by people smarter than me to drop into projects. Something like STL</p></pre>dchapes: <pre><p>I too wrote the tool that does (most of) what I gave just as a proof of concept (and to play with the ast package).</p>
<p>In practice I've never really needed anything like this (e.g. I call the set example I used "silly" since in practice when I need such a set I just write out the couple of lines it takes and often use a map of bools directly without methods. Just as whenever I need sorting I just write out the trivial one-liner <code>Len</code> and <code>Swap</code> methods in-front of the sometimes more involved <code>Less</code> method that are needed for <code>Sort.Interface</code>).</p></pre>dshills: <pre><p>I guess that is the argument from the Go team. You don't need that stuff very often and when you do it isn't hard to write. I'm not completely sold but I'm about to embark on my first large scale Go project so we shall see :)</p></pre>icholy: <pre><p>Heh, I arrived at the exact same idea of using <code>_T_</code> in the method/function/type names to be replaced while implementing (never finished it) my own go generics implementation.</p></pre>dchapes: <pre><p>Mine uses whatever string is provided (e.g. "K=string V=int" or "T1=MyType T2=OtherType", etc) and replaces <code>T</code>, <code>Foo_T</code>, <code>T_Foo</code>, or <code>Foo_T_Bar</code> (Under the assumption that idiomatic Go code otherwise avoids "_" in identifiers). For types like "int" it capitalizes as appropriate (or an alternate can be specified). The annoying thing that I never bothered getting fully correct was editing the comments.</p></pre>anlhord: <pre><p>and the advantage on simply using copy+paste & search+replace?</p></pre>dshills: <pre><p>None other than simplicity and repeatability. copy+paste with search and replace was how I was doing it before I wrote this :)</p>
<p>Also was curious if it was doable. </p>
<p>oh I so wish we had generics :( I love working in Go. It is the only thing in the entire workflow that really
frustrates me.</p></pre>anlhord: <pre><p>as a person implementing generics to gccgo (against the will of go authors), I can guarantee you will keep frustrated, even if they are implemented.</p>
<p>most blatant copy paste cases will be reduced, but there will be still rough edges. things like operator overloading etc... </p>
<p>furthermore for example when u subtract *T - *T and provide T type as struct or whatever what should happen. etc..</p></pre>
这是一个分享于 的资源,其中的信息可能已经有所发展或是发生改变。
入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889
- 请尽量让自己的回复能够对别人有帮助
- 支持 Markdown 格式, **粗体**、~~删除线~~、
`单行代码`
- 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
- 图片支持拖拽、截图粘贴等方式上传