Golang 入门资料+笔记Golang学习

《GO语言圣经》学习笔记(七)方法和接口

2020-08-05  本文已影响0人  半亩房顶

知识点

接收器

func (p *Point) ScaleBy(factor float64) {
    p.X *= factor
    p.Y *= factor
}

此处 *Point 即是此函数的接收器

tips:
1、不管你的method的receiver是指针类型还是非指针类型,都是可以通过指针/非指针类型进行调用的,编译器会帮你做类型转换。
2、在声明一个method的receiver该是指针还是非指针类型时,你需要考虑两方面的内部,
第一方面是这个对象本身是不是特别大,如果声明为非指针变量时,调用会产生一次拷贝;
第二方面是如果你用指针类型作为receiver,那么你一定要注意,这种指针类型指向的始终是一块内存地址,就算你对其进行了拷贝。熟悉C或者C++的人这里应该很快能明白。

Nil也是一个合法的接收器类型

// An IntList is a linked list of integers.
// A nil *IntList represents the empty list.
type IntList struct {
    Value int
    Tail  *IntList
}
// Sum returns the sum of the list elements.
func (list *IntList) Sum() int {
    if list == nil {
        return 0
    }
    return list.Value + list.Tail.Sum()
}

顺便提一句,要小心空map,注意不要赋值,不然就恭喜get一个panic小技巧了
panic: assignment to entry in nil map

封装

Go语言只有一种控制可见性的手段:大写首字母的标识符会从定义它们的包中被导出,小写字母的则不会。这种限制包内成员的方式同样适用于struct或者一个类型的方法。因而如果我们想要封装一个对象,我们必须将其定义为一个struct。

封装的优点:

接口

var any interface{}
any = true
any = 12.34
any = "hello"
any = map[string]int{"one": 1}
any = new(bytes.Buffer)

类型断言

类型断言是一个使用在接口值上的操作。语法上它看起来像x.(T)被称为断言类型,这里x表示一个接口的类型和T表示一个类型。一个类型断言检查它操作对象的动态类型是否和断言的类型匹配。

经常地我们对一个接口值的动态类型是不确定的,并且我们更愿意去检验它是否是一些特定的类型。如果类型断言出现在一个预期有两个结果的赋值操作中,例如如下的定义,这个操作不会在失败的时候发生panic但是代替地返回一个额外的第二个结果,这个结果是一个标识成功的布尔值:

var w io.Writer = os.Stdout
f, ok := w.(*os.File)      // success:  ok, f == os.Stdout
b, ok := w.(*bytes.Buffer) // failure: !ok, b == nil

第二个结果常规地赋值给一个命名为ok的变量。如果这个操作失败了,那么ok就是false值,第一个结果等于被断言类型的零值,在这个例子中就是一个nil的*bytes.Buffer类型。

这个ok结果经常立即用于决定程序下面做什么。if语句的扩展格式让这个变的很简洁:

if f, ok := w.(*os.File); ok {
    // ...use f...
}

当类型断言的操作对象是一个变量,你有时会看见原来的变量名重用而不是声明一个新的本地变量,这个重用的变量会覆盖原来的值,如下面这样:

if w, ok := w.(*os.File); ok {
    // ...use w...
}

基于类型断言区别错误类型

I/O可以因为任何数量的原因失败,但是有三种经常的错误必须进行不同的处理:文件已经存在(对于创建操作),找不到文件(对于读取操作),和权限拒绝。os包中提供了这三个帮助函数来对给定的错误值表示的失败进行分类:

package os

func IsExist(err error) bool
func IsNotExist(err error) bool
func IsPermission(err error) bool

eg.下面是IsNotExist的实际使用:

_, err := os.Open("/no/such/file")
fmt.Println(os.IsNotExist(err)) // "true"

类型开关

一个类型开关像普通的switch语句一样,它的运算对象是x.(type)-它使用了关键词字面量type-并且每个case有一到多个类型。一个类型开关基于这个接口值的动态类型使一个多路分支有效。这个nil的case和if x == nil匹配,并且这个default的case和如果其它case都不匹配的情况匹配。一个对sqlQuote的类型开关可能会有这些case:

switch x.(type) {
    case nil:       // ...
    case int, uint: // ...
    case bool:      // ...
    case string:    // ...
    default:        // ...
}

引用

拓展

[]byte 扩容算法

发现很多设计都是类似的实现,比如redis的SDS

type Buffer struct {
    buf     []byte
    initial [64]byte
    /* ... */
}

// Grow expands the buffer's capacity, if necessary,
// to guarantee space for another n bytes. [...]
func (b *Buffer) Grow(n int) {
    if b.buf == nil {
        b.buf = b.initial[:0] // use preallocated space initially
    }
    if len(b.buf)+n > cap(b.buf) {
        buf := make([]byte, b.Len(), 2*cap(b.buf) + n)
        copy(buf, b.buf)
        b.buf = buf
    }
}

欢迎大家关注我的公众号


半亩房顶
上一篇下一篇

猜你喜欢

热点阅读