golang基本题目相关

强某某 · · 465 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

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函数的名称

函数初始化顺序

1.jpg
  • 数据类型
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["具体成员"]==这样去比较,多个时候通过&&即可,否则直接比较是没法进行的


有疑问加站长微信联系(非本文作者)

本文来自:简书

感谢作者:强某某

查看原文:golang基本题目相关

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

465 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传