type Parent struct {
Name string
Age int
}
func (p Parent) String() string {
return fmt.Sprintf("Name:%s, Age:%d", p.Name, p.Age)
}
func StructCombine_1() {
var p1 = Parent{}
fmt.Println(p1)
var p2 = Parent{"name2", 2}
fmt.Println(p2)
var p3 = Parent{"name3",3,}
fmt.Println(p3)
var p4 = Parent{
"name4",
4}
fmt.Println(p4)
var p5 = Parent{
"name5",
5,
}
fmt.Println(p5)
var p6 = Parent{Name:"name6"}
fmt.Println(p6)
var p7 = Parent{Age:7}
fmt.Println(p7)
}
golang中的struct声明格式:
type StructName struct {
FieldName type,
...
}
上面代码中,是结构体变量的定义,注意初始化的方法,可以指定字段名进行初始化,也可以按照所有字段的进行赋值,如果使用指定字段方式赋值,没有指定的字段按照默认值处理,特别注意:逗号有的地方是不能少的,请以上面代码为主,查看哪些在}之前仍旧有逗号的,这就是不能少的情况。
上面让Parent实现了String() string接口,目的是为了按照我们指定的格式打印输出Parent变量的内容。
type Parent struct {
Name string
Age int
}
type Child struct {
Parent
Sex string
Age int
}
func (p Parent) String() string {
return fmt.Sprintf("Name:%s, Age:%d", p.Name, p.Age)
}
func (c Child) String() string {
return fmt.Sprintf("Name:%s, Sex:%s, p.Age:%d, c.Age:%d", c.Name, c.Sex, c.Parent.Age, c.Age)
}
func StructCombine_2() {
var p = Parent{
"P",
18,
}
var c = Child{
p,
"f",
20,
}
fmt.Println(p.Age)
fmt.Println(c.Age)
fmt.Println(c.Parent.Age)
}
=== RUN TestStructCombine_2
18
20
18
--- PASS: TestStructCombine_2 (0.00s)
PASS
没什么大问题。
type Parent struct {
Name string
Age int
}
type ParentNew struct {
Name string
Age int
}
type Child struct {
Parent
ParentNew
Sex string
Age int
}
func (p Parent) String() string {
return fmt.Sprintf("Name:%s, Age:%d", p.Name, p.Age)
}
func (p ParentNew) String() string {
return fmt.Sprintf("Name:%s, Age:%d", p.Name, p.Age)
}
func (c Child) String() string {
return fmt.Sprintf("Name:%s - %s, Sex:%s, p.Age:%d, c.Age:%d", c.Parent.Name, c.ParentNew.Name, c.Sex, c.Parent.Age, c.Age)
}
func StructCombine_3() {
var p = Parent{
"P",
18,
}
var pn = ParentNew{
"PN",
19,
}
var c = Child{
p,
pn,
"f",
20,
}
fmt.Println(c.Name)
}
在这段代码中,我们定义的Child组合了Parent和ParentNew,而Parent和ParentNew都定义了字段Name,Child没有定义字段Name,现在我们想通过c.Name访问Name字段,到底会访问Parent.Name还是ParentNew.Name?
我们看看运行效果:
.\struct_combine.go:52:15: ambiguous selector c.Name
Compilation finished with exit code 2
编译报错了!很明显,我们这样写的代码,golang也不知道如何选择。
其实golang的做法很简单:通过组合继承已有struct的能力,如字段,如果组合者Child已经有对应字段,则优先访问Child的字段,如果Child没有,则去组合的Parent中查找,直到查找到为止,如果从组合中的多个Parent中都查找到,这样是符合语法要求的,编译期间就报错,也就是说具体访问的字段在编译期间就已经确定下来了。
上面代码是探讨字段的情况,下面探讨一下方法的情况:
type Base struct {
}
type Comb struct {
Base
}
func (b Base) Work() {
fmt.Println("Base Work")
}
func (c Comb) Work() {
fmt.Println("Comb Work")
}
func StructCombMethod_1() {
var b = Base{}
var c = Comb{b}
b.Work()
c.Work()
}
=== RUN TestStructCombMethod_1
Base Work
Comb Work
--- PASS: TestStructCombMethod_1 (0.00s)
PASS
很明显,编译期间,这些接受者都是已经确定的了。
type Base struct {
}
type Comb struct {
Base
}
func (b Base) Work() {
fmt.Println("Base Work")
}
func (c Comb) Work() {
fmt.Println("Comb Work")
}
func (b Base) Play() {
fmt.Println("Base Play")
b.Work()
}
func StructCombMethod_2() {
var b = Base{}
var c = Comb{b}
c.Play()
}
=== RUN TestStructCombMethod_2
Base Play
Base Work
--- PASS: TestStructCombMethod_2 (0.00s)
PASS
由于Comb没有Play方法,c.Play()实际上是c.Base.Play(),此时接收者是Base,即b,自然结果就是
Base Play
Base Work
但其实Comb,即c是有Work方法的,按照支持多态的语言,是会调用Comb Work的,从这个也可以推断出:
golang是不支持多态的。
现在我们看看,Comb组合多个Base,看看会发生什么?
type Base struct {
}
type BaseNew struct {
}
type Comb struct {
Base
BaseNew
}
func (b Base) Work() {
fmt.Println("Base Work")
}
func (b BaseNew) Work() {
fmt.Println("BaseNew Work")
}
func (c Comb) Work() {
fmt.Println("Comb Work")
}
func (b Base) Play() {
fmt.Println("Base Play")
b.Work()
}
func (b BaseNew) Play() {
fmt.Println("BaseNew Play")
b.Work()
}
func StructCombMethod_3() {
var b = Base{}
var bn = BaseNew{}
var c = Comb{b,bn}
c.Play()
}
.\struct_comb_method.go:45:3: ambiguous selector c.Play
Compilation finished with exit code 2
跟字段一样,因为不支持多态,必须是编译时确定下来的。