Golang开发踩过的坑

Golang开发踩过的坑

  • 序言
    • for-range
    • 变量的有效区域
    • 结构体中嵌入匿名空接口
      • TIPS
    • 如何判断某type类型实现了某接口

序言

作为Golang开发的小白,日常开发时候总会遇到一些问题,本篇博客的会收录一些日常开发时踩过的坑,可能有解决了的,也许也会有没解决的。

for-range

在使用for-range进行遍历切片或数组时,遍历时的指针indexvalue只是一个临时且地址不变的内存地址

package main

import "fmt"

func main() {
    num := [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 0}
    numPointer := [10]*int{}
    for i, v := range num {
        numPointer[i] = &v
        fmt.Print(&i, " ") //0xc00001e0c8 0xc00001e0c8 0xc00001e0c8 0xc00001e0c8 0xc00001e0c8 0xc00001e0c8 0xc00001e0c8 0xc00001e0c8 0xc00001e0c8 0xc00001e0c8
    }
    fmt.Println(numPointer) //[0xc00001e0f0 0xc00001e0f0 0xc00001e0f0 0xc00001e0f0 0xc00001e0f0 0xc00001e0f0 0xc00001e0f0 0xc00001e0f0 0xc00001e0f0 0xc00001e0f0]
}

要想的到原来切片或者数组中元素的的地址应该改为

numPointer[i] = &num[i]

变量的有效区域

在进行函数调用时,应注意函数的参数与返回值是否冲突或者是否在相同调用区域内

package main

import (
    "errors"
    "fmt"
)
//test 将参数进行加1后与一个err,一起返回
func test(a int) (int, error) {
    a++
    return a, errors.New("test")
}

func main() {
    var b int
    for i := 0; i < 2; i++ {
        b, err := test(b)
        if err != nil {
            fmt.Println(err, b)
        }
    }
    fmt.Println(b)
}

输出结果为:

test 1
test 1
0

将main函数中的test调用改为:

func main() {
    var b int
    var err error
    for i := 0; i < 2; i++ {
        b, err = test(b)
        if err != nil {
            fmt.Println(err, b)
        }
    }
    fmt.Println(b)
}

修改后输出为:

test 1
test 2
2

结构体中嵌入匿名空接口

package main

import (
    "fmt"
    "strconv"
    "time"
)

// 接口:一组方法的集合
// OpenCloser 接口定义两个方法 返回 error
type OpenCloser interface {
    Open() error
    Close() error
}


type win struct {
    open bool // 门的状态是否开启
    lock bool // 门的状态是否上锁
}

func (d *win) Open() error {
   fmt.Println("win open...")
   d.open = true
   return nil
}

func (d *win) Close() error {
    fmt.Println("win close...")
    d.open = false
    return nil
}

type Door struct {
    win
    open bool // 门的状态是否开启
    lock bool // 门的状态是否上锁
}
func (d *Door) Open() error {
    fmt.Println("door open...")
    d.open = true
    return nil
}


type AutoDoor struct {
    OpenCloser   // 匿名接口
    delay int    // 延迟多长时间开启
    msg   string // er自动开启时的警报
}

func (a *AutoDoor) Open() error {
    fmt.Println("Open after " + strconv.Itoa(a.delay) + " seconds")
    time.Sleep(time.Duration(a.delay) * time.Second)
    fmt.Println("Door is opening:" + a.msg)
    return nil
}

func main() {
    //door := &AutoDoor{&Door{false, false}, 3, "warning"}
    door:=&AutoDoor{
        OpenCloser: &win{
            open: false,
            lock: false,
        },
        delay:      3,
        msg:        "test",
    }
    door.Open()//AutoDoor
    if v, ok := door.OpenCloser.(*win); ok { //类型断言
        fmt.Println("1",v)
    }

    door.OpenCloser.Open()//door
    if v, ok := door.OpenCloser.(*Door); ok { //类型断言
        fmt.Println("2",v)
    }

    door.Close()//win
    if v, ok := door.OpenCloser.(*win); ok { //类型断言
        fmt.Println("3",v)
    }

    fmt.Println("4",door.OpenCloser.(*Door))
}

输出结果为:

Open after 3 seconds
Door is opening:test
1 &{false false}
win open...
win close...
3 &{false false}
4 &{false false}

TIPS

当结构中有匿名空接口时,注意创建新对象时传入的空接口为指针类型,否则会报错。

如何判断某type类型实现了某接口

var _ interfaceName=new(typeName)
var _ interfaceName=(*typeName)(nil)

package main

import "fmt"

type a interface {
	say(string) string
	walk()
}

type b interface {
	say(str string) string
}

type Person struct {
	name string
}

func (p *Person) say(str string) string {
	return p.name + " say " + str
}

var _ b = new(Person)//会分配内存,编译器检查,编译时检查
var _ b = (*Person)(nil)//不会分配内存,编译器检查,编译时检查

func main() {
	person := &Person{name: "Alice"}
	var i interface{} = person
	c := i.(b)
	fmt.Println(c.say("hello"))//Alice say hello
}

引申出new与make的区别

你可能感兴趣的:(日常划水)