Go 语言入门指南(三) 青训营
这篇博客继续对go
的基础语法进行整理。主要包括:接口、文件操作。
一、接口
接口也有点不好理解,首先注意:==接口是一种类型----抽象类型。==有点像C++的模板类型!底层分为动态类型和动态值两部分。
接口类型对行为(方法)做约束。就像是一种协议、一种规则约束。
不同的类有一个相似的方法,就可以屏蔽类的差异,以这个方法为约束构造一个新的类型---interface
同一个类可能属于多个interface
。另外interface
也可以嵌套使用。
看下面的例子:
// 在函数传参时就可以使用speaker这个类型来当形参 // 实参可以是实现了speak方法的任意类 type speaker interface{ // 具体的方法声明,所有有这些方法的类都可以通过speaker这个interface来统一 speak() // ... } // cat类有speak这个方法 type cat struct{ name string } func (c cat)speak(){ // ... } // dog类有speak这个方法 type dog struct{ name string } func (d dog)speak(){ // ... } // pig类有speak这个方法 type pig struct{ name string } func (p pig)speak(){ // ... } func amimalSpeak(x speaker){ x.speak() } func main(){ c := cat{name: "aaa"} d := dog{name: "sss"} p := pig{name: "ddd"} // 实参可以是实现了speak方法的任何类 amimalSpeak(c) amimalSpeak(p) amimalSpeak(d) // 可以直接赋值!speaker就是抽象类型 var am speaker fmt.Printf("%T\n", am) // nil // am 有动态类型和动态值 am = c fmt.Printf("%T\n", am) // main.cat am = d fmt.Printf("%T\n", am) // main.dog am = p fmt.Printf("%T\n", am) // main.pig }
1. 使用值接收者和使用指针接收者的区别
实现值接收者的类可以赋值给interface
类型,实现值接收者的类的指针也可以赋值给interface
类型。
但是实现指针接收者的类想要赋值给interface
类型,必须取地址。(常用)
2. 空接口
应用:函数形参(可以接收任意类型的变量)
map
的value
类型
看下面例子:
// 接口里没有任何约束,也就是任何类型都可以传给空接口 // fmt.Println() 的形参就是典型的空接口 interface{} // 这个就是空接口类型 // 这个map的value可以是任意类型 var m map[string]interface{} m = make(map[string]interface{}, 10) m["aaa"] = "111" m["sss"] = 1 m["ddd"] = []int{1,2,3} // 可以接收任意类型的变量 func show(a interface{}){ }
二、文件操作
所有的文件操作其实都是对底层操作系统的文件操作做了封装,所以只需要会用那些封装的接口就可以了,go
的文件操作主要有三个包:os
、bufio
、ioutil
。下面是简单的接口用法。
打开文件:
// *os.File func Open(name string) (file *File, err error) // flag标记:O_WRONLY/O_RDONLY...和底层的一样; FileMode:文件权限 func OpenFile(name string, flag int, perm FileMode) (file *File, err error)
读的操作:
func main(){ // Open:只读的方式打开文件 file,err := os.Open("./test.txt") if err != nil{ fmt.Printf("open file test.txt error:%v\n", nil) return } // 关闭文件描述符,并设置成defer,这也是defer的应用场景 // 在判断完err后写这个关闭!! defer file.Close() // 读取文件方法一 tmp := make([]byte, 128) // 读到tmp里,返回值n表示实际读到的字节数 n,err := file.Read(tmp) if err != nil{ // ... } // 读取文件方法二 使用bufio包(基于缓冲区) reader := bufio.NewReader(file) // reader里有很多读取方法 line,err := reader.ReadString('\n') // 一次读一行,读到line中 if err == os.EOF{ // ... return } if err != nil{ // ... } // 读取文件方法三 使用ioutil包 // 不用打开文件,直接读取,函数里肯定还是打开和关闭文件了 // 直接读取到文件末尾!也就是读取所有内容 ret,err := ioutil.ReadFile("./xxx.txt") if err != nil{ // ... } }
写的操作:
file,err := os.OpenFile("./xxx.txt",os.O_CREATE|os.O_WRONLY|os.TRUNC, 0644) if err != nil{ // ... } // 一定是在判断完nil后defer关闭 defer file.Close() // 写入方法一 file.Write([]byte("ssss")) file.WriteString("sdfsasasa") // 写入方法二 使用bufio包 writer := bufio.NewWriter(file) writer.WriteString("sasa") // 写到缓存里 writer.Flush() // 刷新缓冲区!! // 写入方法三 使用ioutil包(基于缓冲区) // 不用打开文件,直接写入,函数里肯定还是打开和关闭文件了 err := ioutil.WriteFile("./xx.txt", []byte("asdsa"), 0666) if err != nil{ // ... }
这篇博客就总结到这里吧。