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{
// ...
}
这篇博客就总结到这里吧。