Note that there are some explanatory texts on larger screens.

plurals
  1. POIdiomatic way to implement generic functions in Go
    primarykey
    data
    text
    <p>Let's say I want to write a function to check whether a predicate is matched for an element in a slice:</p> <pre><code>func IsIn(array []T, pred func(elt T) bool) bool { for _, obj := range array { if pred(obj) { return true;} } return false; } </code></pre> <p>Obviously, the previous code won't compile, since <code>T</code> does not exist. I can replace it with some <code>interface{}</code> like this:</p> <pre><code>func IsIn(array[]interface{}, pred func(elt interface{}) bool) bool { ... } </code></pre> <p>As I am happy to let the predicate perform the casting:</p> <pre><code>IsIn([]interface{}{1,2,3,4}, func(o interface{}) {return o.(int) == 3; }); </code></pre> <p>But then, the function won't accept any array which is not of type <code>[]interface{}</code>:</p> <pre><code>IsIn([]int{1,2,3,4}, func(o interface{}) { return o.(int) == 3; }) // DO NOT COMPILE </code></pre> <p>And similarly:</p> <pre><code>func IsIn(arr interface, pred func(o interface{}) bool) bool { for _, o := range arr.([]interface{}) { ... } } IsIn([]int{1,2,3,4}, func(o interface{}) { return o.(int) == 3; }) // PANICS AT RUNTIME (cannot cast []int to []interface) </code></pre> <p>The other alternative is to have typed functions for each array type:</p> <pre><code>IsInInt(arr []int, pred func(i int) bool) { ... } IsInStr(arr []string, pred func(s string) bool) { ... } ... </code></pre> <p>But it seems like a LOT of code duplication.</p> <p>Has anyone come up with an nice way to deal with such situations ?</p> <p><strong>EDIT</strong></p> <p>Thanks to <a href="https://stackoverflow.com/users/1065241/jnml">jnml</a>'s fantastic tips on Go reflection, I think I have found a nice way to express these patterns, by converting every 'iterable' to a channel:</p> <pre><code>func iter(obj interface{}) chan interface{} { c := make(chan interface{}) v := reflect.ValueOf(obj) if (v.Kind() == reflect.Array || v.Kind() == reflect.Slice) { go func() { for i := 0; i &lt; v.Len(); i++ { c&lt;-v.Index(i).Interface() } close(c) }() } else if v.Kind() == reflect.Chan { go func() { x, ok := v.Recv() for ok { c&lt;-x.Interface() x,ok = v.Recv() } close(c) }() } else if (... whatever iteration protocol you have ...) { } else { panic("Cannot iterate !") } return c; } </code></pre> <p>With my initial example rewritten using it <a href="http://play.golang.org/p/lRmXX19tb9" rel="nofollow noreferrer">on the playground</a>.</p> <p>Thanks a lot to <a href="https://stackoverflow.com/users/1065241/jnml">jnml</a> and <a href="https://stackoverflow.com/users/694331/anisus">ANisus</a> for helping out !</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload