FAQ
I am writing a data serialisation module, and I found that "range” only supports builtin types such as string, list, and map.

This make me write a lot of repeated code like

  var value interface{}
         switch value.(type) {
         case []interface{}:
                 foo := len(value.([]interface{})) // I really hate this
                 for index, value := range value.([]interface{}) {
    // do something
                 }

         case map[string]interface{}:
                 bar := len(value.(map[string]interface{})))} // I really hate this
                 for index, value := range value.(map[string]interface{}) {
    // do other thing
                 }
         }

I was wondering why Google implements it like this, why not just range over an interface that has Iter() function.

---------------------------------
Where Python Happens!

mail: linluxiang@gmail.com
twitter: @linluxiang

--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

Search Discussions

  • Jesse McNelis at Nov 25, 2013 at 5:43 am

    On Mon, Nov 25, 2013 at 4:23 PM, linluxiang wrote:

    I am writing a data serialisation module, and I found that "range” only
    supports builtin types such as string, list, and map.

    This make me write a lot of repeated code like

    var value interface{}
    switch value.(type) {
    case []interface{}:
    foo := len(value.([]interface{})) // I really hate this
    for index, value := range value.([]interface{}) {
    // do something
    }

    case map[string]interface{}:
    bar := len(value.(map[string]interface{})))} // I really
    hate this
    for index, value := range value.(map[string]interface{}) {
    // do other thing
    }
    }
    You can drop all the type asserts there, the type switch does it for you.
    eg. http://play.golang.org/p/d45MDc2eWY


    I was wondering why Google implements it like this, why not just range
    over an interface that has Iter() function.
    Iteration by calling a method requires some way of indicating when the
    iteration should finish, and eventually requires some kind of error
    handling.
    If range took an Iter() interface it would then need to handle those kind
    of things as well as handle the concept of nested iteration.
    Python does it with exceptions and a whole bunch of insanity, Go doesn't
    have exceptions and avoids insanity.

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • Matt Harden at Nov 26, 2013 at 11:18 pm
    If you want you can create an iterator method that returns a channel,
    spawning a goroutine to write into the channel, then iterate over that with
    range. close() the channel on the write side when done. The channel will be
    GC'd once there are no references to it remaining. If you only keep a
    writable version of the channel in your goroutine, it's possible the whole
    goroutine will be GC'd once there are no readable references to the
    channel. I'm not sure about that last part.

    On Sun, Nov 24, 2013 at 11:43 PM, Jesse McNelis wrote:
    On Mon, Nov 25, 2013 at 4:23 PM, linluxiang wrote:

    I am writing a data serialisation module, and I found that "range” only
    supports builtin types such as string, list, and map.

    This make me write a lot of repeated code like

    var value interface{}
    switch value.(type) {
    case []interface{}:
    foo := len(value.([]interface{})) // I really hate this
    for index, value := range value.([]interface{}) {
    // do something
    }

    case map[string]interface{}:
    bar := len(value.(map[string]interface{})))} // I really
    hate this
    for index, value := range value.(map[string]interface{}) {
    // do other thing
    }
    }
    You can drop all the type asserts there, the type switch does it for you.
    eg. http://play.golang.org/p/d45MDc2eWY


    I was wondering why Google implements it like this, why not just range
    over an interface that has Iter() function.
    Iteration by calling a method requires some way of indicating when the
    iteration should finish, and eventually requires some kind of error
    handling.
    If range took an Iter() interface it would then need to handle those kind
    of things as well as handle the concept of nested iteration.
    Python does it with exceptions and a whole bunch of insanity, Go doesn't
    have exceptions and avoids insanity.


    --
    You received this message because you are subscribed to the Google Groups
    "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an
    email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • Kyle Lemons at Nov 26, 2013 at 11:44 pm

    On Tue, Nov 26, 2013 at 3:17 PM, Matt Harden wrote:

    If you want you can create an iterator method that returns a channel,
    spawning a goroutine to write into the channel, then iterate over that with
    range. close() the channel on the write side when done. The channel will be
    GC'd once there are no references to it remaining. If you only keep a
    writable version of the channel in your goroutine,
    it's possible the whole goroutine will be GC'd once there are no readable
    references to the channel. I'm not sure about that last part.
    It doesn't behave that way and probably won't in the future. Imagine how
    confusing it would be if all of your deadlocked-on-send goroutines vanished
    from your stack trace!

    On Sun, Nov 24, 2013 at 11:43 PM, Jesse McNelis wrote:
    On Mon, Nov 25, 2013 at 4:23 PM, linluxiang wrote:

    I am writing a data serialisation module, and I found that "range” only
    supports builtin types such as string, list, and map.

    This make me write a lot of repeated code like

    var value interface{}
    switch value.(type) {
    case []interface{}:
    foo := len(value.([]interface{})) // I really hate this
    for index, value := range value.([]interface{}) {
    // do something
    }

    case map[string]interface{}:
    bar := len(value.(map[string]interface{})))} // I really
    hate this
    for index, value := range value.(map[string]interface{})
    {
    // do other thing
    }
    }
    You can drop all the type asserts there, the type switch does it for you.
    eg. http://play.golang.org/p/d45MDc2eWY


    I was wondering why Google implements it like this, why not just range
    over an interface that has Iter() function.
    Iteration by calling a method requires some way of indicating when the
    iteration should finish, and eventually requires some kind of error
    handling.
    If range took an Iter() interface it would then need to handle those kind
    of things as well as handle the concept of nested iteration.
    Python does it with exceptions and a whole bunch of insanity, Go doesn't
    have exceptions and avoids insanity.


    --
    You received this message because you are subscribed to the Google Groups
    "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an
    email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
    --
    You received this message because you are subscribed to the Google Groups
    "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an
    email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • Bryan Mills at Nov 27, 2013 at 12:46 am
    Um... Yeah, don't do that - Go is not Concurrent ML. Spawning a goroutine
    to feed an iterator is a good way to permanently leak memory in your Go
    program.

    For a nice, non-leaky way to iterate over a custom data structure, see
    filepath.Walk in the standard library.
    (http://golang.org/pkg/path/filepath/#Walk)
    On Tuesday, November 26, 2013 6:17:36 PM UTC-5, Matt Harden wrote:

    If you want you can create an iterator method that returns a channel,
    spawning a goroutine to write into the channel, then iterate over that with
    range. close() the channel on the write side when done. The channel will be
    GC'd once there are no references to it remaining. If you only keep a
    writable version of the channel in your goroutine, it's possible the whole
    goroutine will be GC'd once there are no readable references to the
    channel. I'm not sure about that last part.


    On Sun, Nov 24, 2013 at 11:43 PM, Jesse McNelis <jes...@jessta.id.au<javascript:>
    wrote:
    On Mon, Nov 25, 2013 at 4:23 PM, linluxiang <linlu...@gmail.com<javascript:>
    wrote:
    I am writing a data serialisation module, and I found that "range” only
    supports builtin types such as string, list, and map.

    This make me write a lot of repeated code like

    var value interface{}
    switch value.(type) {
    case []interface{}:
    foo := len(value.([]interface{})) // I really hate this
    for index, value := range value.([]interface{}) {
    // do something
    }

    case map[string]interface{}:
    bar := len(value.(map[string]interface{})))} // I really
    hate this
    for index, value := range value.(map[string]interface{})
    {
    // do other thing
    }
    }
    You can drop all the type asserts there, the type switch does it for you.
    eg. http://play.golang.org/p/d45MDc2eWY


    I was wondering why Google implements it like this, why not just range
    over an interface that has Iter() function.
    Iteration by calling a method requires some way of indicating when the
    iteration should finish, and eventually requires some kind of error
    handling.
    If range took an Iter() interface it would then need to handle those kind
    of things as well as handle the concept of nested iteration.
    Python does it with exceptions and a whole bunch of insanity, Go doesn't
    have exceptions and avoids insanity.


    --
    You received this message because you are subscribed to the Google Groups
    "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an
    email to golang-nuts...@googlegroups.com <javascript:>.
    For more options, visit https://groups.google.com/groups/opt_out.
    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • Carlos Salguero at Nov 26, 2013 at 11:38 pm
    This is a code I'm using to iterate through a struct's fields.
    Note this function is not recursive because the structs I'm using only are
    1 level deep.


    func structToMap(m interface{}) (retval map[string]interface{}) {

         s := reflect.ValueOf(m)
         typeOfT := s.Type()
         if typeOfT.Kind() == reflect.Ptr {
             typeOfT = typeOfT.Elem()
         }
         for i := 0; i < s.NumField(); i++ {
             f := s.Field(i)
             // fmt.Printf("%d: %s %s = %v\n", i, typeOfT.Field(i).Name,
    f.Type(), f.Interface()) // uncomment this to see what's happening
             retval[strings.ToLower(typeOfT.Field(i).Name)] = f.Interface()
         }
         return
    }


    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • RickB at Dec 5, 2013 at 9:45 pm
    Extending the usefulness of 'range' is one of the simplest ways I can think
    of making Go more flexible. I really like the things you can do with
    'range', but it could do a lot more reasonably easily.

    Suppose there were to be one or two standard-library interfaces that
    'range' supported. Then I could range over my custom data structures
    simply by implementing one of those interfaces. For example, for array-like
    iteration:

    type ArrayRangeable interface {
         Len() int
         Get(i int) interface{}
    }

    Arrays and slices all provide an interface that is something like this
    built-in, i.e. with 'len()' and 'array[index]' indexing.

    Or, for iterable iteration is the slightly-more complex interface:

    type UnboundedRangeable interface {
         HasNext() bool
         Next() interface{}
    }

    As with iterators in other languages, this would only be traversable once,
    which raises issues that would need to be thought through, so
    'UnboundedRangeable' might need further work. But the basic idea is simple
    in principle.

    One disadvantage of the suggestion is that neither of these interfaces has
    strongly-typed values at compile time because they both rely on
    'interface{}'.

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • Minux at Dec 6, 2013 at 12:59 am

    On Dec 5, 2013 4:44 PM, "RickB" wrote:
    Extending the usefulness of 'range' is one of the simplest ways I can
    think of making Go more flexible. I really like the things you can do with
    'range', but it could do a lot more reasonably easily.
    Suppose there were to be one or two standard-library interfaces that
    'range' supported. Then I could range over my custom data structures
    simply by implementing one of those interfaces. For example, for array-like
    iteration:
    type ArrayRangeable interface {
    Len() int
    Get(i int) interface{}
    }

    Arrays and slices all provide an interface that is something like this
    built-in, i.e. with 'len()' and 'array[index]' indexing.
    Or, for iterable iteration is the slightly-more complex interface:

    type UnboundedRangeable interface {
    HasNext() bool
    Next() interface{}
    }

    As with iterators in other languages, this would only be traversable
    once, which raises issues that would need to be thought through, so
    'UnboundedRangeable' might need further work. But the basic idea is simple
    in principle.
    One disadvantage of the suggestion is that neither of these interfaces
    has strongly-typed values at compile time because they both rely on
    'interface{}'.
    in fact, that is the biggest problem. losing type safety in range is not
    the way to go.

    this issue has been discussed at length on this mailing list, please search
    the archive for prior threads.

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
groupgolang-nuts @
categoriesgo
postedNov 25, '13 at 5:23a
activeDec 6, '13 at 12:59a
posts8
users8
websitegolang.org

People

Translate

site design / logo © 2022 Grokbase