【golang】INT_MAX最大值 INT_MIN最小值自定义

爱被打了一巴掌 2022-04-23 10:36 398阅读 0赞

golang没有INT_MAX INT_MIN常量值,可以用位操作运算

1. 无符号整型uint

最小值0,二进制所有位都为0

const UINT_MIN uint = 0

  1. 最大值的二进制所有位为1

const UINT_MAX = ^uint(0)

2. 有符号整型int

  1. 最大值,根据二进制补码,第一位为0,其余为1

const INT_MAX = int(^uint(0) >> 1)

  1. 最小值,第一位为1,其余为0,最大值取反即可

const INT_MIN = ^INT_MAX

  1. golang中***byte***数据类型与rune相似,它们都是用来表示字符类型的变量类型。它们的不同在于:
  • byte 等同于int8,常用来处理ascii字符
  • rune 等同于int32,常用来处理unicode或utf-8字符
  1. 如果将数组作为函数的参数类型,则***在函数调用时该参数将发生数据复制***。因此,在函数体中无法修改传入的数组的内容,因为函数内操作的只是所传入数组的一个副本

内容复制

  1. 数组切片支持Go语言的另一个内置函数 copy() ,用于将内容从一个数组切片复制到另一个数组切片。如果加入的两个数组切片不一样大,就会按其中较小的那个数组切片的元素个数进行复制。下面的示例展示了 copy() 函数的行为:

slice1 := []int{1, 2, 3, 4, 5}
slice2 := []int{5, 4, 3}
copy(slice2, slice1) // 只会复制slice1的前3个元素到slice2中
copy(slice1, slice2) // 只会复制slice2的3个元素到slice1的前3个位置

问题1 直接使用值为 nil 的 slice、map

  1. var m map\[int\]int
  2. m\[1\] = 2

main.main()
/home/lin/project/test.go:46 +0x31d
exit status 2

  1. 允许对值为 nil slice 添加元素,但对值为 nil map 添加元素则会造成运行时 panic
  2. // Like mapaccess, but allocates a slot for the key if it is not present in the map.
  3. func mapassign(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer {
  4. if h == nil {
  5. panic(plainError("assignment to entry in nil map"))
  6. }

问题2 map

map 容量

  1. 在创建 map 类型的变量时可以指定容量,但不能像 slice 一样使用 `cap()` 来检测分配空间的大小
  2. m := make(map[string]int, 99)
  3. println(cap(m)) // error: invalid argument m1 (type map[string]int) for cap

更新 map 字段的值

  1. 如果 map 一个字段的值是 struct 类型,则无法直接更新该 struct 的单个字段:因为 map 中的元素是不可寻址的
  2. 多个协程并发访问一个map,有可能会导致程序退出,并打印下面错误信息:
  3. fatal error: concurrent map read and map write
  4. 并发访问map是不安全的,会出现未定义行为,导致程序退出。所以如果希望在多协程中并发访问map,必须提供某种同步机制,一般情况下通过读写锁sync.RWMutex实现对map的并发访问控制

问题3 数组类型的值作为函数参数

  1. 数组是值。作为参数传进函数时,传***递的是数组的原始值拷贝***,此时在函数内部是无法更新该数组的
  2. 如果想修改参数数组:
  • 直接传递指向这个数组的指针类型

    x := [3]int{1,2,3}
    func(arr *[3]int) {}

    二维数组:

    table := make([][]int, x)
    for i := range table {

    1. table[i] = make([]int, y)

    }

问题3 string 类型的值是常量,不可更改

string 类型的值是只读的二进制 byte slice,如果真要修改字符串中的字符,将 string 转为 []byte 修改后,再转string

问题4 字符串的长度

  1. Go 的内建函数 `len()` 返回的是字符串的 byte 数量

问题5 对内建数据结构的操作并不是同步的

  1. goroutine channel 是进行原子操作的好方法,或使用 "sync" 包中的锁

问题6 channel

  1. 向已关闭的 channel 发送数据会造成 panic,从已关闭的 channel 接收数据是安全的
  2. 在一个值为 nil channel 上发送和接收数据将永久阻塞

问题7 在 range 迭代 slice、array、map 时通过更新引用来更新元素

  1. range 迭代中,得到的值其实是元素的一份值拷贝,更新拷贝并不会更改原来的元素,即是拷贝的地址并不是原有元素的地址

问题8 slice

  1. slice 中重新切出新 slice 时,新 slice 会引用原 slice 的底层数组。如果跳了这个坑,程序可能会分配大量的临时 slice 来指向原底层数组的部分数据,将导致难以预料的内存使用
  2. 可以通过拷贝临时 slice 的数据,而不是重新切片来解决
  3. 向一个 slice 中追加元素而它指向的底层数组容量不足时,将会重新分配一个新数组来存储数据。而其他 slice 还指向原来的旧底层数组。
  4. // 超过容量将重新分配数组来拷贝值、重新存储
  5. func main() {
  6. s1 := []int{1, 2, 3}
  7. fmt.Println(len(s1), cap(s1), s1) // 3 3 [1 2 3 ]
  8. s2 := s1[1:]
  9. fmt.Println(len(s2), cap(s2), s2) // 2 2 [2 3]
  10. for i := range s2 {
  11. s2[i] += 20
  12. }
  13. // 此时的 s1 与 s2 是指向同一个底层数组的
  14. fmt.Println(s1) // [1 22 23]
  15. fmt.Println(s2) // [22 23]
  16. s2 = append(s2, 4) // 向容量为 2 的 s2 中再追加元素,此时将分配新数组来存
  17. for i := range s2 {
  18. s2[i] += 10
  19. }
  20. fmt.Println(s1) // [1 22 23] // 此时的 s1 不再更新,为旧数据
  21. fmt.Println(s2) // [32 33 14]
  22. }

问题9 defer

  1. defer 延迟执行的函数,它的参数会在声明时候就会求出具体值,而不是在执行时才求值:
  2. // 在 defer 函数中参数会提前求值
  3. func main() {
  4. var i = 1
  5. defer fmt.Println("result: ", func() int { return i * 2 }())
  6. i++
  7. }

问题10 new和make区别

  1. new 的作用是初始化一个指向类型的指针(*T)。使用new函数来分配空间。传递给new函数的是一个类型,不是一个值。返回值是 指向这个新分配的零值的指针
  2. make 的作用是为 slicemap chan 初始化并返回引用(T)

问题11 进程和线程、协程的区别

  1. 进程比较重量,占据独立的内存,所以上下文进程间的切换开销(栈、寄存器、虚拟内存、文件句柄等)比较大,但相对比较稳定安全
  2. 线程间通信主要通过共享内存,上下文切换很快,资源开销较少,但相比进程不够稳定容易丢失数据(线程是处理器调度的基本单位)
  3. **协程是一种用户态的轻量级线程,**协程的调度完全由用户控制。协程拥有自己的寄存器上下文和栈。协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈,直接操作栈则基本没有内核切换的开销,可以不加锁的访问全局变量,所以上下文的切换非常快。

问题12 struct{}类型值的表示法只有一个,即:struct{}{}。

  1. 它占用的内存空间是0字节,这个值在整个Go 程序中永远都只会存在一份。虽然我们可以无数次地使用这值字面量,但是用到的却都是同一个值。

问题13 string 与 byte转化问题

https://www.jianshu.com/p/648a6d3bbb24

问题14 tool pprof使用

  1. go tool pprof -alloc\_space -cum -svg http://127.0.0.1:9988/debug/pprof/heap > heap.svg
  2. go tool pprof --alloc\_objects http://127.0.0.1:9988/debug/pprof/heap
  3. if debug {
  4. go func() {
  5. http.ListenAndServe("0.0.0.0:9988", nil)
  6. }()
  7. }

问题15 内存回收机制 mark and sweep(标记-清除)算法

该算法法分为两步:

  1. 标记从根变量开始迭代得遍历所有被引用的对象,对能够通过应用遍历访问到的对象都进行标记为“被引用”;
  2. 清除是在标记完成后进行的操作,对没有标记过的内存进行回收(回收同时可能伴有碎片整理操作)。

    三色标记法优化了这个问题

问题16 报错cannot find package “gopkg.in/go-playground/validator.v9”

  1. go语言第三方包依赖管理工具govendor,报错cannot find package "gopkg.in/go-playground/validator.v9"
  2. 比如,gopkg.in/go-playground/validator.v9 这个包,实际对应的就是 github.com/go-playground/validator v9 分支,那么只要 git clone -b v9 https://github.com/go-playground/validator.git 就可以拉下来。

参考:

  1. [https://segmentfault.com/a/1190000013739000][https_segmentfault.com_a_1190000013739000]

发表评论

表情:
评论列表 (有 0 条评论,398人围观)

还没有评论,来说两句吧...

相关阅读

    相关 互换位置

    问题: 下面程序的功能是从键盘任意输入n个数,然后找出其中的最大数与最小数,并将其位置对换。这个程序有无错误?如果有,那么错在哪里?请通过程序调试找到错误的原因并修正错误