FAQ
I just start thinking that I begin understanding go and it quickly bytes me
back :(

I have a function with a signature "func AssertEqual(t *testing.T, args...
interface{})" that happily works if called with strings for args...
However, I have this one: "func Contains(list []interface{}, token
interface{}) bool" which doesn't: if I call it with a []string and string,
the compiler yells "cannot use list (type []string) as type []interface {}
in function argument". I am surely missing something but I cannot grasp
what. Can anyone please help sorting this out? Thank you!

--

Search Discussions

  • DisposaBoy at Nov 21, 2012 at 7:19 am
    it's mentioned in the FAQ

    --
  • Jesse McNelis at Nov 21, 2012 at 7:23 am

    On Wed, Nov 21, 2012 at 6:12 PM, yassen wrote:

    I just start thinking that I begin understanding go and it quickly bytes
    me back :(

    I have a function with a signature "func AssertEqual(t *testing.T, args...
    interface{})" that happily works if called with strings for args...
    However, I have this one: "func Contains(list []interface{}, token
    interface{}) bool" which doesn't: if I call it with a []string and string,
    the compiler yells "cannot use list (type []string) as type []interface {}
    in function argument". I am surely missing something but I cannot grasp
    what. Can anyone please help sorting this out? Thank you!

    http://golang.org/doc/go_faq.html#convert_slice_of_interface
    http://golang.org/ref/spec#Passing_arguments_to_..._parameters
    "If the final argument is assignable to a slice type []T, it may be passed
    unchanged as the value for a ...T parameter if the argument is followed by
    .... In this case no new slice is created."

    When you're passing individual strings the call takes those strings
    converts them to interface{} values and allocates a new []interface{} to
    put them in.
    When you pass a slice with '...' the call won't allocate and will instead
    use the slice directly. But since this is a []string and not a
    []interface{} it can't do that because they are different types (as
    mentioned in the FAQ), so you get a type error.

    You can do the conversion yourself

    a:=[]string{"pizza","pie"}
    b := make([]interface,0,len(a))
    for _,i:= range a{
    b = append(b,i)
    }
    Assert(t,b...)
    or just just pass the strings individually,
    Assert(t, a[0],a[1])




    --
    =====================
    http://jessta.id.au

    --
  • Yassen at Nov 21, 2012 at 9:33 am
    Jesse, DisposaBoy, thank you guys! It is indeed in the FAQ: []string and
    []intreface{} have different representation in memory so they are not
    compatible.
    On Wednesday, November 21, 2012 9:23:41 AM UTC+2, Jesse McNelis wrote:

    http://golang.org/doc/go_faq.html#convert_slice_of_interface
    http://golang.org/ref/spec#Passing_arguments_to_..._parameters
    "If the final argument is assignable to a slice type []T, it may be
    passed unchanged as the value for a ...T parameter if the argument is
    followed by .... In this case no new slice is created."

    When you're passing individual strings the call takes those strings
    converts them to interface{} values and allocates a new []interface{} to
    put them in.
    When you pass a slice with '...' the call won't allocate and will instead
    use the slice directly. But since this is a []string and not a
    []interface{} it can't do that because they are different types (as
    mentioned in the FAQ), so you get a type error.

    You can do the conversion yourself

    a:=[]string{"pizza","pie"}
    b := make([]interface,0,len(a))
    for _,i:= range a{
    b = append(b,i)
    }
    Assert(t,b...)
    or just just pass the strings individually,
    Assert(t, a[0],a[1])
    Well, my problem is with Contains(t, token, list...). It is supposed to
    give an answer to the question if the token is found in the list, where
    list is supposed to be a slice of elements with the same type as token. If
    I swap Contains() args to have token first and rewrite the call to
    Contains() to have the token as first arg and the other elements as scalar
    args, it works. However, that is terribly inconvenient and thus not usable.

    Any way to "unpack" a []string slice into a scalar sequence of arguments? I
    guess no way, but asking just in case. Thanks!

    --
  • Yassen at Nov 21, 2012 at 9:42 am

    On Wednesday, November 21, 2012 11:33:27 AM UTC+2, yassen wrote:
    Any way to "unpack" a []string slice into a scalar sequence of arguments?
    I guess no way, but asking just in case. Thanks!
    I mean a syntax construct which does the opposite of ... and will make a
    call to a variadic function with a sequence of scalar arguments taken from
    the given slice. Example (represented by the double asterisk):

    func Contains(token interface{}, list... interface{}) bool {
    for _, v := range list {
    if token == v { return true }
    }
    return false
    }

    args := []string{"one", "2", "three"}
    ok := Contains("2", args**)

    (Apologies for my go ignorance)

    --
  • Volker Dobler at Nov 21, 2012 at 11:07 am

    Am Mittwoch, 21. November 2012 10:42:24 UTC+1 schrieb yassen:
    I mean a syntax construct which does the opposite of ... and will make a
    call to a variadic function with a sequence of scalar arguments taken from
    the given slice. Example (represented by the double asterisk):

    func Contains(token interface{}, list... interface{}) bool {
    for _, v := range list {
    if token == v { return true }
    }
    return false
    }

    args := []string{"one", "2", "three"}
    ok := Contains("2", args**)
    This is more than just some syntax and syntactical sugar. This would
    need exactly the described conversion between []interface{}
    (which is what list in Contains basically is) and []string (which you
    want to pass in). It does not matter that your ** tries to say
    "unpack slice": After unpacking, the resulting positional parameters
    would have to be repacked to be represented by the list []interface
    slice. Nothing won.

    (I know it "feels strange" at first to write the same Contains
    function twice, e.g. once for string and once for int. If you happen
    to implement the function 25 times: Refactor massively, e.g.
    introduce appropriate interfaces or use reflection. If you just
    need string, int and float64 why not a bit of copy&paste? This
    might be the easier/more readable/cleaner to maintain way
    of doing it. Have some test to maintain correctness. Lets assume
    your Contains needs extra cases to handle NaNs or Infs in the
    float64 case: Much easier with a ContainsFloat64 version than
    a generic Contains. DRY is a nice principle, but it doesn't have
    the status of Kant's Categorical Imperative.)

    Volker

    --
  • Yassen at Nov 21, 2012 at 11:22 am
    Thanks, Volker,
    On Wednesday, November 21, 2012 1:07:04 PM UTC+2, Volker Dobler wrote:

    This is more than just some syntax and syntactical sugar. This would
    need exactly the described conversion between []interface{}
    (which is what list in Contains basically is) and []string (which you
    want to pass in). It does not matter that your ** tries to say
    "unpack slice": After unpacking, the resulting positional parameters
    would have to be repacked to be represented by the list []interface
    slice. Nothing won.
    Well, but syntax sugar helps keep the code less noisy.

    (I know it "feels strange" at first to write the same Contains
    function twice, e.g. once for string and once for int. If you happen
    to implement the function 25 times: Refactor massively, e.g.
    introduce appropriate interfaces or use reflection. If you just
    need string, int and float64 why not a bit of copy&paste? This
    might be the easier/more readable/cleaner to maintain way
    of doing it. Have some test to maintain correctness. Lets assume
    your Contains needs extra cases to handle NaNs or Infs in the
    float64 case: Much easier with a ContainsFloat64 version than
    a generic Contains. DRY is a nice principle, but it doesn't have
    the status of Kant's Categorical Imperative.)
    When I had my first AssertEqual(fitst, second interface{}) and it worked,
    I was impressed by Go flexibility and I was sure I've found the Golden Mine
    and that slices (and anything else) were going to work ... Alas!

    Struggling with this, I first though of using reflection but finally ended
    up writing a couple of ContainsZzz() s ... not that bad, after all! (and
    not that elegant, either ;)

    Thanks again,
    Yassen

    --
  • Greg Ward at Nov 26, 2012 at 4:08 pm

    On 21 November 2012, yassen said:
    When I had my first AssertEqual(fitst, second interface{}) and it worked,
    I was impressed by Go flexibility and I was sure I've found the Golden Mine
    and that slices (and anything else) were going to work ... Alas!
    Before you go too far down that road, I recommend you take a look at
    the Testify packages:

    https://github.com/stretchrcom/testify

    In particular, you want their assert package, which is full of yummy
    goodness that lets you type

    assert.Equal(t, a, b)
    assert.Nil(t, err)

    in your tests. Saves a lot of repetitive typing, and the resulting
    test failures are pretty clear.

    Greg

    --
  • Jan Mercl at Nov 26, 2012 at 8:02 pm

    On Mon, Nov 26, 2012 at 5:08 PM, Greg Ward wrote:
    On 21 November 2012, yassen said:
    In particular, you want their assert package, which is full of yummy
    goodness that lets you type

    assert.Equal(t, a, b)
    assert.Nil(t, err)

    in your tests. Saves a lot of repetitive typing, and the resulting
    test failures are pretty clear.
    My personal recommendation is to never use canned asserts.

    -j

    --
  • Chris dollin at Nov 26, 2012 at 8:22 pm

    On 26 November 2012 16:16, Jan Mercl wrote:

    My personal recommendation is to never use canned asserts.
    Care to expand, or possibly expound?

    Chris

    --
    Chris "undecided" Dollin

    --
  • Jan Mercl at Nov 26, 2012 at 8:46 pm

    On Mon, Nov 26, 2012 at 9:16 PM, chris dollin wrote:
    On 26 November 2012 16:16, Jan Mercl wrote:

    My personal recommendation is to never use canned asserts.
    Care to expand, or possibly expound?
    For example:
    https://groups.google.com/d/topic/golang-nuts/6hmxZY8IQNQ/discussion
    https://groups.google.com/d/topic/golang-nuts/JC2Nv7XDGGA/discussion
    https://groups.google.com/d/topic/golang-nuts/a2mCOKhodxI/discussion

    -j

    --
  • André Moraes at Nov 21, 2012 at 7:04 pm

    Any way to "unpack" a []string slice into a scalar sequence of arguments? I
    guess no way, but asking just in case. Thanks!
    If you can change the Contains function to receive a interface{}
    instead of ...interface{}

    package main

    import (
    "fmt"
    "reflect"
    )

    func main() {
    strv := []string{"a", "b", "c"}
    intv := []int{1, 2, 3}
    fmt.Printf("Contains (str): %v\n", Contains("a", strv))
    fmt.Printf("Contains (int): %v\n", Contains(1, intv))
    }

    // This is OK
    func Contains(v interface{}, vals interface{}) bool {
    println("TypeOf vals: ", reflect.TypeOf(vals).String())
    switch vals := vals.(type) {
    case []string:
    for _, item := range vals {
    if v.(string) == item { return true }
    }
    return false
    case []int:
    for _, item := range vals {
    if v.(int) == item { return true }
    }
    return false
    default:
    panic("You can't handle the truth")
    }
    return false
    }




    --
    André Moraes
    http://amoraes.info

    --

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
groupgolang-nuts @
categoriesgo
postedNov 21, '12 at 7:12a
activeNov 26, '12 at 8:46p
posts12
users8
websitegolang.org

People

Translate

site design / logo © 2017 Grokbase