package main
import (
"fmt"
"runtime"
"strings"
"sync"
"time"
"unsafe"
)
//死锁
func main01() {
t := time.NewTicker(time.Second * 5)
// defer t.Stop() 解决死锁方案,在此处用defer关闭
for range t.C {
fmt.Println(1)
//stop关闭信号,不关闭通道通信,导致死锁
// t.Stop()
}
}
//字符串处理
func main02() {
//只要字符串包含fedabc任何一个就去掉,而且和顺序无关,所以整体都被去除了
s := strings.TrimRight("abcdefedcba", "fedabc")
fmt.Printf("%q\n", s) //"" %q输出带双引号的内容
//按照顺序删除后缀
s1 := strings.TrimSuffix("abcdefedcbaabcdef", "abcdef")
fmt.Println(s1) //abcdefedcba
}
//切片操作
func main03() {
v := []int{1, 2, 3}
//不会出现死循环 range会对数据进行拷贝
for i := range v {
v = append(v, i) //[1 2 3 0 1 2]
fmt.Printf("%p\n", v) //array的地址 :slice中是array的引用,其中包含指向slice的数组len和slice的上限的指针
fmt.Printf("%p\n", &v) //指针地址
//所以上面两者打印不是同一个地址
}
fmt.Println(v)
}
func main04() {
//rune数据类型,支持中文编码集
r := []rune("你好")
for _, val := range r {
fmt.Printf("%c", val)
}
}
func main05() {
//string 类型 可以转成[]byte []rune
b := []byte("hello")
r := []rune("haha")
// i:=[]int("sfas") 报错
//将字符串转成整型
// i,err:=strconv.Atoi("124")
fmt.Println(b, r)
}
func f(a int, b int) {
//返回拷贝成功得个数,前面是目标结构体,后面是源结构体
val := copy(make([]struct{}, a), make([]struct{}, b))
fmt.Printf("%d\n", val) //90
}
func main06() {
slice := make([]struct{}, 10)
//slice:本身存储了三个内容,array len cap 这三者都是整型,所以64位系统下,一个整型8字节 3*8=24 如果32位系统则是12
fmt.Println(unsafe.Sizeof(slice)) //24
//此处10指的是切片中array这个指针指向得地址存储数据所占据得大小
//此时目标结构体最多只能放90个,所以结果是90,如果90,314换个位置,还是结果90,因为源结构体也就90个
f(90, 314)
}
type P *int
type Q *int
func main61() {
var p P = new(int)
*p += 8
var x *int = p
var q Q = x
*q++
fmt.Println(*p, *q) //9 9 引用同一块内存
}
func main62() {
m := make(map[string]int)
m["foo"]++
fmt.Println(m["foo"]) //1 进⾏初始化,m["foo"]不能存在因为int类型初始化为0
}
//错误拦截
func main07() {
go func() {
//如果没有错误拦截,则不一定输出多少.之后报panic异常程序终止
defer func() {
err := recover()
if err != nil {
fmt.Println(err)
}
}()
panic("Boom")
}()
for i := 0; i < 100; i++ {
fmt.Print(".")
}
fmt.Println("Done")
}
func main08() {
defer func() { fmt.Println("1") }()
defer func() { fmt.Println("2") }()
defer func() { fmt.Println("3") }()
panic("触发异常")
/*
3 2 1 触发异常
遇到panic之后,后面代码都不执行了,只有所有操作出栈之后才能输出异常得警告
*/
}
type student struct {
Name string
Age int
}
func main09() {
m := make(map[string]*student)
stus := []student{
{Name: "zhou", Age: 24},
{Name: "li", Age: 23},
{Name: "wang", Age: 22},
}
for _, stu := range stus {
//for循环得stu必须如下重新赋值,不然指针类型赋值会把最后一次循环得付给所有value
stu := stu
m[stu.Name] = &stu
}
//这种方式则可以直接使用,不需要中间赋值一次
// for i := 0; i < len(stus); i++ {
// m[stus[i].Name] = &stus[i]
// }
for k, v := range m {
fmt.Println(k, v)
}
}
func main10() {
//设置0的时候即使用最大值,其他数值都是指定使用多少个CPU
runtime.GOMAXPROCS(1)
wg := sync.WaitGroup{}
wg.Add(10)
for i := 0; i < 10; i++ {
go func(i int) {
fmt.Println(i)
wg.Done()
}(i)
}
//队列顺序
// time.Sleep(time.Second) 1核时候,不加这句 9 0....8
wg.Wait()
}
func main11() {
a := []int{0, 1, 2, 3, 4, 5, 6, 7}
b := a[:3]
//这种b被另外一个切片赋值,b的容量是 a的长度-起始截取下表(此时是0,cap-low),所以b的cap是8,append一个4不会超出容量
//而且其中array指向和a的array都是一个地址,所以b追加一个4,会覆盖a中的3
b = append(b, 4)
// fmt.Println(cap(b)) //8
fmt.Println(a) //[0 1 2 4 4 5 6 7]
fmt.Println(b) // [0 1 2 4]
}
//这样就行了
func GetValue() interface{} {
return 1
}
// func GetValue() int {
// return 1
// }
func main12() {
i := GetValue()
switch i.(type) {
case int:
println("int") //输出int
case string:
println("string")
case interface{}:
println("interface")
default:
println("unknown")
}
//报错:断言必须是接口类型,cannot type switch on non-interface value i (type int)
}
func main13() {
//new:创建指针 make创建都是引用类型,例如切片有容量长度等附加属性
//list此时是指针类型 *[]int
list := new([]int)
// list = append(list, 1) 报错 append要求是切片,但是此时是切片指针
*list = append(*list, 1)
fmt.Println(list, *list) //&[1] [1]
}
func main14() {
s1 := []int{1, 2, 3}
s2 := []int{4, 5}
//...叫不定参数
// s1 = append(s1, s2)//报错
//不定参原理等同于切片,append第二个参数必须是不定参
s1 = append(s1, s2...)
fmt.Println(s1)
}
func test(a ...int) {
}
//不定参
func sum(arr ...int) {
//原理等同于切片:所以也有len cap
fmt.Printf("%T\n", arr) //[]int
//必须这样才能正常传参,不然传递的就只是切片而不是不定参
test(arr...)
}
func main() {
//可以一个参数也不传递
sum()
}
init函数
package main
func init() {}
func init() {}
func main() {}
- 这个程序将会正常运⾏
- ⼀个包下不可以有两个相同名称的函数,init函数除外,编译期间,编译器会⽤唯⼀的后缀重
写每个init函数的名称 - 一个init函数只能执行一次,并且无法在主函数中调用init函数
func init() {
var pcs [1]uintptr
runtime.Callers(1, pcs[:])
fn := runtime.FuncForPC(pcs[0])
fmt.Println(fn.Name())
}
func init() {
var pcs [1]uintptr
runtime.Callers(1, pcs[:])
fn := runtime.FuncForPC(pcs[0])
fmt.Println(fn.Name())
}
main.init.0 main.init.1
编译期间,编译器会⽤唯⼀的后缀重写每个init函数的名称
函数初始化顺序
- 数据类型
package main
func A(string string) string {
return string + string
}
func B(len int) int {
return len+len
}
func C(val, default string) string {
if val == "" {
return default
}
return val
}
- A B 能运⾏
- default 是关键字,不可以使⽤做变量名,string 和 len 是事先声明的标识符,可以使⽤,但
是不建议使⽤
- select
package main
import (
"time"
"fmt"
)
func A() int {
time.Sleep(100 * time.Millisecond)
return 1
}
func B() int {
time.Sleep(1000 * time.Millisecond)
return 2
}
func main() {
ch := make(chan int, 1)
go func() {
select {
case ch <- A():
case ch <- B():
default:
ch <- 3
}
}()
fmt.Println(<-ch)
}
输出1 或 2,管道获取到返回值后完成了主函数,主函数在接收到第⼀个返回值前在进⾏阻塞等待
- 方法继承
package main
import "fmt"
type People struct{}
func (p *People) ShowA() {
fmt.Println("showA")
p.ShowB()
}
func (p *People) ShowB() {
fmt.Println("showB")
}
type Teacher struct {
People
}
func (t *Teacher) ShowB() {
fmt.Println("teacher showB")
}
func main() {
t := Teacher{}
t.ShowA()
}
输出showA showB
这是Golang的组合模式,可以实现OOP的继承。 被组合的类型People所包含的⽅法虽然升
级成了外部类型Teacher这个组合类型的⽅法(⼀定要是匿名字段),但它们的⽅法
(ShowA())调⽤时接受者并没有发⽣变化。 此时People类型并不知道⾃⼰会被什么类型组
合,当然也就⽆法调⽤⽅法时去使⽤未知的组合者Teacher类型的功能。
- defer调用
package main
import "fmt"
func calc(index string, a, b int) int {
ret := a + b
fmt.Println(index, a, b, ret)
return ret
}
func main() {
a := 1
b := 2
defer calc("1", a, calc("3", a, b))
a = 0
defer calc("2", a, calc("4", a, b))
b = 1
}
输出 3 1 2 3,4 0 2 2,2 0 2 2,1 1 3 4
注意:defer calc内部的calc没有defer修饰所以会立即执行
结构体比较
package main
import "fmt"
func main() {
sn1 := struct {
age int
name string
}{age: 11, name: "qq"}
sn2 := struct {
age int
name string
}{age: 11, name: "qq"}
if sn1 == sn2 {
fmt.Println("sn1 == sn2")
}
}
输出sn1 == sn2
进⾏结构体⽐较时候,只有相同类型的结构体才可以⽐较,结构体是否相同不但与属性类型个数有关,还与属性顺序相关。结构体相同的情况下还需要结构体属性都是可⽐较类型才可以使⽤"=="进⾏⽐较。
package main
import "fmt"
func main() {
sn1 := struct {
age int
m map[string]string
}{age: 11,m: map[string]string{"a": "1"}}
sn2 := struct {
age int
m map[string]string
}{age: 11, m: map[string]string{"a": "1"}}
if sn1 == sn2 {
fmt.Println("sn1 == sn2")
}
}
编译错误,进⾏结构体⽐较时候,只有相同类型的结构体才可以⽐较,结构体是否相同不但与属性类型
个数有关,还与属性顺序相关。结构体相同的情况下还需要结构体属性都是可⽐较类型才可
以使⽤"=="进⾏⽐较。
总结:结构体比较,顺序不同也会不相等;
比较和成员的类型有关,例如:map是属性,地址肯定不一样的,可以通过map["具体成员"]==这样去比较,多个时候通过&&即可,否则直接比较是没法进行的
有疑问加站长微信联系(非本文作者)