SoFunction
Updated on 2025-03-04

Golang Assertions and Closure Usage Analysis

1. Use of Go assertions

Assertions in Go are used to judge the type of a variable, and their usage is as follows:

value, ok := x.(T)

The above code is to determine whether x is a variable of type T:

  • If a specific type of T is, the assertion will check whether x is the type. If so, buy it and return x and a boolean value.true, otherwise return onefalse
  • If T is an interface type, the type assertion checks whether the dynamic type of x satisfies T. If the check is successful, the return value is an interface value of type T and a Boolean valuetrue, otherwise return onefalse
  • We can also not accept the returned boolean value, in this case, if the assertion fails, it will be directlypanic, so this method is not recommended

Also, assertions and can be used with switch

    switch a.(type) {
        case int:
        ("the type of a is int")
        case string:
        ("the type of a is string")
        case float64:
        ("the type of a is float")
        default:
        ("unknown type")
    }

2. Interpretation of closures

ClosureIs it fromfunctionand references related to itenvironmentCombined entity.

It is a bit abstract in concept, so let's understand it with a concrete example below.

func foo1(x int) func() {
  return func() {
    x = x + 1
    ("foo2 val = %d\n", x)
  }
}

f1 := foo1(1)
f1() // 2
f1() // 3

In the above example, f1() and its variable x (value 1) form a closure. Each time f1() is called, the value of x will +1 and be printed.

In a sense, closures extend the life cycle of variables (the stack allocation is changed to the heap allocation).

2.1 Pointer Passing

func foo2(x *int) func() {
  return func() {
    *x = *x + 1
    ("foo2 val = %d\n", *x)
  }
}

x := 1
f1 := foo2(&x)
f2 := foo2(&x)
f1() // 2
f2() // 3

Through the first example, we know that a function and its environment (the passed in variable) form a closure. At this time, if the passed in is a pointer, then there will be a situation where multiple closures share a variable.

2.2 Delayed binding

Delay binding of closures, in layman's terms, is that the closure function will be bound to the environment variables when it is called for the first time. We still use the two functions mentioned above as examples:

func foo1(x int) func() {
  return func() {
    x = x + 1
    ("foo2 val = %d\n", x)
  }
}

func foo2(x *int) func() {
  return func() {
    *x = *x + 1
    ("foo2 val = %d\n", *x)
  }
}

x := 1
f1 := foo1(x)
f2 := foo2(&x)
f2() // 2
f1() // 3
  • We have created two closure functions f1 and f2, and the value of the variable x is 1
  • When f1 and f2 are created, the variable is not bound to the function
  • When f2() is called for the first time, &x is bound to it, the value of x +1 becomes 2
  • When f1() is called for the first time, x is bound to it. At this time, x has become 2, and +1, so it becomes 3.

2.3 Delayed binding of Go Routine

We start Go Routine in one function and call another function:

func show(v interface{}) {
    ("foo4 val = %v\n", v)
}
func foo4() {
    values := []int{1, 2, 3, 5}
    for _, val := range values {
        go show(val)
    }
}
​
foo4()
//foo3 val = 2
//foo3 val = 3
//foo3 val = 1
//foo3 val = 5

Because the execution order of Go Routine is randomly parallel, it is executed multiple timesfoo4()The output order is different, but the elements "1, 2, 3, 5" must be printed.

However, if we try to reproduce the above logic in the form of anonymous functions, we will find:

func foo5() {
    values := []int{1, 2, 3, 5}
    for _, val := range values {
        go func() {
            ("foo5 val = %v\n", val)
        }()
    }
}

foo5()
//foo3 val = 5
//foo3 val = 5
//foo3 val = 5
//foo3 val = 5

In fact, the essence of this problem is the sameDelayed binding of closures, or in other words, the object of this anonymous function isClosure. In our callgo func() { xxx }()When it is not really started executing this code, it is just a function declaration. When this anonymous function is executed, it is the time for internal variables to find the real assignment. The traversal of for-loop is almost completed "instantaneously", and the 4 Go Routines are actually executed afterwards, so the above situation will occur.

This is the end of this article about Golang assertions and closure usage analysis. For more related Go assertions and closure content, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!