4.说说Go语言中,数组和切片的区别?切片的底层

数组 数组的长度是类型的一部分,不同的长度的数组,类型不是一致的

a := [3]int{1, 2, 3}
b := [4]int{1, 2, 3}
fmt.Printf("a 的类型为%s, b的类型为%s\n", reflect.TypeOf(a), reflect.TypeOf(b))
fmt.Println(reflect.TypeOf(a) == reflect.TypeOf(b))
   
// a 的类型为[3]int, b的类型为[4]int
// false
as := a[0:2]
bs := b[0:2]
fmt.Printf("as的类型为%v,bs的类型为%v\n", reflect.TypeOf(as), reflect.TypeOf(bs))
fmt.Println(reflect.TypeOf(as) == reflect.TypeOf(bs))
   
// as的类型为[]int,bs的类型为[]int
// true
func main(){ 
 arrayA := [2]int{100, 200}
 var arrayB [2]int
 arrayB = arrayA

 fmt.Printf("arrayA : %v , %v\n", &arrayA[0], arrayA)
 fmt.Printf("arrayB : %v , %v\n", &arrayB[0], arrayB)
 testArray(arrayA)

 fmt.Println()
 
 sliceA := arrayA[0:1]
 sliceB := sliceA
 fmt.Printf("sliceA : %v , %v\n", &sliceA[0], sliceA)
 fmt.Printf("sliceB : %v , %v\n", &sliceB[0], sliceB)
 testSlice(sliceA)

}
func testArray(x [2]int) {
 fmt.Printf("func Array : %v , %v\n", &x[0], x)
}
func testSlice(x []int) {
 fmt.Printf("func Slice : %v , %v\n", &x[0], x)
}
/*
arrayA : 0xc0000180b0 , [100 200]
arrayB : 0xc0000180c0 , [100 200]
func Array : 0xc000018110 , [100 200]

sliceA : 0xc0000180b0 , [100]
sliceB : 0xc0000180b0 , [100]
func Slice : 0xc0000180b0 , [100]
*/
c := [...]int{1,2,3,4}
fmt.Printf("c 的类型为%s, 长度为%v\n", reflect.TypeOf(c), len(c))
// c 的类型为[4]int, 长度为4

cs := []int{1, 2, 3, 4}
cs = append(cs, 5)
fmt.Printf("cs 的类型为%s, 长度为%v\n", reflect.TypeOf(cs), len(cs))
// cs 的类型为[]int, 长度为5
type slice struct {
    array unsafe.Pointer // 指向数组的指针
    len   int             // 当前切片的长度
    cap   int             // 当前切片容量
}
func main() {
 arr := [4]int{1, 2, 3, 4}
 sliceA := arr[:]
 fmt.Printf("len(silceA) = %v, cap(sliceA) = %v\n", len(sliceA), cap(sliceA))
 // len(silceA) = 4, cap(sliceA) = 4

 // 修改arr的第一个元素值,sliceA的第一个元素值跟着变化
 arr[0] = 5
 fmt.Printf("sliceA = %v\n", sliceA)
 // sliceA = [5 2 3 4]

 // 给slice添加元素,导致slice扩容,空间重新分配
 sliceA = append(sliceA, 6)
 fmt.Printf("sliceA = %v\n", sliceA)
 fmt.Printf("len(silceA) = %v, cap(sliceA) = %v\n", len(sliceA), cap(sliceA))
 // sliceA = [5 2 3 4 6]
 // len(silceA) = 5, cap(sliceA) = 8

 // 修改arr的第一个元素值,发现sliceA的第一个元素值不在跟着变化
 arr[0] = 7
 fmt.Printf("arr = %v\n", arr)
 fmt.Printf("sliceA = %v\n", sliceA)
 // arr = [7 2 3 4]
 // sliceA = [5 2 3 4 6]
}

func main() {
 arr := [3]int{1, 2, 3}
 slice := arr[0:1]
 slice2 := append(slice, 5, 6, 7)

 fmt.Println(arr, slice, slice2)
}
// [1 2 3] [1] [1 5 6 7]

func main() {
 arr := [3]int{1, 2, 3}
 slice := arr[0:1]
 slice2 := append(slice, 5, 6)

 fmt.Println(arr, slice, slice2)
}
// [1,5,6] [1] [1,5,6]

5. 说说go语⾔的同步锁

var x = 0
var waitGroup sync.WaitGroup

func main() {
    waitGroup.Add(2)
    go add()
    go add()
    waitGroup.Wait()
    fmt.Println(x)
}

func add() {
    for i := 0; i < 10000; i++ {
        y := x
        y = y + 1
        x = y
    }
    waitGroup.Done()
}
var x = 0
var waitGroup sync.WaitGroup
var mutex sync.Mutex

func main() {
    waitGroup.Add(2)
    go add()
    go add()
    waitGroup.Wait()
    fmt.Println(x)
}

func add() {
    for i := 0; i < 10000; i++ {
        mutex.Lock()
        y := x
        y = y + 1
        x = y
        mutex.UnLock()
    }
    waitGroup.Done()
}

于此之外还有读写锁,即

var rwmutex sync.RWMutex
rwmutex.Lock()// 加写锁,阻止其他读写获取锁
rwmutex.RLock()// 加读锁,如果其他gorountine要获取读锁的话,会获得读锁,如果要获取写锁就会等待

channel特性

给⼀个 nil channel 发送数据,造成永远阻塞

从⼀个 nil channel 接收数据,造成永远阻塞

给⼀个已经关闭的 channel 发送数据,引起 panic

从⼀个已经关闭的 channel 接收数据,如果缓冲区中为空,则返回⼀个零值

⽆缓冲的channel是同步的,⽽有缓冲的channel是⾮同步的

func main() {
   c := make(chan int)
   go add(c)
   go send(c)
   // 给5秒时间让前两个goroutine有足够时间运行
   time.Sleep(5 * time.Second)
}

// 不断向channel c中发送[0,10)的随机数
func send(c chan int) {
   for {
      c <- rand.Intn(10)
   }
}
func add(c chan int) {
   sum := 0
   // 1秒后,将向t.C通道发送时间点,使其可读
   t := time.NewTimer(2 * time.Second)
   for {
      // 两秒内,将一直选择第一个case
      // 两秒后,t.C可读,将选择第二个case
      // c变成nil channel后,两个case分支都将一直阻塞
      select {
      case input := <-c:
         // 不断读取c中的随机数据进行加总
         sum = sum + input
      case <-t.C:
         c = nil
         fmt.Println(sum)
      }
   }
}
func main() {
   c := make(chan int)
   go send(c)
   go receive(c)
   // 给5秒时间让前两个goroutine有足够时间运行
   time.Sleep(5 * time.Second)
}

// 不断向channel c中发送[0,10)的随机数
func send(c chan int) {
   for {
      c <- rand.Intn(10)
   }
}

func receive(c chan int) {
   i := 0
   t := time.NewTimer(1 * time.Second)
   for {
      select {
      case <-t.C:
         c = nil
      case <-c:
         fmt.Println(i)
         i++
      }
   }
}