Go中没有面向对象的概念,若期望以面向对象的思路进行编程,需要基于结构体struct进行。
由于Go不支持OOP,故:
- Go中无专门class体系
- Go中无方法重载
- Go中无构造函数、析构函数
- Go中无this或self指向本身的指针
基于struct的伪OOP
结构体基本特征
- 结构体是值类型
- 结构体内存连续
package main
import "fmt"
type Person struct {
Name string
Age int
}
func main() {
//结构体变量
var p1 Person
fmt.Println(p1)
var p2 Person = Person{
Name: "",
Age: 0,
}
fmt.Println(p2)
//结构体指针
var p3 *Person = new(Person)
fmt.Println(p3)
var p4 *Person = &Person{}
fmt.Println(p4)
//不同于C语言中s.name s->name的使用方式
//Go中只有s.name方式,即使是指针,也是(*s).name的方式
//但是Go编译器对(*s).name进行了优化,允许指针s.name的写法,但实际上仍是指针的效果
}
结构体强转
package main
import "fmt"
type Person struct {
Name string
Age int
}
type Student struct {
Name string
Age int
}
func main() {
var p Person
var s Student = Student{ //也可以{"张三", 18}
Name: "张三",
Age: 18,
}
//结构体名字或者字段不一样即是不同类型的结构体,不同数据类型
//如果要强转,只能名字不一样,即要求结构体字段名称或者类型完全一样,包括字段顺序,即实质一致,要求内存分布一致
p = Person(s)
fmt.Println(p)
}
结构体tag
结构体tag,由反射机制处理
package main
import (
"encoding/json"
"fmt"
)
type Student struct {
Name string `json:"name,omitempty"`
Age int `json:"age,omitempty"`
}
func main() {
var s Student = Student{
Name: "张三",
Age: 18,
}
marshal, err := json.Marshal(s)
if err != nil {
}
//私有属性不能参与序列化
fmt.Println(string(marshal))
fmt.Println(marshal)
}
方法
func (receiver type) methodName (参数列表) (返回值列表) {
方法体
return
}
//1.receiver type表示方法与该类型绑定,即该类型变量可以调用该方法
//2.receiver type可以是结构体,也可以是其他类型,如int,不过好像不能直接用int
//3.return 非必须
//4.!!!建议receiver
方法和指定数据类型绑定,任意自定义类型都可以有方法,如int、float64,并非仅仅struct,这一点方法的含义更加宽泛
type A struct { Num int } func (a A) test() { //a A相当于融合了绑定关系和self或this,但又不仅仅局限于结构体,a名称任意 fmt.Println(a.Num) }方法同样适用大小写风格访问控制权限
如果某类型实现String方法,则fmt.Println默认使用该方法进行输出
根据指针简化原则,需要指针调用的方法和值调用的方法都可以传入指针或者值,即接受值类型,可以传入指针类型,接受指针类型,可以传入值类型,我感觉都应该接受指针类型吧
方法与函数最大的不同在于绑定关系
Go中没有构造函数和析构函数,一般使用工厂模式实现创建对象
注意:Go中结构体内部字段和方法是可以被包内访问的,不仅仅是在结构体所属方法中,这一点与Java等严密的封装不同
package main import "fmt" type Student struct { Name string age int } func main() { var s = Student{ Name: "张三", age: 18, } fmt.Println(s.Name, s.age) //张三 18 }
构造函数的替代->工厂模式
package main
import (
"fmt"
"gocode/testproject01/unit10/demo11/model"
)
func main() {
// 跨包创建结构体Student的实例:
// var s model.Student = model.Student{"丽丽", 10}
// s := model.student{"丽丽", 10}
// fmt.Println(s)
s := model.NewStudent("娜娜", 20)
fmt.Println(s)
}
封装
Go并非OOP严格封装,如不像Java那么严格
- 使用大小写风格访问控制权限
- 基于工厂模式创建对象,类似构造函数
- 使用get、set方法访问属性
- 特别注意:如果是在本包中,即使某一个函数与结构体无绑定关系,这个函数也是能访问结构体私有属性的,例如工厂模式实现函数,可能是一种模糊不清的“类静态方法”
继承
Go中基于结构体匿名字段方式实现继承
结构体可以使用匿名结构体属性所有的属性和方法,即包括公有或者私有
结构体的匿名属性可以是基本类型
支持多继承,使用多个匿名结构体属性即可
菱形继承问题必须指定匿名结构体属性
结构体属性可以为结构体类型,组合关系
type A struct {
a int
b string
c B
}
package main
import "fmt"
type Person struct {
Name string
Age int
}
func (p Person) String() string {
return fmt.Sprintf("Person %s %d", p.Name, p.Age)
}
type Student struct {
Person //匿名的Person属性 //如果此处为*Person,则下方赋值时需要传地址
int
}
func main() {
var s = Student{Person{ //赋值 //&Person{}
Name: "0",
Age: 0,
}, 0}
fmt.Println(s.Age, s.Person.Age)
s.Age = 1
fmt.Println(s.Age, s.Person.Age)
fmt.Println(s.String())
}
多态
多态
Go的多态是基于接口实现的
//基于多态的数组
var arr [3]SayInterface
arr[0] = American{"rose"}
arr[1] = Chinese{"张三"}
arr[2] = Chinese{"李四"}
接口
Go中的接口是一种协议接口,即若A接口包含B、C方法描述,而D类型实现了接口A的所有方法,即B、C方法,则可以说D实现了接口A
只要是自定义数据类型就可以实现接口,并不一定是struct
一个自定义类型可以实现多个接口
接口是引用类型,默认值为nil
空接口,空接口没有任何方法,所有类型都实现了空接口,即空接口可以指向任意类型变量
type 接口名称 interface {
method1(参数列表) 返回值列表
method1(参数列表) 返回值列表
...
}
package main
import "fmt"
type SayInterface interface {
Say()
}
func Say(say SayInterface) {
say.Say()
}
type Chinese struct {
}
func (chinese Chinese) Say() {
fmt.Println("你好")
}
type American struct {
}
func (american American) Say() {
fmt.Println("Hello")
}
type Integer int
func (Integer) Say() {
//1.绑定类型可以省略名字,但这样就无法使用对象本身了
//2.任意自定义类型就可以实现接口
fmt.Println(1)
}
func main() {
c := Chinese{}
a := American{}
c.Say()
a.Say()
//函数式
Say(c)
Say(a)
var i SayInterface = Integer(1) //多态
i.Say()
}
接口继承,与结构体继承方式一致,用于接口扩展