GO 重新进阶学习(一)

结构方法

类型的 String() 方法和格式化描述符
如果类型定义了 String() 方法,它会被用在 fmt.Printf() 中生成默认的输出:
等同于使用格式化描述符 %v 产生的输出
还有 fmt.Print() 和 fmt.Println() 也会自动使用 String() 方法。
昨天晚上看书的知识点
1.如果想要改变接收器中的数据。就用指针接受器
2.如果实在不知道用那个就全部用指针接受器

Go 语言规范定义了接口方法集的调用规则:
类型 *T 的可调用方法集包含接受者为 *T 或 T 的所有方法集
类型 T 的可调用方法集包含接受者为 T 的所有方法
类型 T 的可调用方法集不包含接受者为 *T 的方法

所以在大多数情况下,还是用指针

备注

不要在 String() 方法里面调用涉及 String() 方法的方法,它会导致意料之外的错误,比如下面的例子,它导致了一个无限迭代(递归)调用(TT.String() 调用 fmt.Sprintf,而 fmt.Sprintf 又会反过来调用 TT.String()…),很快就会导致内存溢出:

type TT float64

func (t TT) String() string {
    return fmt.Sprintf("%v", t)
}
t. String()

练习 10.12 type_string.go

给定结构体类型 T:

type T struct {
    a int
    b float32
    c string
}

值 t: t := &T{7, -2.35, “abc\tdef”}。给 T 定义 String(),使得 fmt.Printf(“%v\n”, t) 输出:7 / -2.350000 / “abc\tdef”。

练习 10.13 celsius.go
为 float64 定义一个别名类型 Celsius,并给它定义 String(),它输出一个十进制数和 °C 表示的温度值。

练习 10.14 days.go
为 int 定义一个别名类型 Day,定义一个字符串数组它包含一周七天的名字,为类型 Day 定义 String() 方法,它输出星期几的名字。使用 iota 定义一个枚举常量用于表示一周的中每天(MO、TU…)。

练习 10.15 timezones.go
为 int 定义别名类型 TZ,定义一些常量表示时区,比如 UTC,定义一个 map,它将时区的缩写映射为它的全称,比如:UTC -> “Universal Greenwich time”。为类型 TZ 定义 String() 方法,它输出时区的全称。

练习 10.16 stack_arr.go/stack_struct.go

实现栈(stack)数据结构:
它的格子包含数据,比如整数 i、j、k 和 l 等等,格子从底部(索引 0)至顶部(索引 n)来索引。这个例子中假定 n=3,那么一共有 4 个格子。
一个新栈中所有格子的值都是 0。
push 将一个新值放到栈的最顶部一个非空(非零)的格子中。
pop 获取栈的最顶部一个非空(非零)的格子的值。现在可以理解为什么栈是一个后进先出(LIFO)的结构了吧。
为栈定义一 Stack 类型,并为它定义一个 Push 和 Pop 方法,再为它定义 String() 方法(用于调试)它输出栈的内容,比如:[0:i] [1:j] [2:k] [3:l]。
1)stack_arr.go:使用长度为 4 的 int 数组作为底层数据结构。
2)stack_struct.go:使用包含一个索引和一个 int 数组的结构体作为底层数据结构,索引表示第一个空闲的位置。
3)使用常量 LIMIT 代替上面表示元素个数的 4 重新实现上面的 1)和 2),使它们更具有一般性。

练习 10.17
从练习 10.16 开始(它基于结构体实现了一个栈结构),为栈的实现(stack_struct.go)创建一个单独的包 stack,并从 main 包 main.stack.go 中调用它。

垃圾回收和 SetFinalizer

这里会去看一下GO中的垃圾回收

接口

以后经典的完整文件读取
一个接口可以包含一个或多个其他的接口,这相当于直接将这些内嵌接口的方法列举在外层接口中一样。

type ReadWrite interface {
    Read(b Buffer) bool
    Write(b Buffer) bool
}

type Lock interface {
    Lock()
    Unlock()
}

type File interface {
    ReadWrite
    Lock
    Close()
}

接口的套用,反正都会实现的
练习 11.1 simple_interface.go:

定义一个接口 Simpler,它有一个 Get() 方法和一个 Set(),Get() 返回一个整型值,Set() 有一个整型参数。创建一个结构体类型 Simple 实现这个接口。

接着定一个函数,它有一个 Simpler 类型的参数,调用参数的 Get() 和 Set() 方法。在 main 函数里调用这个函数,看看它是否可以正确运行。

type Simpler interface {
	Get() int
	Set(inputInt int)
}

type Simple struct {
	dataInt int
}

//这里好像必须是指针的接受器,如果用到是值接受器,没有报错当时没有数据进行改变
func (receiver *Simple) Get() int {
	return receiver.dataInt
}

func (receiver *Simple) Set(inputInt int) {
	receiver.dataInt = inputInt
}

func main() {
	var simpleOne = new(Simple)
	simpleOne.Set(20)
	var dataInt = simpleOne.Get()
	fmt.Printf("%v", dataInt)
}

这里开始是类型处理

练习 11.4 simple_interface2.go:

接着练习 11.1 中的内容,创建第二个类型 RSimple,它也实现了接口 Simpler,写一个函数 fi,使它可以区分 Simple 和 RSimple 类型的变量。
练习 11.9 simple_interface3.go:

首先是创建RSimple

type Simpler interface {
	Get() int
	Set(inputInt int)
}

type RSimple struct {
	RDataInt int
}

type Simple struct {
	dataInt int
}

func (r *RSimple) Get() int {
	return r.RDataInt
}
func (r *RSimple) Set(inputInt int) {
	r.RDataInt = inputInt
}

func (receiver *Simple) Get() int {
	return receiver.dataInt
}

func (receiver *Simple) Set(inputInt int) {
	receiver.dataInt = inputInt
}

然后开始编写区分函数,这里直接用的Simper切片

func fi(SimplerInterface []Simpler) {
	for i, simpler := range SimplerInterface {
		fmt.Printf("%d", i)
		switch t := simpler.(type) {
		case *RSimple:
			fmt.Printf("%T %v", t, t)
		case *Simple:
			fmt.Printf("%T %v", t, t)
		case nil:
			fmt.Printf("nil value: nothing to check?\n")
		default:
			fmt.Printf("Unexpected type %T\n", t)
		}
		println("----------------")
	}
}

继续 练习 11.2,在它中添加一个 gI 函数,它不再接受 Simpler 类型的参数,而是接受一个空接口参数。然后通过类型断言判断参数是否是 Simpler 类型。最后在 main 使用 gI 取代 fI 函数并调用它。确保你的代码足够安全。

func gI(SimplerInerface interface{}) {
	switch t := SimplerInerface.(type) {
	case Simpler:
		fmt.Printf("%T %v", t, t)
		switch t2 := t.(type) {
		case *RSimple:
			fmt.Printf("%T %v", t2, t2)
		case *Simple:

			fmt.Printf("%T %v", t2, t2)
		case nil:
			fmt.Printf("nil value: nothing to check?\n")
		default:
			fmt.Printf("Unexpected type %T\n", t2)
		}
	case nil:
		fmt.Printf("nil value: nothing to check?\n")
	default:
		fmt.Printf("Unexpected type %T\n", t)
	}
}

这里有个问题
如果传入

var emptyInterface = new(Simpler)
gI(emptyInterface)

这个我进不到第一个case
Unexpected type *main.Simpler

学习接口和类型断言后,然后就是通用使用
这里加上泛型的使用。因为每个种类都去处理类型匹配非常难受
下一篇文章中学习一下1.8中的泛型使用
这里的问题都具有泛化性,所以弄完泛型后进行数据结构的编写

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值