go语法-结构体和接口
看go代码,非常考验对go语言的理解程度。觉得费解的地方,肯定是有不熟悉的语法。
3,接口与实现
type Error interface { Error() string Stacktrace() Error Trace(offset int, format string, args ...interface{}) Error Data() interface{} }
type A struct { data interface{} msgtraces []msgtraceItem stacktrace []uintptr } function newA(data interface{}) { return &A{ data: data msgtraces: nil stacktrace: nil } } func (a A) Error() string { return fmt.Sprintf("#{err}"); } func (a A) Stacktrace() Error { return a; // 因为a是实现Error接口的结构体的实例 } func (a A) Trace() Error { return a; } func (a A) Data() interface{} { return a.data; }
3,接口
Go 语言的接口设计是非侵入式的,接口编写者无须知道接口被哪些类型实现。而接口实现者只需知道实现的是什么样子的接口,但无须指明实现哪一个接口。编译器知道最终编译时使用哪个类型实现哪个接口,或者接口应该由谁来实现。
a := PhoneConnecter{"PhoneConnecter"}
a.Connect()
Disconnect(a)
func Disconnect(usb USB) {
if pc, ok := usb.(PhoneConnecter); ok {
fmt.Println("Disconnect", pc.name)
return
}
fmt.Println("Unknown device")
}
// 改造为空接口
func Disconnect(usb interface{}) {
switch v := usb.(type)
case PhoneConnecter
fmt.Println("Disconnect", v.name)
defult:
fmt.Println("Unknown device")
}
接口转换可以降级。
比如 type struct TVConnect {
name string
}
是不能强制转换为USB,因为没有实现USB。
1,结构体
结构体是不同数据类型的集合,聚合数据类型。数组是相同数据类型的集合。
go中没有类,继承,只保留了结构体及组合。
初始化的5种方法:
type struct Person {
name string
age int
sex string
address string
}
方法1:
var p1 Person
p2.name = ""
fmt.Printf(p2);
方法2:
p3: = Person{}
p3.name = ""
fmt.Printf(p3);
方法3://常用
p4: = Person{
name: xx
}
fmt.Printf(p4);
方法4:
p5 := Person{"", } // 顺序不能写错
方法5:New // 指针类型
p1 := Person{"1", }
p2 := p1 // 深拷贝
p2.name = "2"
//结论是p1, p2两个空间。修改的时候两个互不干预。
var pp1 * Person
pp1 = &p1 // 浅拷贝
fmt.PrintLn(*pp1)
pp1.name = "3"
fmt.PrintLn(pp1) // &{}
fmt.PrintLn(p1) // {}
pp2 := new(Person) //指针类型
// (*pp2).name
pp2.name // 简写
结构体的指针
值类型:int,float,bool,string,array,struct
引用类型:slice,map,function,pointer
但常用指针: new (),不是nil,空指针,指向了新分配的类型的内存空间,里面存储的零值。
结构体是值类型:
p1 := Person{name:"", age:"", sex:"", address:"北京市"}
p2 := p1
p1.name = "newName"
p1变了,但p2没变。
默认是深copy,如果想浅copy,定义指针。
pp1 := &p1
pp1.name = "王五"; //这样原始数据p1就被修改了。
内置的pp2:=new(Person)
结构体是值类型,往往借助于指针来操作(通过new),new之后并不是nil,而是开辟了一段内存空间,存储零值。
newStruct是构造函数
结构体嵌套
package main import "fmt" type A struct { ax, ay int } type B struct { A bx, by float32 } func main() { b := B{A{1, 2}, 3.0, 4.0} fmt.Println(b.ax, b.ay, b.bx, b.by) // 嵌入结构体的成员,可以通过外部结构体的实例直接访问。 fmt.Println(b.A) }
匿名结构体,匿名字段(一个结构体的字段没有字段名)
匿名结构体类比匿名函数,平常不常用。
s2:= struct {
name string
age int
} {
name:"李四"
age:"19"
}
匿名结构体字段
type Worker struct {
string
int
}
w2:=Work{"li", 32}
w2.string
w2.int
匿名字段类型不能重复,否则冲突。
还可以把另一个结构体作为匿名字段。
结构体嵌套
最初始的理解是对的。
type Book struct {
bookName string
price float64
}
type Student struct {
name string
age int
book Book
}
b1 := Book{}
b1.bookName = "西游记"
b1.price = 45.8
s1 := Student{}
s1.name = ""
s1.age =
s1.book = b1;
s1.book.bookName
s1.book.price
也可以
s2:=Student{name:"", age: 19, book: Book{bookName:"", price:89.,7}}
实际结构体的嵌套需要定义指针,而不是值复制。
book := Book{bookName:"", price:89.,7}
s2:=Student{name:"", age: 19, book: &book}
go中的面向对象
用结构体嵌套来实现类的继承。
提升字段:子结构体是匿名字段的时候。可以直接使用子结构体的字段,不需要多点一次子结构体的名字。
注:代码里非常常用。
总结:嵌套分为两种情况:一种是模拟继承,is a子类是特殊的父类。可以直接访问子类的字段。
k另一种情况是:模拟面向对象的聚合关系,has a,一个类拥有另一个类。不能直接访问子类的字段。