NOTE

1.5 function

What functions are in Go, variadic parameters, multiple return values, named returns, closures, init functions, methods, stacks, and common functions.

GoCreated Updated 1 min readhistorical

This is a historical learning note and may contain outdated or incomplete understanding.

1. What It Is

  • Functions are first-class citizens
  • There are named functions and anonymous functions
  • Binding a function to a struct turns it into a method

2. Usage

2.1. Variadic Parameters

func Print(a ...interface{}) {
	fmt.Println(a...)
}

func TestFunction1(t *testing.T) {
	var a = []interface{}{123, "abc"}

	Print(a...) // 123 abc
	Print(a)    // [123 abc]
}

2.2. Multiple Return Values

Go functions can return multiple values.

func TestFunction2(t *testing.T) {
	fmt.Println(multiRes(0))
	fmt.Println(multiRes(1))

}

func multiRes(val int) (res int, err error) {
	if val == 0 {
		return val * 2, nil
	}

	// If the return parameters are named, they can be returned directly
	return
}

// output
0 <nil>
2 <nil>

2.2.1. Implementation

  • C implementation Allocate space for return values in the calling function, then pass pointers to the return values to the called function.
// calling function
int ret1, ret2;
f(a, b, &ret1, &ret2)
// called function
void f(int arg1, int arg2, int *ret1, int *ret2
  • Go implementation Reserve space for the return values above the input parameters.
func f(arg1, arg2 int) (ret1, ret2 int)

Assembly layout:

space reserved for ret2
space reserved for ret1
parameter 2
parameter 1  <-SP 

2.3. Return Values Can Be Named

func TestFunction3(t *testing.T) {
	fmt.Println(namedRes(1))
}

func namedRes(i int) (res int, err error) {
	res = i * 2
	err = fmt.Errorf("error...")
	return
}
// output
2 error...

2.4. Closures

2.4.1. What They Are

  • An inner function references a variable from an outer function, and after the outer function returns, the inner function can still use that variable. This is called a closure
  • Anonymous function + references a variable in an outer scope = closure function

2.4.2. Usage

2.4.2.1. A closure accesses outer variables by reference
func TestFunction5(t *testing.T) {
	var i int = 10
	func() {
		i++
	}()

	fmt.Println(i)
}
// output
11
2.4.2.2. A closure is evaluated later
func TestFunction6(t *testing.T) {
    for i := 0; i < 3; i++ {
        defer func(){ println(i) } ()
    }
}
// Output:
// 3
// 3
// 3
  • Modification
func TestFunction6(t *testing.T)  {
    for i := 0; i < 3; i++ {
        i := i // Define a local variable i inside the loop body
        defer func(){ println(i) } ()
    }
}

// Or
func TestFunction6(t *testing.T)  {
    for i := 0; i < 3; i++ {
        // Pass i through the function argument
        // The defer statement evaluates call arguments immediately
        defer func(i int){ println(i) } (i)
    }
}

2.5. init Function

  • init1.go
// Executed before init
var aa string = getAa()

func getAa() string {
	fmt.Println("aaaaaaaaaa")
	return "eeeeee"
}

func init() {
	fmt.Println("init")
}
  • function1_test.go
func TestFunction4(t *testing.T) {
	fmt.Println(aa)
}

// output
aaaaaaaaaa
init
eeeeee

2.6. Methods

type Student struct {
	Name string
}

func (s Student) learn() {
	fmt.Println(s.Name + " is learning")
}

func TestMethod(t *testing.T) {
	s := &Student{
		Name: "user",
	}
	s.learn()
}

// output
user is learning

3. Function Stack

  • Go’s stack changes dynamically. Initially it allocates only 4 or 8 KB, and it can grow to the GB level.
  • Before Go 1.4, a linked list was used to implement dynamic stacks; afterward, arrays were used.

4. Common Functions

4.1. print

func testPrint() {
	fmt.Printf("Hello %d\n", 23)              // Used for formatted output
	fmt.Fprint(os.Stdout, "Hello ", 23, "\n") // Used when changing the file descriptor
	fmt.Println("Hello", 23)                  // Used for concatenated output
	s := fmt.Sprint("Hello ", 23)             // Used by String()
	fmt.Println(s)
}

4.2. len vs cap

func Test1(t *testing.T) {
	strings := make([]string, 0, 10)
	fmt.Println(len(strings), cap(strings))

	strings = append(strings, "a")
	fmt.Println(len(strings), cap(strings))
}

// output
0 10
1 10

5. References

Discussion

Sign in with GitHub to comment. Discussions are stored as GitHub Issues.View on GitHub