BuBu

Zwj`Blog

My decentralized blog
github
email

Go

Go#

Basics#

Command Line Argument Parsing#

package main

import (
   // Code to be added here.[1]
   "flag"
   "fmt"
)

var name string

func init() {
   // Code to be added here.[2]
   flag.StringVar(&name, "name", "everyone", "The greeting object.")
}

func main() {
   // Code to be added here.[3]
   flag.Parse()
   fmt.Printf("Hello, %s!\n", name)
}

Execution

go run main.go -name="Robert"

Output

Hello, Robert!

Variables#

Definition#

// Variable declaration
var a int = 10

Short Declaration#

// Short declaration
b := 20
fmt.Println(a, b)

Multiple Assignment#

// Multiple assignment
c, d, e := 30, 40, 50
fmt.Println(c, d, e)

Swap Variable Values#

// Swap variable values
f, g := 99, 88
fmt.Println(f, g) // 99 88
f, g = g, f
fmt.Println(f, g) // 88 99

Ignore Values with Underscore#

// Ignore values/return values
h, _ := 10, 20
fmt.Println(h)

Formatted Output#

// Formatted output
fmt.Printf("%d\n", 1)         // %d 1 outputs as integer
fmt.Printf("%f\n", 1.1)       // %f 1.100000 outputs as float
fmt.Printf("%.2f\n", 1.11111) // %.2f 1.11 outputs as float, keeping 2 decimal places
fmt.Printf("%t\n", false)     // %t false outputs as boolean
fmt.Printf("%s\n", "false")   // %s false outputs as string
fmt.Printf("%c\n", 'a')       // %c 'a' outputs as character
fmt.Printf("%p\n", &a)        // %p 0x1400012c008 outputs address as pointer
fmt.Printf("%T\n", a)         // %T outputs the type of the variable

Get Input#

// Get user input
fmt.Scan(&a)   // Input 88
fmt.Println(a) // Output 88

Characters and Bytes#

var n byte = 'a' // byte can only store a single character
var m rune = '' // rune is equivalent to char in other languages, stores a single Unicode character/Chinese etc.
fmt.Println(n, m)

Constants#

Definition#

Constants store data that will not change.

// Constant definition
const a = false

iota Enumeration#

Constant declarations can use the iota constant generator for initialization, which is used to generate a set of constants initialized with similar rules, but without writing the initialization expression on each line. Note: In a const declaration statement, on the line where the first declared constant is located, iota will be set to 0, and then incremented by one on each line with a constant declaration.

const (
   b = iota
   c = iota
   d = iota
)
fmt.Println(b, c, d) // 0 1 2

const (
   f = iota
   g
   h
)
fmt.Println(f, g, h) // 0 1 2

If the constants are written on the same line with the same value, changing to a new line will increment.

const (
   i    = iota
   j, k = iota, iota
)
fmt.Println(i, j, k) // 0 1 1

Operators#

Arithmetic Operators#

OperatorDescription
+Addition
-Subtraction
*Multiplication
/Division
%Modulus

Note: ++ (increment) and -- (decrement) are separate statements in Go, not operators.

Relational Operators#

OperatorDescription
==Checks if two values are equal, returns True if equal, otherwise returns False.
!=Checks if two values are not equal, returns True if not equal, otherwise returns False.
>Checks if the left value is greater than the right value, returns True if so, otherwise returns False.
>=Checks if the left value is greater than or equal to the right value, returns True if so, otherwise returns False.
<Checks if the left value is less than the right value, returns True if so, otherwise returns False.
<=Checks if the left value is less than or equal to the right value, returns True if so, otherwise returns False.

Logical Operators#

OperatorDescription
&&Logical AND operator. True if both operands are True, otherwise False.
!Logical NOT operator. True if condition is True, otherwise False.

Bitwise Operators#

Bitwise operators operate on the binary bits of integers in memory.

OperatorDescription
&Bitwise AND. (1 only if both bits are 1)
^Bitwise XOR. (1 if bits are different)
<<Left shift n bits, equivalent to multiplying by 2^n. “a<<b” shifts all bits of a left by b bits, discarding high bits and filling low bits with 0.
>>Right shift n bits, equivalent to dividing by 2^n. “a>>b” shifts all bits of a right by b bits.

Assignment Operators#

OperatorDescription
=Simple assignment operator, assigns the value of an expression to a left value.
+=Assign after addition.
-=Assign after subtraction.
*=Assign after multiplication.
/=Assign after division.
%=Assign after modulus.
<<=Assign after left shift.
>>=Assign after right shift.
&=Assign after bitwise AND.
=
^=Assign after bitwise XOR.

Type Conversion#

// Type conversion
c := 3
d := float64(c)
fmt.Println(c, d)

Control Flow#

If Statement (Go does not support ternary)#

• Parentheses around the condition expression can be omitted.
• With initialization statement, can define local variables in the code block.
• The left brace must be at the end of the condition expression.

if booleanExpression {
  /* Execute when boolean expression is true */
} 

You can declare variables in the expression.

x := 0
if n := "abc"; x > 0 { // The initialization statement does not have to be a variable definition, println("init") is also acceptable.
   println(n[2])
} else if x < 0 { // Note the position of the left brace for else if and else.
   println(n[1])
} else {
   println(n[0])
}

Switch Statement#

Syntax#

Go defaults to having Break, if Break is not needed, you can use the fallthrough keyword.

switch var1 {
    case val1:
        ...
    case val2:
        ...
    default:
        ...
}

The variable var1 can be of any type, while val1 and val2 can be any values of the same type. The type is not limited to constants or integers, but must be of the same type; or the final result is an expression of the same type. You can test multiple possible values that meet the conditions, separated by commas, for example: case val1, val2, val3.

package main

import "fmt"

func main() {
   /* Define local variable */
   var grade string = "B"
   var marks int = 90

   switch marks {
      case 90: grade = "A"
      case 80: grade = "B"
      case 50,60,70 : grade = "C"
      default: grade = "D"  
   }

   switch {
      case grade == "A" :
         fmt.Printf("Excellent!\n" )     
      case grade == "B", grade == "C" :
         fmt.Printf("Good\n" )      
      case grade == "D" :
         fmt.Printf("Pass\n" )      
      case grade == "F":
         fmt.Printf("Fail\n" )
      default:
         fmt.Printf("Poor\n" )
   }
   fmt.Printf("Your grade is %s\n", grade )
}    

The execution result of the above code is:

Excellent!
Your grade is A  
Type Switch#
switch x.(type){
    case type:
       statement(s)      
    case type:
       statement(s)
    /* You can define any number of cases */
    default: /* Optional */
       statement(s)
}  
Example#
package main

import "fmt"

func main() {
    var x interface{}
    // Method 1:
    switch i := x.(type) { // With initialization statement
    case nil:
        fmt.Printf(" x's type :%T\r\n", i)
    case int:
        fmt.Printf("x is int type")
    case float64:
        fmt.Printf("x is float64 type")
    case func(int) float64:
        fmt.Printf("x is func(int) type")
    case bool, string:
        fmt.Printf("x is bool or string type")
    default:
        fmt.Printf("Unknown type")
    }
    // Method 2
    var j = 0
    switch j {
    case 0:
    case 1:
        fmt.Println("1")
    case 2:
        fmt.Println("2")
    default:
        fmt.Println("def")
    }
    // Method 3
    var k = 0
    switch k {
    case 0:
        println("fallthrough")
        fallthrough
        /*
            Go's switch is very flexible, the expression does not have to be a constant or integer, the execution process goes from top to bottom until a match is found;
            and if the switch has no expression, it will match true.
            In Go, switch is equivalent to each case having a break at the end,
            after a successful match, it will not automatically execute other cases below, but jump out of the entire switch,
            but you can use fallthrough to force the execution of the following case code.
        */
    case 1:
        fmt.Println("1")
    case 2:
        fmt.Println("2")
    default:
        fmt.Println("def")
    }
    // Method 4
    var m = 0
    switch { // Omit condition expression, can be treated as if...else if...else
    case m > 0 && m < 10:
        fmt.Println("i > 0 and i < 10")
    case m > 10 && m < 20:
        fmt.Println("i > 10 and i < 20")
    default:
        fmt.Println("def")
    }
}   

The execution result of the above code is:

    x's type :<nil>
    fallthrough
    1
    1
    def

For Statement#

The for loop is a loop control structure that can execute a specified number of loops.

Syntax#

Go's for loop has three forms, only one of which uses a semicolon.

    for init; condition; post { }
    for condition { }
    for { }
    init: Generally an assignment expression, assigning an initial value to the control variable;
    condition: A relational expression or logical expression, the loop control condition;
    post: Generally an assignment expression, incrementing or decrementing the control variable.
    The execution process of the for statement is as follows:
    ① First assign the initial value to the expression init;
    ② Determine whether the assignment expression init meets the given condition condition, if its value is true, satisfying the loop condition, then execute the statements in the loop body, then execute post, enter the second loop, and determine condition again; otherwise, if the value of condition is false, it does not satisfy the condition, the for loop terminates, and the statements outside the loop body are executed.   
s := "abc"

for i, n := 0, len(s); i < n; i++ { // A common for loop, supports initialization statements.
    println(s[i])
}

n := len(s)
for n > 0 {                // Replace while (n > 0) {}
    n-- 
    println(s[n])        // Replace for (; n > 0;) {}
}

for {                    // Replace while (true) {}
    println(s)            // Replace for (;;) {}
}  

Do not expect the compiler to understand your thoughts; it is a good idea to calculate all results in the initialization statement.

package main

func length(s string) int {
    println("call length.")
    return len(s)
}

func main() {
    s := "abcd"

    for i, n := 0, length(s); i < n; i++ {     // Avoid multiple calls to the length function.
        println(i, s[i])
    } 
}  

Output:

    call length.
    0 97
    1 98
    2 99
    3 100 
Example#
package main

import "fmt"

func main() {

   var b int = 15
   var a int

   numbers := [6]int{1, 2, 3, 5}

   /* for loop */
   for a := 0; a < 10; a++ {
      fmt.Printf("a's value is: %d\n", a)
   }

   for a < b {
      a++
      fmt.Printf("a's value is: %d\n", a)
      }

   for i,x:= range numbers {
      fmt.Printf("The %d position x's value = %d\n", i,x)
   }   
} 

The output of the above example is:

    a's value is: 0
    a's value is: 1
    a's value is: 2
    a's value is: 3
    a's value is: 4
    a's value is: 5
    a's value is: 6
    a's value is: 7
    a's value is: 8
    a's value is: 9
    a's value is: 1
    a's value is: 2
    a's value is: 3
    a's value is: 4
    a's value is: 5
    a's value is: 6
    a's value is: 7
    a's value is: 8
    a's value is: 9
    a's value is: 10
    a's value is: 11
    a's value is: 12
    a's value is: 13
    a's value is: 14
    a's value is: 15
    The 0 position x's value = 1
    The 1 position x's value = 2
    The 2 position x's value = 3
    The 3 position x's value = 5
    The 4 position x's value = 0
    The 5 position x's value = 0  
Nested Loops#

A for loop can nest one or more for loops.

Syntax

The following is the format of nested loops in Go:

for [condition |  ( init; condition; increment ) | Range]
{
   for [condition |  ( init; condition; increment ) | Range]
   {
      statement(s)
   }
   statement(s)
}  
Example

The following example uses nested loops to output prime numbers between 2 and 100:

package main

import "fmt"

func main() {
   /* Define local variables */
   var i, j int

   for i=2; i < 100; i++ {
      for j=2; j <= (i/j); j++ {
         if(i%j==0) {
            break // If a factor is found, it is not a prime number
         }
      }
      if(j > (i/j)) {
         fmt.Printf("%d  is a prime number\n", i)
      }
   }  
}  

The output of the above example is:

    2  is a prime number
    3  is a prime number
    5  is a prime number
    7  is a prime number
    11  is a prime number
    13  is a prime number
    17  is a prime number
    19  is a prime number
    23  is a prime number
    29  is a prime number
    31  is a prime number
    37  is a prime number
    41  is a prime number
    43  is a prime number
    47  is a prime number
    53  is a prime number
    59  is a prime number
    61  is a prime number
    67  is a prime number
    71  is a prime number
    73  is a prime number
    79  is a prime number
    83  is a prime number
    89  is a prime number
    97  is a prime number  
Infinite Loops#

If the condition statement in the loop is never false, it will result in an infinite loop. We can execute an infinite loop in the for loop statement by only setting a condition expression:

package main

import "fmt"

func main() {
    for true  {
        fmt.Printf("This is an infinite loop.\n");
    }
}  

Range Statement#

Syntax#

Golang range is similar to iterator operations, returning (index, value) or (key, value).

The range format of the for loop can iterate over slices, maps, arrays, strings, etc. The format is as follows:

for key, value := range oldMap {
    newMap[key] = value
}   
1st value2nd value
stringindexs[index]unicode, rune
array/sliceindexs[index]
mapkeym[key]
channelelement

You can ignore unwanted return values, or use the special variable "_" for that.

package main

func main() {
    s := "abc"
    // Ignore 2nd value, supports string/array/slice/map.
    for i := range s {
        println(s[i])
    }
    // Ignore index.
    for _, c := range s {
        println(c)
    }
    // Ignore all return values, just iterate.
    for range s {

    }

    m := map[string]int{"a": 1, "b": 2}
    // Return (key, value).
    for k, v := range m {
        println(k, v)
    }
}   

Output:

    97
    98
    99
    97
    98
    99
    a 1
    b 2  
Important Note#

* Note that range will copy objects.

package main

import "fmt"

func main() {
    a := [3]int{0, 1, 2}

    for i, v := range a { // index and value are taken from copies.

        if i == 0 { // Before modifying, we first modify the original array.
            a[1], a[2] = 999, 999
            fmt.Println(a) // Confirm modification is effective, output [0, 999, 999].
        }

        a[i] = v + 100 // Modify the original array using the value taken from the copy.

    }

    fmt.Println(a) // Output [100, 101, 102].  
}   

Output:

    [0 999 999]
    [100 101 102]   

It is recommended to use reference types, as their underlying data will not be copied.

package main

func main() {
    s := []int{1, 2, 3, 4, 5}

    for i, v := range s { // Copy struct slice { pointer, len, cap }.

        if i == 0 {
            s = s[:3]  // Modifying the slice will not affect range.
            s[2] = 100 // Modifying the underlying data.
        }

        println(i, v)
    }
}   

Output:

    0 1
    1 2
    2 100
    3 4
    4 5

The other two reference types, map and channel, are pointer wrappers, unlike slices which are structs.

Difference Between for and range#

The main difference is in the usage scenarios.

for can iterate over arrays and slices || iterate over maps with integer keys incrementing || iterate over strings.

for range can accomplish everything for can do, but can also do things that for cannot do, including:

Iterate over maps with string type keys while simultaneously getting both key and value || iterate over channels.

Functions#

Definition#

Function Characteristics#
    • No need to declare a prototype.
    • Supports variable parameters.
    • Supports multiple return values.
    • Supports named return parameters. 
    • Supports anonymous functions and closures.
    • Functions are also a type, a function can be assigned to a variable.

    • Does not support nested functions (a package cannot have two functions with the same name).
    • Does not support overloading.
    • Does not support default parameters. 
Function Declaration#

A function declaration includes a function name, parameter list, return value list, and function body. If a function has no return value, the return list can be omitted. The function starts executing from the first statement until it executes the return statement or the last statement of the function.

A function can have no parameters or accept multiple parameters.

Note that the type comes after the variable name.

When two or more consecutive function named parameters are of the same type, all but the last type can be omitted.

A function can return any number of return values.

Use the keyword func to define a function, and the left brace cannot start on a new line.

func test(x, y int, s string) (int, string) {
    // Parameters of the same type can be merged. Multiple return values must use parentheses.
    n := x + y          
    return n, fmt.Sprintf(s, n)
}

Functions are first-class objects, and can be passed as parameters. It is recommended to define complex signatures as function types for better readability.

package main

import "fmt"

func test(fn func() int) int {
    return fn()
}
// Define function type.
type FormatFunc func(s string, x, y int) string 

func format(fn FormatFunc, s string, x, y int) string {
    return fn(s, x, y)
}

func main() {
    s1 := test(func() int { return 100 }) // Directly passing an anonymous function as a parameter.

    s2 := format(func(s string, x, y int) string {
        return fmt.Sprintf(s, x, y)
    }, "%d, %d", 10, 20)

    println(s1, s2)
}

Output:

    100 10, 20

A function with return values must have a clear termination statement; otherwise, it will raise a compilation error.

Parameters#

Regular Parameters#

When a function is defined with parameters, those variables can be called formal parameters of the function. Formal parameters are like local variables defined within the function body.

However, when calling the function, the variables passed in are called actual parameters, and the function can pass parameters in two ways:

Value Passing

This means that when calling the function, an actual parameter is copied and passed into the function, so if the parameter is modified in the function, it will not affect the actual parameter.

func swap(x, y int) int {
       ... ...
  }
Reference Passing

This means that when calling the function, the address of the actual parameter is passed into the function, so any modifications to the parameter in the function will affect the actual parameter.

package main

import (
    "fmt"
)

/* Define a function to swap values */
func swap(x, y *int) {
    var temp int

    temp = *x /* Save the value of x */
    *x = *y   /* Assign the value of y to x */
    *y = temp /* Assign the temp value to y*/

}

func main() {
    var a, b int = 1, 2
    /*
        Call swap() function
        &a points to a pointer, the address of variable a
        &b points to b pointer, the address of variable b
    */
    swap(&a, &b)

    fmt.Println(a, b)
}

Output:

    2 1

By default, Go uses value passing, meaning that during the call, it does not affect the actual parameters.

Note 1

Whether by value passing or reference passing, what is passed to the function is a copy of the variable, but value passing is a copy of the value. Reference passing is a copy of the address, and generally speaking, address copying is more efficient. Value copying depends on the size of the copied object; the larger the object, the lower the performance.

Note 2

Maps, slices, channels, pointers, and interfaces are passed by reference by default.

Variable Parameters#

Variable parameters mean that the function's parameters are not fixed, and the type behind is fixed. (Variable parameters)

Golang's variable parameters are essentially slices. There can only be one, and it must be the last one.

When assigning parameters, you can pass an array or slice directly without assigning them one by one, and it is especially important to add "..." after the parameters.

func main() {
   // Variable parameter function
   test(1, 2, 3, 4)// [1 2 3 4]
}

func test(args ...int) {
   fmt.Println(args)
}
Method to Pass Slice to Variable Parameters

When using a slice object as a variable parameter, it must be expanded. slice...

package main

import (
    "fmt"
)

func test(s string, n ...int) string {
    var x int
    for _, i := range n {
        x += i
    }

    return fmt.Sprintf(s, x)
}

func main() {
    s := []int{1, 2, 3}
    res := test("sum: %d", s...)    // slice... expand slice
    println(res)
}

Return Values#

The identifier "_" is used to ignore a certain return value of a function.

Go's return values can be named, and can be used just like variables declared at the beginning of the function body.

The names of return values should have some meaning and can be used as documentation.

A return statement with no parameters returns the current values of each return variable. This usage is called "naked" return.

Direct return statements should only be used in short functions like the one below. In longer functions, they will affect the readability of the code.

package main

import (
    "fmt"
)

func add(a, b int) (c int) {
    c = a + b
    return
}

func calc(a, b int) (sum int, avg int) {
    sum = a + b
    avg = (a + b) / 2

    return
}

func main() {
    var a, b int = 1, 2
    c := add(a, b)
    sum, avg := calc(a, b)
    fmt.Println(a, b, c, sum, avg)
}

Output:

    1 2 3 3 1 

Golang return values cannot be received using container objects. They can only be received using multiple variables or ignored with "_".

package main

func test() (int, int) {
    return 1, 2
}

func main() {
    // s := make([]int, 2)
    // s = test()   // Error: multiple-value test() in single-value context

    x, _ := test()
    println(x)
}

Output:

    1 

Multiple return values can be directly used as actual parameters for other function calls.

package main

func test() (int, int) {
    return 1, 2
}

func add(x, y int) int {
    return x + y
}

func sum(n ...int) int {
    var x int
    for _, i := range n {
        x += i
    }

    return x
}

func main() {
    println(add(test()))
    println(sum(test()))
}

Output:

    3
    3

Named return parameters can be seen as local variables similar to formal parameters, and are implicitly returned by the last return statement.

package main

func add(x, y int) (z int) {
    z = x + y
    return
}

func main() {
    println(add(1, 2))
}

Output:

    3  

Named return parameters can be shadowed by local variables with the same name, in which case an explicit return is required.

func add(x, y int) (z int) {
    { // Cannot be at the same level, causing "z redeclared in this block" error.
        var z = x + y
        // return   // Error: z is shadowed during return
        return z // Must return explicitly.
    }
}

Named return parameters allow deferred calls to read and modify through closures.

package main

func add(x, y int) (z int) {
    defer func() {
        z += 100
    }()

    z = x + y
    return
}

func main() {
    println(add(1, 2)) 
}

Output:

    103

Explicit return before returning will first modify the named return parameter.

package main

func add(x, y int) (z int) {
    defer func() {
        println(z) // Output: 203
    }()

    z = x + y
    return z + 200 // Execution order: (z = z + 200) -> (call defer) -> (return)
}

func main() {
    println(add(1, 2)) // Output: 203
}

Output:

    203
    203

Anonymous Functions#

Anonymous functions are functions that do not require a function name. LISP first adopted anonymous functions in 1958.

In Go, functions can be defined in code like ordinary variables, and Go supports defining anonymous functions at any time in the code.

Anonymous functions consist of a function declaration without a function name and a function body. The advantage of anonymous functions is that they can directly use variables within the function without declaring them.

package main

import (
    "fmt"
    "math"
)

func main() {
    getSqrt := func(a float64) float64 {
        return math.Sqrt(a)
    }
    fmt.Println(getSqrt(4))
}

Output:

 2
Closures#

Because functions are destroyed after they are called, the variable values inside the function are not saved.

func test1(a int) {
   a++
   fmt.Println(a)
}
func main() {
   a := 1
   for i := 0; i < 10; i++ {
      test1(a)
   }
}

Output

2
2
2
2
2
2
2
2
2
2

The return value is also a function, which is called a closure.

You can achieve persistence of functions in the stack area through anonymous functions and closures.

func main(){
  a := 1
  f := test2(a)
  for i := 0; i < 10; i++ {
     fmt.Println(f())
  }
}
func test2(a int) func() int {
   return func() int {
      return a
   }
}

Output result

2
3
4
5
6
7
8
9
10
11

Recursive Functions#

Recursion is when a function calls itself during execution. A function that calls itself is called a recursive function.

Conditions for recursion:

    1. The subproblem must be the same as the original problem, but simpler.
    2. It cannot call itself indefinitely; it must have an exit point to simplify to a non-recursive situation.
Factorial#
package main

import "fmt"

func factorial(i int) int {
    if i <= 1 {
        return 1
    }
    return i * factorial(i-1)
}

func main() {
    var i int = 7
    fmt.Printf("Factorial of %d is %d\n", i, factorial(i))
}

Output:

    Factorial of 7 is 5040
Fibonacci Sequence#

This sequence starts from the third term, where each term equals the sum of the previous two terms.

package main

import "fmt"

func fibonaci(i int) int {
    if i == 0 {
        return 0
    }
    if i == 1 {
        return 1
    }
    return fibonaci(i-1) + fibonaci(i-2)
}

func main() {
    var i int
    for i = 0; i < 10; i++ {
        fmt.Printf("%d\n", fibonaci(i))
    }
}

Output:

    0
    1
    1
    2
    3
    5
    8
    13
    21
    34

Defer Delayed Calls#

Defer Characteristics#
    1. The defer keyword is used to register delayed calls.
    2. These calls are executed just before return. Therefore, they can be used for resource cleanup.
    3. Multiple defer statements are executed in a last-in-first-out order.
    4. The variables in the defer statement are determined at the time of the defer declaration.
Defer Usage#
    1. Close file handles
    2. Release resource locks
    3. Release database connections

Defer is last-in-first-out.

package main

import "fmt"

func main() {
    var whatever [5]struct{}

    for i := range whatever {
        defer fmt.Println(i)
    }
} 

Output:

    4
    3
    2
    1
    0
Defer and Closures#

image-20220416190037239

Defer will delay the execution of the function; although the anonymous function is called immediately, it will not execute until the entire main() function ends.

image-20220416190056827

Since the anonymous function is prefixed with defer, it will not execute immediately. However, the problem is that the program starts executing from the top, and when it reaches the anonymous function, although it does not execute immediately, the parameter passing is already completed.

Defer and Exceptions#

Multiple deferred registrations are executed in a FILO order (first in, last out). Even if a function or a delayed call encounters an error, these calls will still be executed.

package main

func test(x int) {
    defer println("a")
    defer println("b")

    defer func() {
        println(100 / x) // div0 exception not caught, gradually passed out, ultimately terminating the process.
    }()

    defer println("c")
}

func main() {
    test(0)
} 

Output:

    c
    b
    a
    panic: runtime error: integer divide by zero
Important#

* Note that the parameters in the deferred call are evaluated or copied at the time of registration; you can use pointers or closures to "defer" read.

package main

func test() {
    x, y := 10, 20

    defer func(i int) {
        println("defer:", i, y) // y closure reference
    }(x) // x is copied <<<<<------ here the closure passes the parameter in

    x += 10
    y += 100
    println("x =", x, "y =", y)
}

func main() {
    test()
}  

Output:

    x = 20 y = 120
    defer: 10 120
Misuse of Defer#

* Misusing defer may lead to performance issues, especially in a "large loop".

package main

import (
    "fmt"
    "sync"
    "time"
)

var lock sync.Mutex

func test() {
    lock.Lock()
    lock.Unlock()
}

func testdefer() {
    lock.Lock()
    defer lock.Unlock()
}

func main() {
    func() {
        t1 := time.Now()

        for i := 0; i < 10000; i++ {
            test()
        }
        elapsed := time.Since(t1)
        fmt.Println("test elapsed: ", elapsed)
    }()
    func() {
        t1 := time.Now()

        for i := 0; i < 10000; i++ {
            testdefer()
        }
        elapsed := time.Since(t1)
        fmt.Println("testdefer elapsed: ", elapsed)
    }()

}

Output:

    test elapsed:  223.162µs
    testdefer elapsed:  781.304µs
Defer Traps#
Defer and Closure
package main

import (
    "errors"
    "fmt"
)

func foo(a, b int) (i int, err error) {
    defer fmt.Printf("first defer err %v\n", err)
    defer func(err error) { fmt.Printf("second defer err %v\n", err) }(err)
    defer func() { fmt.Printf("third defer err %v\n", err) }()
    if b == 0 {
        err = errors.New("divided by zero!")
        return
    }

    i = a / b
    return
}

func main() {
    foo(2, 0)
}  

Output:

    third defer err divided by zero!
    second defer err <nil>
    first defer err <nil>

Explanation: If the defer following is not a closure, the last execution will not yield the latest value.

Defer and Return
package main

import "fmt"

func foo() (i int) {

    i = 0
    defer func() {
        fmt.Println(i)
    }()

    return 2
}

func main() {
    foo()
}

Output:

    2

Explanation: In a function with named return values (here the named return value is i), when executing return 2, i's value is actually reassigned to 2. So the defer closure outputs the result as 2 instead of 1.

Defer Nil Function
package main

import (
    "fmt"
)

func test() {
    var run func() = nil
    defer run()
    fmt.Println("runs")
}

func main() {
    defer func() {
        if err := recover(); err != nil {
            fmt.Println(err)
        }
    }()
    test()
} 

Output:

runs
runtime error: invalid memory address or nil pointer dereference

Explanation: The function named test runs to completion, then the defer function will be executed and panic due to the value being nil. However, it is worth noting that the declaration of run() is fine because it will only be called after the test function runs to completion.

Arrays#

    1. Arrays: A fixed-length sequence of the same data type.
    2. Array definition: var a [len]int, for example: var a [5]int, the length of the array must be a constant and is part of the type. Once defined, the length cannot change.
    3. The length is part of the array type, so var a[5] int and var a[10]int are different types.
    4. Arrays can be accessed via subscripts, with subscripts starting from 0, the last element's subscript is: len-1
    for i := 0; i < len(a); i++ {
    }
    for index, v := range a {
    }
    5. Out-of-bounds access will trigger a panic if the subscript is outside the valid range of the array.
    6. Arrays are value types, assignment and parameter passing will copy the entire array, not the pointer. Therefore, changing the value of the copy will not change the value of the original.
    7. Supports "==" and "!=" operators, as memory is always initialized.
    8. Pointer array [n]*T, array pointer *[n]T.

Array Initialization#

One-Dimensional Array#
    Global:
    var arr0 [5]int = [5]int{1, 2, 3}
    var arr1 = [5]int{1, 2, 3, 4, 5}
    var arr2 = [...]int{1, 2, 3, 4, 5, 6}
    var str = [5]string{3: "hello world", 4: "tom"}
    Local:
    a := [3]int{1, 2}           // Uninitialized elements default to 0.
    b := [...]int{1, 2, 3, 4}   // Determine array length by initialization values.
    c := [5]int{2: 100, 4: 200} // Initialize elements using index.
    d := [...]struct {
        name string
        age  uint8
    }{
        {"user1", 10}, // Element type can be omitted.
        {"user2", 20}, // Don't forget the last comma.
    }

Code:

package main

import (
    "fmt"
)

var arr0 [5]int = [5]int{1, 2, 3}
var arr1 = [5]int{1, 2, 3, 4, 5}
var arr2 = [...]int{1, 2, 3, 4, 5, 6}
var str = [5]string{3: "hello world", 4: "tom"}

func main() {
    a := [3]int{1, 2}           // Uninitialized elements default to 0.
    b := [...]int{1, 2, 3, 4}   // Determine array length by initialization values.
    c := [5]int{2: 100, 4: 200} // Initialize elements using index.
    d := [...]struct {
        name string
        age  uint8
    }{
        {"user1", 10}, // Element type can be omitted.
        {"user2", 20}, // Don't forget the last comma.
    }
    fmt.Println(arr0, arr1, arr2, str)
    fmt.Println(a, b, c, d)
}

Output:

[1 2 3 0 0] [1 2 3 4 5] [1 2 3 4 5 6] [   hello world tom]
[1 2 0] [1 2 3 4] [0 0 100 0 200] [{user1 10} {user2 20}]
Multi-Dimensional Array#
    Global
    var arr0 [5][3]int
    var arr1 [2][3]int = [...][3]int{{1, 2, 3}, {7, 8, 9}}
    Local:
    a := [2][3]int{{1, 2, 3}, {4, 5, 6}}
    b := [...][2]int{{1, 1}, {2, 2}, {3, 3}} // The 2nd dimension cannot use "..." .

Code:

package main

import (
    "fmt"
)

var arr0 [5][3]int
var arr1 [2][3]int = [...][3]int{{1, 2, 3}, {7, 8, 9}}

func main() {
    a := [2][3]int{{1, 2, 3}, {4, 5, 6}}
    b := [...][2]int{{1, 1}, {2, 2}, {3, 3}} // The 2nd dimension cannot use "..." .
    fmt.Println(arr0, arr1)
    fmt.Println(a, b)
}

Output:

    [[0 0 0] [0 0 0] [0 0 0] [0 0 0] [0 0 0]] [[1 2 3] [7 8 9]]
    [[1 2 3] [4 5 6]] [[1 1] [2 2] [3 3]]

Value copy behavior can cause performance issues, and it is generally recommended to use slices or array pointers.

package main

import (
    "fmt"
)

func test(x [2]int) {
    fmt.Printf("x: %p\n", &x)
    x[1] = 1000
}

func main() {
    a := [2]int{}
    fmt.Printf("a: %p\n", &a)

    test(a)
    fmt.Println(a)
}

Slices#

Slice is not an array or an array pointer. It references a segment of an array through internal pointers and related properties to achieve a variable-length scheme.

    1. Slice: A slice is a reference type of an array, so slices are reference types. But itself is a struct, value copy passing.
    2. The length of a slice can change, so a slice is a mutable array.
    3. The way to iterate over a slice is the same as that of an array, and you can use len() to get the length. It indicates the number of available elements, and read/write operations cannot exceed this limit. 
    4. Cap can be used to find the maximum expansion capacity of a slice, which cannot exceed the array limit. 0 <= len(slice) <= len(array), where array is the array referenced by the slice.
    5. Slice definition: var variableName []type, for example var str []string var arr []int.
    6. If slice == nil, then both len and cap results are equal to 0.

Slice Creation#

package main

import "fmt"

func main() {
   //1. Declare a slice
   var s1 []int
   if s1 == nil {
      fmt.Println("is empty")
   } else {
      fmt.Println("is not empty")
   }
   // 2.:=
   s2 := []int{}
   // 3.make()
   var s3 []int = make([]int, 0)
   fmt.Println(s1, s2, s3)
   // 4. Initialize assignment
   var s4 []int = make([]int, 0, 0)
   fmt.Println(s4)
   s5 := []int{1, 2, 3}
   fmt.Println(s5)
   // 5. Slice from array
   arr := [5]int{1, 2, 3, 4, 5}
   var s6 []int
   // Front included, back excluded
   s6 = arr[1:4]
   fmt.Println(s6)
}

Slice Initialization#

// Global:
var arr = [...]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
var slice0 []int = arr[start:end]
var slice1 []int = arr[:end]
var slice2 []int = arr[start:]
var slice3 []int = arr[:]
var slice4 = arr[:len(arr)-1] // Remove the last element from the slice
// Local:
arr2 := [...]int{9, 8, 7, 6, 5, 4, 3, 2, 1, 0}
slice5 := arr[start:end]
slice6 := arr[:end]
slice7 := arr[start:]
slice8 := arr[:]
slice9 := arr[:len(arr)-1] // Remove the last element from the slice

img

Code:

package main

import (
    "fmt"
)

var arr = [...]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
var slice0 []int = arr[2:8]
var slice1 []int = arr[0:6]        // Can be simplified as var slice []int = arr[:end]
var slice2 []int = arr[5:10]       // Can be simplified as var slice[]int = arr[start:]
var slice3 []int = arr[0:len(arr)] // var slice []int = arr[:]
var slice4 = arr[:len(arr)-1]      // Remove the last element from the slice
func main() {
    fmt.Printf("Global variable: arr %v\n", arr)
    fmt.Printf("Global variable: slice0 %v\n", slice0)
    fmt.Printf("Global variable: slice1 %v\n", slice1)
    fmt.Printf("Global variable: slice2 %v\n", slice2)
    fmt.Printf("Global variable: slice3 %v\n", slice3)
    fmt.Printf("Global variable: slice4 %v\n", slice4)
    fmt.Printf("-----------------------------------\n")
    arr2 := [...]int{9, 8, 7, 6, 5, 4, 3, 2, 1, 0}
    slice5 := arr[2:8]
    slice6 := arr[0:6]         // Can be simplified as slice := arr[:end]
    slice7 := arr[5:10]        // Can be simplified as slice := arr[start:]
    slice8 := arr[0:len(arr)]  // slice := arr[:]
    slice9 := arr[:len(arr)-1] // Remove the last element from the slice
    fmt.Printf("Local variable: arr2 %v\n", arr2)
    fmt.Printf("Local variable: slice5 %v\n", slice5)
    fmt.Printf("Local variable: slice6 %v\n", slice6)
    fmt.Printf("Local variable: slice7 %v\n", slice7)
    fmt.Printf("Local variable: slice8 %v\n", slice8)
    fmt.Printf("Local variable: slice9 %v\n", slice9)
}

Output:

    Global variable: arr [0 1 2 3 4 5 6 7 8 9]
    Global variable: slice0 [2 3 4 5 6 7]
    Global variable: slice1 [0 1 2 3 4 5]
    Global variable: slice2 [5 6 7 8 9]
    Global variable: slice3 [0 1 2 3 4 5 6 7 8 9]
    Global variable: slice4 [0 1 2 3 4 5 6 7 8]
    -----------------------------------
    Local variable: arr2 [9 8 7 6 5 4 3 2 1 0]
    Local variable: slice5 [2 3 4 5 6 7]
    Local variable: slice6 [0 1 2 3 4 5]
    Local variable: slice7 [5 6 7 8 9]
    Local variable: slice8 [0 1 2 3 4 5 6 7 8 9]
    Local variable: slice9 [0 1 2 3 4 5 6 7 8]

Slices Copy and Pass Parameters#

package main

import "fmt"

func printArr(arr *[5]int) {
    arr[0] = 10
    for i, v := range arr {
        fmt.Println(i, v)
    }
}

func main() {
    var arr1 [5]int
    printArr(&arr1)
    fmt.Println(arr1)
    arr2 := [...]int{2, 4, 6, 8, 10}
    printArr(&arr2)
    fmt.Println(arr2)
}

Slices#

Slice is not an array or an array pointer. It references a segment of an array through internal pointers and related properties to achieve a variable-length scheme.

    1. Slice: A slice is a reference type of an array, so slices are reference types. But itself is a struct, value copy passing.
    2. The length of a slice can change, so a slice is a mutable array.
    3. The way to iterate over a slice is the same as that of an array, and you can use len() to get the length. It indicates the number of available elements, and read/write operations cannot exceed this limit. 
    4. Cap can be used to find the maximum expansion capacity of a slice, which cannot exceed the array limit. 0 <= len(slice) <= len(array), where array is the array referenced by the slice.
    5. Slice definition: var variableName []type, for example var str []string var arr []int.
    6. If slice == nil, then both len and cap results are equal to 0.

Slice Creation#

package main

import "fmt"

func main() {
   //1. Declare a slice
   var s1 []int
   if s1 == nil {
      fmt.Println("is empty")
   } else {
      fmt.Println("is not empty")
   }
   // 2.:=
   s2 := []int{}
   // 3.make()
   var s3 []int = make([]int, 0)
   fmt.Println(s1, s2, s3)
   // 4. Initialize assignment
   var s4 []int = make([]int, 0, 0)
   fmt.Println(s4)
   s5 := []int{1, 2, 3}
   fmt.Println(s5)
   // 5. Slice from array
   arr := [5]int{1, 2, 3, 4, 5}
   var s6 []int
   // Front included, back excluded
   s6 = arr[1:4]
   fmt.Println(s6)
}

Slice Initialization#

// Global:
var arr = [...]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
var slice0 []int = arr[start:end]
var slice1 []int = arr[:end]
var slice2 []int = arr[start:]
var slice3 []int = arr[:]
var slice4 = arr[:len(arr)-1] // Remove the last element from the slice
// Local:
arr2 := [...]int{9, 8, 7, 6, 5, 4, 3, 2, 1, 0}
slice5 := arr[start:end]
slice6 := arr[:end]
slice7 := arr[start:]
slice8 := arr[:]
slice9 := arr[:len(arr)-1] // Remove the last element from the slice

img

Code:

package main

import (
    "fmt"
)

var arr = [...]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
var slice0 []int = arr[2:8]
var slice1 []int = arr[0:6]        // Can be simplified as var slice []int = arr[:end]
var slice2 []int = arr[5:10]       // Can be simplified as var slice[]int = arr[start:]
var slice3 []int = arr[0:len(arr)] // var slice []int = arr[:]
var slice4 = arr[:len(arr)-1]      // Remove the last element from the slice
func main() {
    fmt.Printf("Global variable: arr %v\n", arr)
    fmt.Printf("Global variable: slice0 %v\n", slice0)
    fmt.Printf("Global variable: slice1 %v\n", slice1)
    fmt.Printf("Global variable: slice2 %v\n", slice2)
    fmt.Printf("Global variable: slice3 %v\n", slice3)
    fmt.Printf("Global variable: slice4 %v\n", slice4)
    fmt.Printf("-----------------------------------\n")
    arr2 := [...]int{9, 8, 7, 6, 5, 4, 3, 2, 1, 0}
    slice5 := arr[2:8]
    slice6 := arr[0:6]         // Can be simplified as slice := arr[:end]
    slice7 := arr[5:10]        // Can be simplified as slice := arr[start:]
    slice8 := arr[0:len(arr)]  // slice := arr[:]
    slice9 := arr[:len(arr)-1] // Remove the last element from the slice
    fmt.Printf("Local variable: arr2 %v\n", arr2)
    fmt.Printf("Local variable: slice5 %v\n", slice5)
    fmt.Printf("Local variable: slice6 %v\n", slice6)
    fmt.Printf("Local variable: slice7 %v\n", slice7)
    fmt.Printf("Local variable: slice8 %v\n", slice8)
    fmt.Printf("Local variable: slice9 %v\n", slice9)
}

Output:

    Global variable: arr [0 1 2 3 4 5 6 7 8 9]
    Global variable: slice0 [2 3 4 5 6 7]
    Global variable: slice1 [0 1 2 3 4 5]
    Global variable: slice2 [5 6 7 8 9]
    Global variable: slice3 [0 1 2 3 4 5 6 7 8 9]
    Global variable: slice4 [0 1 2 3 4 5 6 7 8]
    -----------------------------------
    Local variable: arr2 [9 8 7 6 5 4 3 2 1 0]
    Local variable: slice5 [2 3 4 5 6 7]
    Local variable: slice6 [0 1 2 3 4 5]
    Local variable: slice7 [5 6 7 8 9]
    Local variable: slice8 [0 1 2 3 4 5 6 7 8 9]
    Local variable: slice9 [0 1 2 3 4 5 6 7 8]

Slices Copy and Pass Parameters#

package main

import "fmt"

func printArr(arr *[5]int) {
    arr[0] = 10
    for i, v := range arr {
        fmt.Println(i, v)
    }
}

func main() {
    var arr1 [5]int
    printArr(&arr1)
    fmt.Println(arr1)
    arr2 := [...]int{2, 4, 6, 8, 10}
    printArr(&arr2)
    fmt.Println(arr2)
}

Slices#

Slice is not an array or an array pointer. It references a segment of an array through internal pointers and related properties to achieve a variable-length scheme.

    1. Slice: A slice is a reference type of an array, so slices are reference types. But itself is a struct, value copy passing.
    2. The length of a slice can change, so a slice is a mutable array.
    3. The way to iterate over a slice is the same as that of an array, and you can use len() to get the length. It indicates the number of available elements, and read/write operations cannot exceed this limit. 
    4. Cap can be used to find the maximum expansion capacity of a slice, which cannot exceed the array limit. 0 <= len(slice) <= len(array), where array is the array referenced by the slice.
    5. Slice definition: var variableName []type, for example var str []string var arr []int.
    6. If slice == nil, then both len and cap results are equal to 0.

Slice Creation#

package main

import "fmt"

func main() {
   //1. Declare a slice
   var s1 []int
   if s1 == nil {
      fmt.Println("is empty")
   } else {
      fmt.Println("is not empty")
   }
   // 2.:=
   s2 := []int{}
   // 3.make()
   var s3 []int = make([]int, 0)
   fmt.Println(s1, s2, s3)
   // 4. Initialize assignment
   var s4 []int = make([]int, 0, 0)
   fmt.Println(s4)
   s5 := []int{1, 2, 3}
   fmt.Println(s5)
   // 5. Slice from array
   arr := [5]int{1, 2, 3, 4, 5}
   var s6 []int
   // Front included, back excluded
   s6 = arr[1:4]
   fmt.Println(s6)
}

Slice Initialization#

// Global:
var arr = [...]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
var slice0 []int = arr[start:end]
var slice1 []int = arr[:end]
var slice2 []int = arr[start:]
var slice3 []int = arr[:]
var slice4 = arr[:len(arr)-1] // Remove the last element from the slice
// Local:
arr2 := [...]int{9, 8, 7, 6, 5, 4, 3, 2, 1, 0}
slice5 := arr[start:end]
slice6 := arr[:end]
slice7 := arr[start:]
slice8 := arr[:]
slice9 := arr[:len(arr)-1] // Remove the last element from the slice

img

Code:

package main

import (
    "fmt"
)

var arr = [...]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
var slice0 []int = arr[2:8]
var slice1 []int = arr[0:6]        // Can be simplified as var slice []int = arr[:end]
var slice2 []int = arr[5:10]       // Can be simplified as var slice[]int = arr[start:]
var slice3 []int = arr[0:len(arr)] // var slice []int = arr[:]
var slice4 = arr[:len(arr)-1]      // Remove the last element from the slice
func main() {
    fmt.Printf("Global variable: arr %v\n", arr)
    fmt.Printf("Global variable: slice0 %v\n", slice0)
    fmt.Printf("Global variable: slice1 %v\n", slice1)
    fmt.Printf("Global variable: slice2 %v\n", slice2)
    fmt.Printf("Global variable: slice3 %v\n", slice3)
    fmt.Printf("Global variable: slice4 %v\n", slice4)
    fmt.Printf("-----------------------------------\n")
    arr2 := [...]int{9, 8, 7, 6, 5, 4, 3, 2, 1, 0}
    slice5 := arr[2:8]
    slice6 := arr[0:6]         // Can be simplified as slice := arr[:end]
    slice7 := arr[5:10]        // Can be simplified as slice := arr[start:]
    slice8 := arr[0:len(arr)]  // slice := arr[:]
    slice9 := arr[:len(arr)-1] // Remove the last element from the slice
    fmt.Printf("Local variable: arr2 %v\n", arr2)
    fmt.Printf("Local variable: slice5 %v\n", slice5)
    fmt.Printf("Local variable: slice6 %v\n", slice6)
    fmt.Printf("Local variable: slice7 %v\n", slice7)
    fmt.Printf("Local variable: slice8 %v\n", slice8)
    fmt.Printf("Local variable: slice9 %v\n", slice9)
}

Output:

    Global variable: arr [0 1 2 3 4 5 6 7 8 9]
    Global variable: slice0 [2 3 4 5 6 7]
    Global variable: slice1 [0 1 2 3 4 5]
    Global variable: slice2 [5 6 7 8 9]
    Global variable: slice3 [0 1 2 3 4 5 6 7 8 9]
    Global variable: slice4 [0 1 2 3 4 5 6 7 8]
    -----------------------------------
    Local variable: arr2 [9 8 7 6 5 4 3 2 1 0]
    Local variable: slice5 [2 3 4 5 6 7]
    Local variable: slice6 [0 1 2 3 4 5]
    Local variable: slice7 [5 6 7 8 9]
    Local variable: slice8 [0 1 2 3 4 5 6 7 8 9]
    Local variable: slice9 [0 1 2 3 4 5 6 7 8]

Slices Copy and Pass Parameters#

package main

import "fmt"

func printArr(arr *[5]int) {
    arr[0] = 10
    for i, v := range arr {
        fmt.Println(i, v)
    }
}

func main() {
    var arr1 [5]int
    printArr(&arr1)
    fmt.Println(arr1)
    arr2 := [...]int{2, 4, 6, 8, 10}
    printArr(&arr2)
    fmt.Println(arr2)
}

Slices#

Slice is not an array or an array pointer. It references a segment of an array through internal pointers and related properties to achieve a variable-length scheme.

    1. Slice: A slice is a reference type of an array, so slices are reference types. But itself is a struct, value copy passing.
    2. The length of a slice can change, so a slice is a mutable array.
    3. The way to iterate over a slice is the same as that of an array, and you can use len() to get the length. It indicates the number of available elements, and read/write operations cannot exceed this limit. 
    4. Cap can be used to find the maximum expansion capacity of a slice, which cannot exceed the array limit. 0 <= len(slice) <= len(array), where array is the array referenced by the slice.
    5. Slice definition: var variableName []type, for example var str []string var arr []int.
    6. If slice == nil, then both len and cap results are equal to 0.

Slice Creation#

package main

import "fmt"

func main() {
   //1. Declare a slice
   var s1 []int
   if s1 == nil {
      fmt.Println("is empty")
   } else {
      fmt.Println("is not empty")
   }
   // 2.:=
   s2 := []int{}
   // 3.make()
   var s3 []int = make([]int, 0)
   fmt.Println(s1, s2, s3)
   // 4. Initialize assignment
   var s4 []int = make([]int, 0, 0)
   fmt.Println(s4)
   s5 := []int{1, 2, 3}
   fmt.Println(s5)
   // 5. Slice from array
   arr := [5]int{1, 2, 3, 4, 5}
   var s6 []int
   // Front included, back excluded
   s6 = arr[1:4]
   fmt.Println(s6)
}

Slice Initialization#

// Global:
var arr = [...]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
var slice0 []int = arr[start:end]
var slice1 []int = arr[:end]
var slice2 []int = arr[start:]
var slice3 []int = arr[:]
var slice4 = arr[:len(arr)-1] // Remove the last element from the slice
// Local:
arr2 := [...]int{9, 8, 7, 6, 5, 4, 3, 2, 1, 0}
slice5 := arr[start:end]
slice6 := arr[:end]
slice7 := arr[start:]
slice8 := arr[:]
slice9 := arr[:len(arr)-1] // Remove the last element from the slice

img

Code:

package main

import (
    "fmt"
)

var arr = [...]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
var slice0 []int = arr[2:8]
var slice1 []int = arr[0:6]        // Can be simplified as var slice []int = arr[:end]
var slice2 []int = arr[5:10]       // Can be simplified as var slice[]int = arr[start:]
var slice3 []int = arr[0:len(arr)] // var slice []int = arr[:]
var slice4 = arr[:len(arr)-1]      // Remove the last element from the slice
func main() {
    fmt.Printf("Global variable: arr %v\n", arr)
    fmt.Printf("Global variable: slice0 %v\n", slice0)
    fmt.Printf("Global variable: slice1 %v\n", slice1)
    fmt.Printf("Global variable: slice2 %v\n", slice2)
    fmt.Printf("Global variable: slice3 %v\n", slice3)
    fmt.Printf("Global variable: slice4 %v\n", slice4)
    fmt.Printf("-----------------------------------\n")
    arr2 := [...]int{9, 8, 7, 6, 5, 4, 3, 2, 1, 0}
    slice5 := arr[2:8]
    slice6 := arr[0:6]         // Can be simplified as slice := arr[:end]
    slice7 := arr[5:10]        // Can be simplified as slice := arr[start:]
    slice8 := arr[0:len(arr)]  // slice := arr[:]
    slice9 := arr[:len(arr)-1] // Remove the last element from the slice
    fmt.Printf("Local variable: arr2 %v\n", arr2)
    fmt.Printf("Local variable: slice5 %v\n", slice5)
    fmt.Printf("Local variable: slice6 %v\n", slice6)
    fmt.Printf("Local variable: slice7 %v\n", slice7)
    fmt.Printf("Local variable: slice8 %v\n", slice8)
    fmt.Printf("Local variable: slice9 %v\n", slice9)
}

Output:

    Global variable: arr [0 1 2 3 4 5 6 7 8 9]
    Global variable: slice0 [2 3 4 5 6 7]
    Global variable: slice1 [0 1 2 3 4 5]
    Global variable: slice2 [5 6 7 8 9]
    Global variable: slice3 [0 1 2 3 4 5 6 7 8 9]
    Global variable: slice4 [0 1 2 3 4 5 6 7 8]
    -----------------------------------
    Local variable: arr2 [9 8 7 6 5 4 3 2 1 0]
    Local variable: slice5 [2 3 4 5 6 7]
    Local variable: slice6 [0 1 2 3 4 5]
    Local variable: slice7 [5 6 7 8 9]
    Local variable: slice8 [0 1 2 3 4 5 6 7 8 9]
    Local variable: slice9 [0 1 2 3 4 5 6 7 8]

Slices Copy and Pass Parameters#

Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.