指针
和c/c++类似,但是go语言中指针不能进行偏移和运算,安全指针
&(取地址) *(根据地址取值)
nil(空指针)
make和new之前对比:make用于初始化slice,map,channel这样的引用类型
而new用于类型的内存分配,分配的值为类型0值,返回该类型指针
结构体
值传递
没有继承,但是可以通过组合来支持面向对象特性。
结构体中可以包括结构体,但是不能包括本身
简单demo
package mainimport "fmt"type person struct {name stringcity stringage int8
}func main() {//创建变量var p1 personp1.name = "pprof.cn"p1.city = "北京"p1.age = 18fmt.Printf("p1=%v\n", p1) //p1={pprof.cn 北京 18}fmt.Printf("p1=%#v\n", p1) //p1=main.person{name:"pprof.cn", city:"北京", age:18}var p2 = new(person)p2.name = "小明"p2.city = "武汉"p2.age = 10fmt.Printf("p2=%v\n", p2)fmt.Printf("p2=%#v\n", p2)//匿名结构体var user struct {Name stringAge int}//user := struct{// Name string// Age int//}user.Name = "pprof.cn"user.Age = 18fmt.Printf("%#v\n", user)
}
注意可见性,如果变量名首字母大写,在其他包可以访问(类似于public),否则只能在相同package中访问。
结构体的嵌套
对于Student中匿名嵌套的话,输出对应值,不需要s.p
package mainimport "fmt"type Person struct {name stringage int
}// Student 结构体嵌套和匿名嵌套
type Student struct {p Personschool stringscore int
}func main() {s := Student{p: Person{name: "张三", age: 18},school: "武汉大学",score: 100,}fmt.Println(s.p.name)
}
方法
-
- 绑定对象实例,只能为当前包内命名类型定义方法
方法定义:
func (recevier type) methodName(参数列表)(返回值列表){}参数和返回值可以省略
-
- 参数recevier任意命名,若方法未曾使用可省略参数名
- receive可以是T和*T类型。T不能是接口
- 不支持方法重载
- 可以使用value或pointer调用全部方法,编译器自动转换
简单demo
receive的类型T和*T之间对比
package mainimport "fmt"// 结构体
type User struct {Name stringEmail string
}// 假设T,产生副本不影响原变量
func (u User) Notify() {fmt.Printf("&u = %p\n", &u)fmt.Println("User 通知消息给", u.Name, " 邮箱为:", u.Email)u.Email = "Notify"
}//如果是*T,传入指针,就会影响u1
//func (u *User) Notify() {
// fmt.Printf("u = %p\n", u)
// fmt.Println("User 通知消息给", u.Name, " 邮箱为:", u.Email)
// u.Email = "Notify"
//}func main() {u1 := User{"user1", "user1.com"}fmt.Printf("&u1 = %p\n", &u1)u1.Notify()//u2 := &u1fmt.Println(u1) //不影响u1变量fmt.Println("*********")u2 := &User{"user2", "user2.com"}fmt.Printf("u2 = %p\n", u2)u2.Notify()fmt.Println(u2)}
func (u User) Notify() 方法时输出,传递副本因此地址不同,修改u不影响mian函数的对象值
func(u *User)Notify()传递指针,影响对象变量的值。
总结:方法就是与特定类型关联的函数,方便相当于c++当中class中的成员函数。
匿名字段demo
通过组合实现于override继承之后覆盖方法的效果。
// 结构体
type User struct {Name stringEmail string
}type Manager struct {UserStage string
}// User的方法
func (u *User) ToString() string {return fmt.Sprintf("%s %s\n", u.Name, u.Email)
}// Manager的方法
func (m *Manager) ToString() string {return fmt.Sprintf("%s %s %s\n", m.Name, m.Email, m.Stage)
}func main() {m := Manager{User: User{"李四", "manage.cn"}, Stage: "经理"}fmt.Println(m.ToString())fmt.Println(m.User.ToString())
}
接口
参考链接:https://www.cnblogs.com/chenny7/p/4497969.html
go语言接口详解:Go 语言接口的原理 | Go 语言设计与实现
interface抽象类型,是一组method的集合,类似于c++中的纯虚函数,如果一个类/对实现了interface中的所有方法就实现了interface接口。通过interface也就是可以实现多态特性。
简单demo
package mainimport "fmt"type Human struct {name stringage intphone string
}type Student struct {Human //匿名字段school stringloan float32
}type Employee struct {Human //匿名字段company stringmoney float32
}// Human实现SayHi方法
func (h Human) SayHi() {fmt.Printf("Hi, I am %s you can call me on %s\n", h.name, h.phone)
}// Human实现Sing方法
func (h Human) Sing(lyrics string) {fmt.Println("La la la la...", lyrics)
}// Employee重载Human的SayHi方法
func (e Employee) SayHi() {fmt.Printf("Hi, I am %s, I work at %s. Call me on %s\n", e.name,e.company, e.phone)
}//func (s Student) SayHi() {
// fmt.Printf("Hi, I am %s, I study in %s. Loan is %f\n", s.name,
// s.school, s.loan)
//}
//func (s Student) Sing(lyrics string) {
// fmt.Println("student Sing")
//}// Interface Men被Human,Student和Employee实现
// 因为这三个类型都实现了这两个方法
type Men interface {SayHi()Sing(lyrics string)
}func main() {mike := Student{Human{"Mike", 25, "222-222-XXX"}, "MIT", 0.0}paul := Student{Human{"Paul", 26, "111-222-XXX"}, "Harvard", 100}sam := Employee{Human{"Sam", 36, "444-222-XXX"}, "Golang Inc.", 1000}tom := Employee{Human{"Tom", 37, "222-444-XXX"}, "Things Ltd.", 5000}//定义Men类型的变量ivar i Men//i能存储Studenti = mikefmt.Println("This is Mike, a Student:")i.SayHi()i.Sing("November rain")//i也能存储Employeei = tomfmt.Println("This is tom, an Employee:")i.SayHi()i.Sing("Born to be wild")//定义了slice Menfmt.Println("Let's use a slice of Men and see what happens")x := make([]Men, 3)//这三个都是不同类型的元素,但是他们实现了interface同一个接口x[0], x[1], x[2] = paul, sam, mikefor _, value := range x {value.SayHi()}
}
通过调用接口相当于实现了多态。
可以继续实现嵌入接口。
空接口demo
空interface(interface{})不包含任何的method
所有的类型都实现了空interface
空接口可以存储任意类型
空interface对于描述起不到任何的作用(因为它不包含任何的method),但是空interface在我们需要存储任意类型的数值的时候相当有用,因为它可以存储任意类型的数值。它有点类似于C语言的void*类型。
// 定义a为空接口,作为函数参数,或者与slice,map等增强灵活性var a interface{}var i int = 5s := "Hello world"// a可以存储任意类型的数值a = ia = s
interface{}可断言类型
空接口断言demo
package mainimport "fmt"type Human struct {Name stringAge int
}type Student struct {HumanSchool string
}// 作为函数形参
func Show(a interface{}) {fmt.Printf("type of:%T value:%v\n", a, a)
}//判断当前类型
func JustifyType(i interface{}) {switch v := i.(type) {case string:fmt.Println("当前传入为string:", v)case int:fmt.Println("当前传入为int:", v)case Student:fmt.Println("当前为Student类型", v)default:fmt.Println("暂未预料")}
}func main() {i := "hello"Show(i)JustifyType(i)j := 10Show(j)JustifyType(j)Show(123)JustifyType(123)h := Human{"Human", 123}Show(h)JustifyType(h)k := Student{}Show(k)JustifyType(k)}