这是我参与「第五届青训营 」笔记创作活动的第 2 天
|| 🎶今日笔记🎶 ||
学习过程的重点内容:
- go的基础语法
- 与类不一样的——结构体
- 独特的继承机制
- 代码优化之——工厂设计模式
go的基础语法
关键字:
-
var
和const
是 Go语言基础里面的变量和常量申明 -
package
和import
用于分包和导入 -
func
用于定义函数和方法 -
return
用于从函数返回 -
defer
用于类似析构函数 -
go
用于并发 -
select
用于选择不同类型的通讯 -
interface
用于定义接口 -
struct
用于定义抽象数据类型 -
break
、case
、continue
、for
、fallthrough
、else
、if
、switch
、goto
、default
用于流程控制 -
chan
用于channel通讯 -
type
用于声明自定义类型 -
map
用于声明map类型数据 -
range
用于读取slice、map、channel数据
错误类型:
Go内置有一个error
类型,专门用来处理错误信息,Go的package
里面还专门有一个包errors
来处理错误
err := errors.New("This is my new errors")
if err != nil {
fmt.Print(err)
}
Array,Slice,Map:
array
就是数组,它的定义方式如下:
var arr [your arr len]type
var arr [10]int // 声明了一个int类型的数组
arr[0] = 12 // 数组下标是从0开始的
arr[1] = 33 // 赋值操作
fmt.Println("The first element is", arr[0]) // 获取数据,返回12
fmt.Println("The last element is", arr[9]) //返回未赋值的最后一个元素,默认返回0
[your arr len]type
中,your arr len
为你自定义数组的长度,type
表示存储元素的类型。对数组的操作和其它语言类似,都是通过[]
来进行读取或赋值:
由于长度也是数组类型的一部分,因此[3]int
与[4]int
是不同的类型,数组也就不能改变长度。数组之间的赋值是值的赋值,即当把一个数组作为参数传入函数的时候,传入的其实是该数组的副本,而不是它的指针。
数组可以使用另一种:=
来声明
a := [3]int{1, 2, 3} // 声明了一个长度为3的int数组
b := [10]int{1, 2, 3} // 声明了一个长度为10的int数组,其中前三个元素初始化为1、2、3,其它默认为0
c := [...]int{4, 5, 6} // 可以省略长度而采用`...`的方式,Go会自动根据元素个数来计算长度
复制代码
Go支持嵌套数组,即多维数组。比如下面的代码就声明了一个二维数组:
// 声明了一个二维数组,该数组以两个数组作为元素,其中每个数组中又有4个int类型的元素
doubleArray := [2][4]int{[4]int{1, 2, 3, 4}, [4]int{5, 6, 7, 8}}
// 上面的声明可以简化,直接忽略内部的类型
easyArray := [2][4]int{{1, 2, 3, 4}, {5, 6, 7, 8}}
结构体 & 类?
与其他语言不同,go的“类”称为结构体,虽然go也是一门面向对象的高级语言,但他不是纯粹的面向对象语言,通过下面的struct例子来对说明
type Person struct { 通过type xxx struct的形式定义一个结构体
Name string `json:"name"` //定义字段&属性(string类型)
Age int `json:"age"` //定义字段&属性(int类型)
Sex string `json:"sex"` //定义字段&属性(string类型)
}
其中'json:"name"'的形式将字段转成json形式
detail:
字段建议以驼峰的形式定义,首字母大写可以使本包以及其他包下的程序来访问(访问权限如Java中的Public),首字母小写的访问权限范围为本类(访问权限如Java中的Private)
func (person Person) pretest(ags []string) Person {
person.Name = ags[0] //给Name字段赋值
person.Sex = ags[1] //给Sex字段赋值
return person
}
将方法与Person进行绑定,这也是方法与函数的区别之一。
type Teacher struct {
Tid int
TName string
}
func (t *Teacher) String() string { //将Teacher设置为指针类型
str := fmt.Sprintf("Tid=%v,TName=%v", t.Tid, t.TName)
return str
}
func main{
teacher := Teacher{
TName: "yang",
Tid: 250,
}
fmt.Println("teacher-->", &teacher)
}
将Teacher设置为指针类型
detail:
其中,将方法名设为 String并且返回类型为 string的话,如同 Java中的 ToString,在 main方法中输出 &teacher(指针类型输出地址值为其字段的真正地址。String()被视为匿名函数处理
控制台输出
teacher--> Tid=250,TName=yang
Process finished with the exit code 0
独特的继承机制
go语言的继承与其他面向对象语言不同,不通过我们常见的extend关键字来实现,通过在子类struct中以内嵌的方式来实现,通俗的说就是在普通继承的时候就是直接extend,而go的是基于 鸭子类型 理论,就是你只要拥有某种特征,你就是他,比如你定义一个鸭子的接口,这个鸭子接口拥有叫和走, 无论你定义狗,还是定义猫,只要他们也实现了鸭子的叫,和走,那么 他们就是鸭子!
type Animal struct {
Name string
}
func (a *Animal) Eat() {
fmt.Printf("%v is eating", a.Name)
fmt.Println()
}
type Cat struct {
Animal
}
cat := &Cat{
Animal: Animal{
Name: "cat",
},
}
cat.Eat() // cat is eating
首先,我们实现了一个 Animal 的结构体,代表动物类。并声明了 Name 字段,用于描述动物的名字。
然后,实现了一个以 Animal 为 receiver 的 Eat 方法,来描述动物进食的行为。
最后,声明了一个 Cat 结构体,组合了 Animal 字段。实例化一个猫,调用 Eat 方法,可以看到正常的输出。
Cat 结构体本身没有 Name 字段,也没有去实现 Eat() 方法。唯一有的就是匿名嵌套的方式继承了 Animal 父类。至此,我们证明了 Go 通过匿名嵌套的方式实现了继承。
上面是嵌入类型实例,同样地也可以嵌入类型指针。
type Cat struct {
*Animal
}
cat := &Cat{
Animal: &Animal{ Name: "cat",
},
}
工厂模式
这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。 在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。并且,若将struct的首字母设为小写,则其他包下的程序访问不到,这时也可以通过工厂模式来实现:
package factory
/**
工厂设计模式
*/
// client 自定义结构体
// client首字母为小写,只能在factory中使用
type client struct {
Id string
name string
}
// GetName 跟Java类似
// 与上面一样,name字段小写其他包也无法直接使用,提供一个方法实现
func (c *client) GetName() string {
return c.name
}
// NewClient Factory
func NewClient(n string, s string) *client {
return &client{
Id: n,
name: s,
}
}
~ End ~