前言
在极客上看了蔡超老师的Go语言课程 随手记下来的一些随笔,Go的基础应用及实例, 系列内容比较偏基础,推荐给想要入门Go语言开发者们阅读。
目录如下
Go语言基础学习 (一) - 变量 常量已经与其他语言的差异
Go语言基础学习 (二) -Go语言中的类型转与Go语言中的数组切片
Go语言基础学习 (三) - Go语言内的 Map声明使用与工厂模式
Go语言基础学习 (四) - Go语言函数简单介绍
Go语言基础学习 (五) - 面向对象编程
Go语言基础学习 (六) - 编写一个好的错误处理
Go语言基础学习 (七) - 包(package)
Go语言基础学习 (八) - 并发编程
- 其实GO并不是一个纯面向对象编程语言。它没有提供类(class)这个关键字,只提供了结构体(struct)类型。java或者C# 里面,结构体(struct)是不能有成员函数的。然而,Go语言中的结构体(struct)可以有"成员函数"。方法可以被添加到结构体中,类似于一个类的实现。
1. 结构体定义
2. 结构体初始化实例化的几种方法
-
实例化去赋值第一种:分别把每个参数的值放在{}内type Employee struct { Id string Name string Age string } e := Employee{"0","Bob",20}第二种:与第一种类似,指定给每一个key赋值type Employee struct { Id string Name string Age string } e := Employee{Name:"Mike",Age",20}第三种: 创建一个指向实例的指针,然后通过 .Id 来单独赋值type Employee struct { Id string Name string Age string } a := new(Employee) a.Id = 1 a.Name = "XiaoMing"
3. 使用行为(方法)定义
-
定义func (e Employee) String() string { return fmt.Sprintf("ID:%s/Name:%s/Age:%d",e.Id,e.name,e.Age) } func TestObj( t *testing.T) { e := Employee{1,"zhangsan",1} t.Log(e.String()) // ID:1/Name:zhangsan/Age:1 }使用指针调用func (e *Employee) String() string { return fmt.Sprintf("ID:%s/Name:%s/Age:%d",e.Id,e.name,e.Age) } func TestObj( t *testing.T) { e := &Employee{1,"zhangsan",1} t.Log(e.String()) // ID:1/Name:zhangsan/Age:1 }结果是相同的 两种方法都可以使用,而两种方法不一样点就是实例的存储地址不同
第一种方法 在实例的调用中会进行复制,会有内存的消耗
第二种方法 不会内存拷贝,减少开销
4. Go的接口相关
-
接口与依赖简单代码实例type Programmer interface { // 接口定义 WirteHelloWorld() string // 想要实现的方法写这里 } type GoProgrammer struct { // 接口的实现数据实例 name string } func (g * GoProgrammer) WirteHelloWorld()string { // 使用指向类型的指针初始化实例 g.name = "Hello World" return g.name } func TestClient(t *testing.T) { var p Programmer p = new(GoProgrammer) t.Log(p.WirteHelloWorld()) // Hello World } -
使用interface 简单实现一个签名工具的方法package sign_test import ( "fmt" "testing" ) type SignFunc interface { VerifySign(sign string,key string) bool GetSignStr(param string,key string) string } type SignData struct { id int name string sex int time int key string } func (s * SignData) VerifySign(sign string,key string) bool { s.key = key // ...... 过程省略...... return true } func (s * SignData) GetSignStr(param string,key string) string { // 过程省略......... return "12312312312" } func TestSign(t * testing.T) { var s SignFunc s = new(SignData) // 验证签名 signRet := s.VerifySign("1231231231","dasdasdasdas") signStr := s.GetSignStr("12313123123131321","123131313213200") fmt.Println("签名验证结果:",signRet) fmt.Println("签名生成结果:",signStr) } -
自定义功能(第四节内的装饰性函数进一步处理优化// 未优化的函数 较为繁琐 func timeSpent(inner func(op int) int ) func(op int)int { return func(n int) int { start := time.Now() ret := inner(n) fmt.Println("time spent:",time.Since(start).Seconds()) return ret } }// 优化后的 type intConv func(op int) int func timeSpent(inner IntConv ) IntConv { return func(n int) int { start := time.Now() ret := inner(n) fmt.Println("time spent:",time.Since(start).Seconds()) return ret } } -
扩展与复用首先看一段PHP的子类继承扩展复用代码class Pet { public function speak(){ var_dump('....'); } public function speakTwo(string $host){ $this->speak(); var_dump($host); } } class Dog extends Pet{ public function speak() { var_dump('wang!'); } } class Test { public function testSubClassAccess(string $host) { $dog = new Dog(); $dog->speakTwo($host); } } $test = new Test(); $test->testSubClassAccess('test!'); // wang! test!创建Pet类,写入两个方法,在创建Dog类,并声明重载speak方法,在调用子类,通过子类调用父类speakTwo方法是,父类会重写speak方法。但是go是没有继承的,可以使用struct结构体来模拟类type Pet struct { // 创造一个Pet的结构体 并且声明两个方法 } func (p * Pet) Speak() { fmt.Println("...") } func (p * Pet) SpeakTwo(host string) { p.Speak() fmt.Println(host) } type Dog struct { // 创建一个Dog的结构体,声明复用同样的方法 p *Pet // 直接指向Pet结构,可以在Dog结构下使用Pet的方法 } func (d * Dog) Speak() { d.p.Speak() // 通过小数点调用p的方法 } func (d *Dog) SpeakTwo(host string) { d.p.SpeakTwo(host) // 通过小数点调用p的方法 } func TestDog(t *testing.T) { dog := new(Dog) dog.SpeakTwo("test!") }打印结果
...
test!从上面结果看来 在Dog结构指向Pet结构体时,Dog是可以使用.来调用Pet内的方法,很像面向对象内的子类继承父类方法,但是在go里面是不支持子类继承重写的,Dog指向了Pet结构体 只代表Dog结构体可以调用Pet结构体内的方法试一下子类继承重写type Pet struct { } func (p * Pet) Speak() { fmt.Println("...") } func (p * Pet) SpeakTwo(host string) { p.Speak() fmt.Println(" ",host) } type Dog struct { Pet } func (d * Dog) Speak() { // 在此处尝试重写Pet结构内的方法 fmt.Println("重写加载成功!!") } func TestDog(t *testing.T) { dog := new(Dog) dog.SpeakTwo("test!") }... test!结果还是同上面一样,所以Go语言内是不支持子类继承的方法复写与重定义 -
多态性type code string // 定义 code 为string类型 type Programmer interface { // 创建interface WriteHelloWorld() code } type GoProgrammer struct { // 创建一个结构体 } // 创建interface 下方法 使用GoProgrammer结构体来实现 func (p *GoProgrammer) WriteHelloWorld() code { return "fmt.Println(\"Hello World!\")" } type JavaProgrammer struct { } func (p *JavaProgrammer) WriteHelloWorld() code { return "System.out.Println(\"Hello World!\")" } // 新增方法,传入interface类型 func writeFirstProgrammer(p Programmer) { fmt.Printf("%T %v\n",p,p.WriteHelloWorld()) // 输入传入进来的inerface下指定的结构体方法 } func TestPolymorphism(t *testing.T) { goProg := new(GoProgrammer) javaProg := new(JavaProgrammer) writeFirstProgrammer(goProg) // 调用方法 传入对应的结构体来调用对应的interface方法 writeFirstProgrammer(javaProg) }*interface_test.GoProgrammer fmt.Println("Hello World!") *interface_test.JavaProgrammer System.out.Println("Hello World!") -
空接口与断言第一个参数为返回值,第二个参数为bool,以第二个参数来判定是否转换成功。使用断言来判断一个方法接受参数的类型func DoSomething(p interface{}) { if i, ok := p.(int); ok { fmt.Println("Int", i) return } if i, ok := p.(string); ok { fmt.Println("String", i) return } fmt.Println("Unknow Type") } func TestEmptyInterfaceAssertion(t *testing.T) { DoSomething(1) DoSomething("1") DoSomething(true) }Int 1 String 1 Unknow Type