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

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

 

1. 无符号整型uint

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

 const UINT_MIN uint = 0

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

const UINT_MAX = ^uint(0)

 

2. 有符号整型int

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

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

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

const INT_MIN = ^INT_MAX

 

     golang中byte数据类型与rune相似,它们都是用来表示字符类型的变量类型。它们的不同在于:

  • byte 等同于int8,常用来处理ascii字符
  • rune 等同于int32,常用来处理unicode或utf-8字符

 

       如果将数组作为函数的参数类型,则在函数调用时该参数将发生数据复制。因此,在函数体中无法修改传入的数组的内容,因为函数内操作的只是所传入数组的一个副本 

 

内容复制

        数组切片支持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

    var m map[int]int
    m[1] = 2
main.main()
    /home/lin/project/test.go:46 +0x31d
exit status 2

       允许对值为 nil 的 slice 添加元素,但对值为 nil 的 map 添加元素则会造成运行时 panic 

// Like mapaccess, but allocates a slot for the key if it is not present in the map.
func mapassign(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer {
        if h == nil {
                panic(plainError("assignment to entry in nil map"))
        }

 

问题2 map

   map 容量

      在创建 map 类型的变量时可以指定容量,但不能像 slice 一样使用 cap() 来检测分配空间的大小

m := make(map[string]int, 99)
println(cap(m))     // error: invalid argument m1 (type map[string]int) for cap  

   更新 map 字段的值

        如果 map 一个字段的值是 struct 类型,则无法直接更新该 struct 的单个字段:因为 map 中的元素是不可寻址的

 

       多个协程并发访问一个map,有可能会导致程序退出,并打印下面错误信息:

fatal error: concurrent map read and map write

       并发访问map是不安全的,会出现未定义行为,导致程序退出。所以如果希望在多协程中并发访问map,必须提供某种同步机制,一般情况下通过读写锁sync.RWMutex实现对map的并发访问控制        

 

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

     数组是值。作为参数传进函数时,传递的是数组的原始值拷贝,此时在函数内部是无法更新该数组的

     如果想修改参数数组:

  • 直接传递指向这个数组的指针类型
x := [3]int{1,2,3}
func(arr *[3]int) {}

     二维数组:

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

 

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

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

 

问题4 字符串的长度

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

 

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

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

 

问题6 channel

    向已关闭的 channel 发送数据会造成 panic,从已关闭的 channel 接收数据是安全的

    在一个值为 nil 的 channel 上发送和接收数据将永久阻塞   

 

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

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

 

问题8 slice

    从 slice 中重新切出新 slice 时,新 slice 会引用原 slice 的底层数组。如果跳了这个坑,程序可能会分配大量的临时 slice 来指向原底层数组的部分数据,将导致难以预料的内存使用

    可以通过拷贝临时 slice 的数据,而不是重新切片来解决

    向一个 slice 中追加元素而它指向的底层数组容量不足时,将会重新分配一个新数组来存储数据。而其他 slice 还指向原来的旧底层数组。

// 超过容量将重新分配数组来拷贝值、重新存储
func main() {
    s1 := []int{1, 2, 3}
    fmt.Println(len(s1), cap(s1), s1)    // 3 3 [1 2 3 ]

    s2 := s1[1:]
    fmt.Println(len(s2), cap(s2), s2)    // 2 2 [2 3]

    for i := range s2 {
        s2[i] += 20
    }
    // 此时的 s1 与 s2 是指向同一个底层数组的
    fmt.Println(s1)        // [1 22 23]
    fmt.Println(s2)        // [22 23]

    s2 = append(s2, 4)    // 向容量为 2 的 s2 中再追加元素,此时将分配新数组来存

    for i := range s2 {
        s2[i] += 10
    }
    fmt.Println(s1)        // [1 22 23]    // 此时的 s1 不再更新,为旧数据
    fmt.Println(s2)        // [32 33 14]
}

 

问题9 defer

     对 defer 延迟执行的函数,它的参数会在声明时候就会求出具体值,而不是在执行时才求值:

// 在 defer 函数中参数会提前求值
func main() {
    var i = 1
    defer fmt.Println("result: ", func() int { return i * 2 }())
    i++
}

 

问题10 new和make区别

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

 

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

    进程比较重量,占据独立的内存,所以上下文进程间的切换开销(栈、寄存器、虚拟内存、文件句柄等)比较大,但相对比较稳定安全

    线程间通信主要通过共享内存,上下文切换很快,资源开销较少,但相比进程不够稳定容易丢失数据(线程是处理器调度的基本单位)

    协程是一种用户态的轻量级线程,协程的调度完全由用户控制。协程拥有自己的寄存器上下文和栈。协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈,直接操作栈则基本没有内核切换的开销,可以不加锁的访问全局变量,所以上下文的切换非常快。

 

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

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

 

问题13 string 与 byte转化问题

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

 

问题14 tool pprof使用

     go tool pprof -alloc_space -cum -svg http://127.0.0.1:9988/debug/pprof/heap > heap.svg

     go tool pprof --alloc_objects http://127.0.0.1:9988/debug/pprof/heap

if debug {
	go func() {
		http.ListenAndServe("0.0.0.0:9988", nil)
	}()
}

 

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

该算法法分为两步:

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

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

 

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

      go语言第三方包依赖管理工具govendor,报错cannot find package "gopkg.in/go-playground/validator.v9"

 

      比如,gopkg.in/go-playground/validator.v9 这个包,实际对应的就是 github.com/go-playground/validator 的 v9 分支,那么只要 git clone -b v9 https://github.com/go-playground/validator.git 就可以拉下来。
 

参考:

     https://segmentfault.com/a/1190000013739000 

 

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值