Go Xiaobai’s 100000 why

Time:2021-9-24

In my last article, I proposedchannelUnder what kind of operation will be triggeredpanic。 In this article, let’s summarize the 100000 why Xiaobai often asks in go.

string

Suppose we want to modify a character whose type is a string variable. If it is the greatest language in the world, we can do this directly (I almost forgot to write PHP):

<?php

$name = "test";
$name[0] = "T";
var_dump($name);
// string(4) "Test"

In go, it is not allowed to use index subscript to operate characters in string variables, which will directly compile errors.

//Not allowed
  x := "test"
  x[0] = 'T'
  //cannot assign to x[0]

Generally, I will convert it into byte.

package main
import "fmt"

func main() {
  s := "test"
  bytes := []byte(s)
  bytes[0] = 'T'
  FMT. Println ("value of S:", string (bytes))
  //Value of S: Test
}

array

Let’s look at such a program,

import "fmt"
func main() {
  a := [3]int{10, 20, 30}
  changeArray(a)
  FMT. Println ("value of a:", a)
}

func changeArray(items [3]int) {
  items[2] = 50
}
//Value of a: [10, 20, 30]

The answer will not be [10,20,30]. Because when the array is passed to the function above, the array will be copied, which is a value transfer. Of course, the subsequent modification has nothing to do with the previous one.

Of course, you can pass array pointers so that they point to the same address.

func main() {
  a := [3]int{10, 20, 30}
  changeArray(&a)
  FMT. Println ("value of a:", a)
}

//Arrays are value passing
func changeArray(items *[3]int) {
  items[2] = 50
}
//Value of a: [10, 20, 50]

Alternatively, slice can be used.

package main

import "fmt"

func main() {
  s := []int{10, 20, 30}
  changeSlice(s)
  FMT. Println ("the value of S is:", s ")
}
func changeSlice(items []int) {
  items[2] = 50
}
//The value of S is: [10, 20, 50]

sliceEssentially, no data is stored. It is only a part of the basic array.sliceThe underlying structure is,

type slice struct {
  Array unsafe. Pointer // pointer position of the underlying array
  Len int // current length of slice
  Cap int // capacity. When the capacity is insufficient, the dynamic capacity expansion mechanism will be triggered
}

When the message issliceAnd the underlying structure of the slicearrayWhen the value of still points to the same array pointer address, the modification of array elements will affect each other.

slice

Look at the code below,

package main

import "fmt"

func main() {
  data := cutting()
  fmt.Printf("data's len:%v,cap:%v\n", len(data), cap(data))
}

func cutting() []int {
  val := make([]int, 1000)
  fmt.Printf("val's len:%v,cap:%v\n ", len(val), cap(val))
  return val[0:10]
}
// val's len:1000,cap:1000
// data's len:10,cap:1000

As mentioned above, when a new slice is intercepted on the basis of the original sliceslicesliceThe underlying array of the original slice will be referenced. If it is a large slice, it will lead to a waste of memory.

We can define an additional variable with appropriate capacity, and thencopyOperation.

package main

import "fmt"

func main() {
  data := cutting()
  fmt.Printf("data's len:%v,cap:%v\n", len(data), cap(data))
}
func cutting() []int {
  val := make([]int, 1000)
  fmt.Printf("val's len:%v,cap:%v\n ", len(val), cap(val))
  res := make([]int, 10)
  copy(res, val)
  return res
}

//val's len:1000,cap:1000
// data's len:10,cap:10

copy

Now that it’s up therecopyWell, let’s seecopy

package main

import "fmt"

func main() {
  var test1, test2 []int
  test1 = []int{1, 2, 3}
  copy(test2, test1)
  FMT. Println ("value of test2:", test2)
}
//Value of test2: []

Why is that?

copyThe number of copied elements is the smallest of the two slices. currenttest1andtest2The minimum length of the istest20, so finally return the empty slice, we cantest2Assign length.

package main

import "fmt"

func main() {
  var test1, test2 []int
  test1 = []int{1, 2, 3}
  test2=make([]int,len(test1))
  copy(test2,test1)
  FMT. Println ("value of test2:", test2)
}
//Value of test2: [1 2 3]

range

Let’s look at the following code,

package main

import "fmt"

func main() {
  res := []int{1, 2, 3}
  for _, item := range res {
    item *= 10
  }
  fmt.Println("res:", res)
}
// res: [1 2 3]

The final value is not as high as expected[10,20,30]。 Why?

Because in gorangeThe second return value is actually a copy of the value.

This also tells us that when the traversal slice type is a structure, we need to avoid such an operation, which will consume a lot of memory. We can do it through the index subscript.

package main

import "fmt"

func main() {
  res := []int{1, 2, 3}
  for index, _ := range res {
    res[index] *= 10
  }
  fmt.Println("res:", res)
  // res: [10 20 30]
}

struct

We often use “= =” to judge whether two structures are equal, for example,

package main

import "fmt"

type User struct {
  Name string
  Age  int

}
func main() {
  user1 := User{}
  user2 := User{}
  fmt.Println(user1 == user2)
  // true
}

This is no problem. What if I add such a field to the structure?

package main

import "fmt"

type User struct {
  Name string
  Age  int
  IsChild func(age int) bool
}

func main() {
  user1 := User{}
  user2 := User{}
  fmt.Println(user1 == user2)
  // invalid operation: user1 == user2 (struct containing func(int) bool cannot be compared)
}

Directly report compilation errors. Why?

If any field in the structure is not comparable, using the “= =” operator will cause compilation errors. I added itIsChildThe field type is a closure function, which is obviously not comparable.

groutine

package main

import (
  "fmt"
)

func main() {
  var hi string
  go func() {
    hi = "golang"
  }()
  fmt.Println(hi)
}

What is the above output?

The probability is nothing, because before the sub coroutine assigns a value to the hi variable, the main coroutine probably prints first, then runs, and then the whole program ends.

Stop the main process in the stupidest way.

package main

import (
  "fmt"
  "time"
)

func main() {
  var hi string
  go func() {
    hi = "golang"
  }()
  time.Sleep(10 * time.Millisecond)
  fmt.Println(hi)
  //golang
}

Look at this question again,

package main

import (
  "fmt"
  "sync"
)

func main() {
  var wg sync.WaitGroup
  for i := 0; i < 5; i++ {
    wg.Add(1)
    go func() {
      FMT. Println ("value is:", I)
      wg.Done()
    }()
  }
  wg.Wait()
}

Each time, the answer is different, but the probability is 5. There is data competition in the operation here, that isdata race。 This happens when two or moregroutineRaised when the same variable is accessed concurrently and one access is writtendata race

You can add parameters from the command line-raceRun detection.
Go Xiaobai's 100000 why

The repair method will also be simple at startupgroutineUse local variables and pass numbers as parameters.

package main

import (
  "fmt"
  "sync"
)
func main() {
  var wg sync.WaitGroup
  for i := 0; i < 5; i++ {
    wg.Add(1)
    go func(item int) {
      FMT. Println ("value is:", item)
      wg.Done()
    }(i)
  }
  wg.Wait()
}

recover()

Can be used in gorecover()Function capturepanicHowever, we also need to pay attention to its usage. The following postures are wrong.

package main

import "fmt"

func main() {
  recover()
  panic("make error")
}
//Wrong posture
package main

import "fmt"


func main() {
  doRecover()
  panic("make error")
}

func doRecover() {
  defer func() {
    if err := recover(); err != nil {
      Fmt.println ("error")
    }
  }()
}
//Wrong posture
package main

import "fmt"


func main() {
  defer func() {
    defer func() {
      if err := recover(); err != nil {
        fmt.Println(err)
      }
    }()
  }()
  panic("make error")
}
//Wrong posture

It takes effect only if it is called directly in the delay function.

package main

import "fmt"

func main() {
  defer func() {
    if err := recover(); err != nil {
      fmt.Println(err)
    }
  }()
  panic("make error")
}
//Correct posture

There are many wrong postures not listed. Do you have different wrong operations? Welcome to leave a message below for discussion.

If the article is helpful to you, like, forward and leave messages are a kind of support!
Go Xiaobai's 100000 why

This work adoptsCC agreement, reprint must indicate the author and the link to this article

Wu qinkuri