结构体和方法
在Go语言中,没有和java一样的class,只有结构体。和其他语言相比,Go语言放弃了大量面向对象的特性。
结构体
定义
type 结构体名 struct {
属性名 属性类型
属性名 属性类型
...
}
type Leg struct {
length int
}
type Hand struct {
length int
}
type Face struct {
name string
}
type Other struct {
name string
}
type Person struct {
name, gender string
age int
legs []Leg
hands []Hand
face Face
other *Other
}
实例化方法
正常的实例化
person := Person{
name: "姓名",
age: 18,
gender: "male",
}
使用new
person := new(Person)
person.name = "name"
使用&
person := &Person{}
来个复杂点的例子,像写json一般:
func TestStruct() {
person := Person{
name: "姓名",
age: 18,
gender: "male",
legs: []Leg{
{
length: 10,
},
{
length: 10,
},
},
hands: []Hand{
{
length: 5,
},
{
length: 5,
},
},
face: Face{
name: "face",
},
other: &Other{
name: "other",
},
}
fmt.Printf("person: %v\n", person)
}
输出:
person: {姓名 male 18 [{10} {10}] [{5} {5}] {face} 0xc00004e230}
结构体的方法-组合函数
在 Go 语言中,我们无法像其他语言的class一般,在结构体(类)内定义方法,Go使用组合函数的方式来为结构体定义结构体方法。
func (person Person) say() {
fmt.Printf("my name is: %v\n", person.name)
}
say
是方法名,(person Person)
表示将say方法与Person绑定。
方法的参数传递
func (Person Person) rename() {
Person.name = "新名字"
}
结果:
person.say() // my name is: 姓名
person.rename()
person.say() // my name is: 姓名
上面那个简单例子,无法在方法里面改变实例person
的属性,因为他是值拷贝。所以这里需要用到指针。
func (Person *Person) rename() {
Person.name = "新名字"
}
结果:
person.say() // my name is: 姓名
person.rename()
person.say() // my name is: 新名字
内部方法和外部方法
在 Go 语言中,函数名的首字母大小写非常重要,它被来实现控制对方法的访问权限。
- 当方法的首字母为大写时,这个方法对于所有包都是Public,其他包可以随意调用
- 当方法的首字母为小写时,这个方法是Private,其他包是无法访问的。
Go里的“继承”-组合
用组合实现继承
Go本身不支持继承,但我们可以通过组合去实现类似继承的效果,如下:
type Worker struct {
workType string
Person
}
Person
是上面定义的struct,这里的Person会作为一个匿名变量。
我们可以直接调用say(),也可以调用Person.say()
worker1 := Worker{workType: "coder", Person: person}
worker1.say() // my name is: 姓名
worker1.Person.say() // my name is: 姓名
实现方法重载
func (person Person) say() {
fmt.Printf("my name is: %v\n", person.name)
}
func (worker *Worker) say() {
worker.Person.say()
fmt.Printf("worker name is: %v\n", worker.name)
}
执行worker1.say()
,结果为:
my name is: 姓名
worker name is: 姓名
接口和多态
定义接口
使用type关键字来定义接口
type Product interface {
calculatePrice() int
getQuantity() int
}
实现接口
如果有一个类型/结构体A,实现了一个接口B的所有方法, 那么我们就可以称A实现了B接口。
type Product interface {
calculatePrice() int
getQuantity() int
}
type Keyboard struct {
name string
quantity int
price int
}
func (keyboard *Keyboard) calculatePrice() int {
payment := keyboard.price * keyboard.quantity
fmt.Printf("payment: %v\n", payment)
return payment
}
func (keyboard *Keyboard) getQuantity() int {
fmt.Printf("keyboard.quantity: %v\n", keyboard.quantity)
return keyboard.quantity
}
实现多态
package interfacetest
import "fmt"
func Execute() {
products := []Product{}
products = append(products, &Keyboard{name: "keyboard", quantity: 2, price: 10})
products = append(products, &Mouse{name: "mouse", quantity: 3, price: 20})
for _, p := range products {
p.getQuantity()
p.calculatePrice()
}
}
type Product interface {
calculatePrice() int
getQuantity() int
}
type Keyboard struct {
name string
quantity int
price int
}
func (keyboard *Keyboard) calculatePrice() int {
payment := keyboard.price * keyboard.quantity
fmt.Printf("%v payment: %v\n", keyboard.name, payment)
return payment
}
func (keyboard *Keyboard) getQuantity() int {
fmt.Printf("keyboard.quantity: %v\n", keyboard.quantity)
return keyboard.quantity
}
type Mouse struct {
name string
quantity int
price int
}
func (mouse *Mouse) calculatePrice() int {
payment := mouse.price * mouse.quantity
fmt.Printf("%v payment: %v\n", mouse.name, payment)
return payment
}
func (mouse *Mouse) getQuantity() int {
fmt.Printf("mouse.quantity: %v\n", mouse.quantity)
return mouse.quantity
}
运行结果:
keyboard.quantity: 2
keyboard payment: 20
mouse.quantity: 3
mouse payment: 60
完整的代码实例可参考: gitee代码仓库