Go语言学习基础刷题记(Golang roadmap)2021-07-13

Posted Demonwuwen

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Go语言学习基础刷题记(Golang roadmap)2021-07-13相关的知识,希望对你有一定的参考价值。

1.

下面的代码输出什么?

func main() {  
    fmt.Println(~2) 
}

编译错误:
invalid character U+007E '~'
很多语言都是采用 ~ 作为按位取反运算符,Go 里面采用的是 ^ 。按位取反之后返回一个每个 bit 位都取反的数,对于有符号的整数来说,是按照补码进行取反操作的(快速计算方法:对数 a 取反,结果为 -(a+1) ),对于无符号整数来说就是按位取反。例如:

func main() {
    var a int8 = 3
    var b uint8 = 3
    var c int8 = -3

    fmt.Printf("^%b=%b %d\\n", a, ^a, ^a) // ^11=-100 -4
    fmt.Printf("^%b=%b %d\\n", b, ^b, ^b) // ^11=11111100 252
    fmt.Printf("^%b=%b %d\\n", c, ^c, ^c) // ^-11=10 2
}

另外需要注意的是,如果作为二元运算符,^ 表示按位异或,即:对应位相同为 0,相异为 1。例如:

func main() {
    var a int8 = 3
    var c int8 = 5
    fmt.Printf("a: %08b\\n",a)
    fmt.Printf("c: %08b\\n",c)
    fmt.Printf("a^c: %08b\\n",a ^ c)
}

给大家重点介绍下这个操作符 &^,按位置零,例如:z = x &^ y,表示如果 y 中的 bit 位为 1,则 z 对应 bit 位为 0,否则 z 对应 bit 位等于 x 中相应的 bit 位的值。

不知道大家发现没有,我们还可以这样理解或操作符| ,表达式 z = x | y,如果 y 中的 bit 位为 1,则 z 对应 bit 位为 1,否则 z 对应 bit 位等于 x 中相应的 bit 位的值,与 &^ 完全相反。

    var x uint8 = 214
    var y uint8 = 92
    fmt.Printf("x: %08b\\n",x)     
    fmt.Printf("y: %08b\\n",y)       
    fmt.Printf("x | y: %08b\\n",x | y)     
    fmt.Printf("x &^ y: %08b\\n",x &^ y)

输出

    x: 11010110
    y: 01011100
    x | y: 11011110
    x &^ y: 10000010

2.

下面这段代码输出什么?

type People struct {
     name string `json:"name"`
}
func main() {
     js := `{
         "name":"seekload"
     }`
     var p People
     err := json.Unmarshal([]byte(js), &p)
     if err != nil {
        fmt.Println("err: ", err)
        return
    }
    fmt.Println(p)
}

输出 {}。

  • 结构体访问控制,因为 name 首字母是小写,导致其他包不能访问,所以输出为空结构体。修复代码:
type People struct {
        Name string `json:"name"`
    }

3.

下面代码输出什么?

const (
     x uint16 = 120
     y
     s = "abc"
     z
 )
 func main() {
    fmt.Printf("%T %v\\n", y, y)
    fmt.Printf("%T %v\\n", z, z)
}
  • 输出 :
    uint16 120
    string abc
    解析:常量组中如不指定类型和初始化值,则与上一行非空常量右值相同

4.

下面代码输出什么?

func main() {
    var ch chan int
    select {
    case v, ok := <-ch:
        println(v, ok)
    default:
        println("default") 
    }
}
  • default。ch 为 nil,读写都会阻塞

5.

下面代码输出什么?

func main() {
    x := interface{}(nil)
    y := (*int)(nil)
    a := y == x
    b := y == nil
    _, c := x.(interface{})
    println(a, b, c)
}
  • 输出:false true false
    解析:
    x的类型为接口,值为nil,y的类型为*int,值为nil,y == x比较类型不一致,所以false,
    y 的值本就为nil,直接与nil比较,所以为true
    x.interface{},类型断言语法:i.(Type),其中 i 是接口,Type 是类型或接口。编译时会自动检测 i 的动态类型与 Type 是否一致。但是,如果动态类型不存在,则断言总是失败

6.

下面代码是否正确?

func main() {
    m := make(map[string]int,2)
    cap(m) 
}
  • 不正确
    解析:问题:使用 cap() 获取 map 的容量。1.使用 make 创建 map 变量时可以指定第二个参数,不过会被忽略。2.cap() 函数适用于数组、数组指针、slice 和 channel,不适用于 map,可以使用 len() 返回 map 的元素个数。

7.

下面代码是否正确?

type ConfigOne struct {
     Daemon string
 }

 func (c *ConfigOne) String() string {
     return fmt.Sprintf("print: %v", c)
 }

 func main() {
    c := &ConfigOne{}
    c.String()
}
  • 解析:
    运行时错误。如果类型实现 String() 方法,当格式化输出时会自动使用 String() 方法。上面这段代码是在该类型的 String() 方法内使用格式化输出,导致递归调用,最后抛错。

8.

下面代码能编译通过吗?

type info struct {
    result int
}
func work() (int,error) {
    return 13,nil
}
func main() {
    var data info
    data.result, err := work() 
    fmt.Printf("info: %+v\\n",data)
}
non-name data.result on left side of :=

不能使用短变量声明设置结构体字段值,修复代码:

func main() {
    var data info
    var err error
    data.result, err = work() //ok
    if err != nil {
        fmt.Println(err)
        return
    }
    fmt.Println(data)   
}

9.

下面代码是否正确?

func main() {

    var s []int
    s = append(s,1)

    var m map[string]int
    m["one"] = 1 
}
  • 解析
    不能对 nil 的 map 直接赋值,需要使用 make() 初始化。但可以使用 append() 函数对为 nil 的 slice 增加元素。
    修复代码:
func main() {
    var m map[string]int
    m = make(map[string]int)
    m["one"] = 1
}

10.

下面代码输出什么?

type T struct {
    n int
}
func main() {
    m := make(map[int]T)
    m[0].n = 1
    fmt.Println(m[0].n)
}
  • 解析:
    编译错误:cannot assign to struct field m[0].n in map
    map[key]struct 中 struct 是不可寻址的,所以无法直接赋值。

修复代码:

type T struct {
    n int
}
func main() {
    m := make(map[int]T)
    t := T{1}
    m[0] = t
    fmt.Println(m[0].n)
}

11.

下面的代码输出什么?

func F(n int) func() int {
    return func() int {
        n++
        return n
    }
}

func main() {
    f := F(5)
    defer func() {
        fmt.Println(f())
    }()
    defer fmt.Println(f())
    i := f()
    fmt.Println(i)
}
  • 输出:768
    解析:defer() 后面的函数如果带参数,会优先计算参数,并将结果存储在栈中,到真正执行 defer() 的时候取出。所以第二个defer是先运算了一次闭包

12.

下面的代码有什么问题?

type data struct {
    sync.Mutex
}

func (d data) test(s string)  {
    d.Lock()
    defer d.Unlock()

    for i:=0;i<5 ;i++  {
        fmt.Println(s,i)
        time.Sleep(time.Second)
    }
}


func main() {

    var wg sync.WaitGroup
    wg.Add(2)
    var d data

    go func() {
        defer wg.Done()
        d.test("read")
    }()

    go func() {
        defer wg.Done()
        d.test("write")
    }()

    wg.Wait()
}

问题:锁失效

  • 将 Mutex 作为匿名字段时,相关的方法必须使用指针接收者,否则会导致锁机制失效。

修复代码:

func (d *data) test(s string)  {     // 指针接收者
    d.Lock()
    defer d.Unlock()

    for i:=0;i<5 ;i++  {
        fmt.Println(s,i)
        time.Sleep(time.Second)
    }
}

或者可以通过嵌入 *Mutex 来避免复制的问题,但需要初始化。

type data struct {
    *sync.Mutex     // *Mutex
}

func (d data) test(s string) {    // 值方法
    d.Lock()
    defer d.Unlock()

    for i := 0; i < 5; i++ {
        fmt.Println(s, i)
        time.Sleep(time.Second)
    }
}

func main() {

    var wg sync.WaitGroup
    wg.Add(2)

    d := data{new(sync.Mutex)}   // 初始化

    go func() {
        defer wg.Done()
        d.test("read")
    }()

    go func() {
        defer wg.Done()
        d.test("write")
    }()

    wg.Wait()
}

以上是关于Go语言学习基础刷题记(Golang roadmap)2021-07-13的主要内容,如果未能解决你的问题,请参考以下文章

Go语言学习基础刷题记(Golang roadmap)2021-07-13

Go语言学习基础刷题记(Golang roadmap)2021-07-13

用golang刷LeetCode

golang 目录

go语言(golang)学习之路

GO 语言基础语法一 (快速入门 Go 语言)