7

I am just starting with GoLang, and I am looking at one of their tutorials (https://golang.org/doc/code.html).

In one of their examples, they set a variable to a struct, but I am so confused as to how they are accessing elements of the struct in the for loop below? Any chance someone can clarify? Thanks alot!

Code:

package stringutil

import "testing"

func TestReverse(t *testing.T) {
    cases := []struct {
        in, want string
    }{
        {"Hello, world", "dlrow ,olleH"},
        {"Hello, 世界", "界世 ,olleH"},
        {"", ""},
    }
    for _, c := range cases {
        got := Reverse(c.in)
        if got != c.want {
            t.Errorf("Reverse(%q) == %q, want %q", c.in, got, c.want)
        }
    }
}
1
  • They're not setting the variable to a struct, they're setting it to a slice of structs. Commented Dec 19, 2015 at 17:06

2 Answers 2

9

Below is the code with some comments to help clarify each statements role in this.

import "testing"

func TestReverse(t *testing.T) {
    cases := []struct { // declaration of anonymous type
        in, want string // fields on that type called in and want, both strings
    }{
        {"Hello, world", "dlrow ,olleH"},
        {"Hello, 世界", "界世 ,olleH"},
        {"", ""},
    } // composite literal initilization
    // note the use of := in assigning to cases, that op combines declaration and assignment into one statement
    for _, c := range cases { // range over cases, ignoring the index - the underscore means to discard that return value
        got := Reverse(c.in) // c is the current instance, access in with the familiar dot notation
        if got != c.want { // again, access operator on c, the current instance
            t.Errorf("Reverse(%q) == %q, want %q", c.in, got, c.want) // more access
        }
    }
}

Let me know if that helps. I can try giving more of a summary in spoken language or add more details if some of the statements don't make sense still. Also, fyi if you're not familiar range 'ranges' over a collection, returning k, v where k is the index or key and v the value.

EDIT: details on the declaration/initilization of cases

    cases := []struct {
        in, want string
    }

This bit inside the first pair of curly braces is the definition of a struct. This is an anonymous type, a normal declaration would look like this;

    type case struct {
        in string
        want string
    }

If you had something like this then there would be a type called case in the scope of this package (not exported, if you wanted to make it 'public' so it would need to be type Case instead). Instead the examples struct is anonymous. It works the same as normal type, however as a developer, you will have no way to reference that type so you can only practically work with the collection initialized here. Internally this type is the same as any other struct with 2 unexported strings for fields. The fields are named in and want. Notice that in the assignment here cases := []struct you have [] before struct this means you're declaring a slice of this anonymous type.

This next little bit, is called static initialization. This is a syntax for initializing collections as types. Each of these nested bits like {"", ""} is the declaration and initilization of one of these anonymous structs, denoted again by the curly braces. In this case you're assigning two empty strings to in and want respectively (if you don't use names, the order is the same as in the definition). The outer pair of braces is for the slice. If your slice were of say int's or string's, then you would just have the values right there without the extra level of nesting like myInts := []int{5,6,7}.

    {
        {"Hello, world", "dlrow ,olleH"},
        {"Hello, 世界", "界世 ,olleH"},
        {"", ""},
    }
Sign up to request clarification or add additional context in comments.

6 Comments

How is the code able to access the strings in the struct via c.in and c.out?
@thegreenfrog the loop is iterating the slice of structs, there are 3 of them. Each of these lines {"Hello, world", "dlrow ,olleH"} is instantiating one. for _, c := range cases is more or less a foreach loop I would read it as "for each case c in cases". . is commonly called the access operator (not sure if Go has a specific name different than that), you use it to access properties on a struct. If I have some struct A with some fields One, Two, and Three, I access those fields from an instance of type A call it a like a.One, a.Two, a.Three.
I can expand on that in the answer if you need further clarification. If use of the access operator is not familiar to you I would recommend doing some general reading on object oriented programming because it is used in nearly every language.
Ok so in and want are essentially variables for us to access the two elements in each slice?
@thegreenfrog I'll update on that in the answer. The declaration in this example combines several different concepts so it will be more clear if I break out the code.
|
1

Go root of what is a struct.

you declare your variables in it so then you can use it from a function. Example:

package main

import (
    "fmt"

)

func main() {
    Get()

}

func Get(){
    out := new(Var)

    out.name = "james"

    fmt.Println(out.name)
}
type Var struct {
    name string
}

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.