12.包
一个包可以简单理解为一个存放.go
文件的文件夹。 该文件夹下面的所有go文件都要在代码的第一行添加如下代码,声明该文件归属的包。
- 一个文件夹下面直接包含的文件只能归属一个
package
,同样一个package
的文件不能在多个文件夹下。 - 包名可以不和文件夹的名字一样,包名不能包含
-
符号。 - 包名为
main
的包为应用程序的入口包,这种包编译后会得到一个可执行文件,而编译不包含main
包的源代码则不会得到可执行文件。
变量名首字母为大写则,它是共有的,对外可见
12.1不在同一个项目下
src
|_demo
|_main
|_main.go
|_go.mod
|_calc
|_add.go
|_sub.go
|_go.mod
12.2在同一目录下
src
|_pkgdemo
|_main.go
|_calc
|_add.go
|_go.mod
12.3init
执行顺序
init
函数是一个无参无返回值的函数
13.接口
接口(interface)是一种类型,一种抽象的类型。
interface
是一组method
的集合。接口做的事就像是定义一个规则,只要一台机器有洗衣服和甩干的功能,我就称它为洗衣机。不关心属性,只关心行为(方法)。
当看到一个接口类型的值时,不知道它是什么,唯一知道的是通过它的方法能做什么。
13.1定义
type 接口类型名 interface{
方法名1( 参数列表1 ) 返回值列表1
方法名2( 参数列表2 ) 返回值列表2
…
}
13.2实现接口条件
接口就是一个需要实现的方法列表
只要全部实现了接口中的方法,那么就实现了这个接口。
// 定义接口
type sayer interface {
say()
}
定义结构体
//定义man结构体
type man struct{
name string
}
// 定义woman结构体
type woman struct{
name string
age int8
}
因为sayer
接口里面有say
方法, 所以要给man woman
分别实现say
方法
// say方法,man
func (m man) say(){
fmt.Println("man say ...", m.name)
}
// say方法, woman
func (w woman) say(){
fmt.Println("woman say ...", w.name)
}
完整代码
//定义man结构体
type man struct{
name string
}
// 定义woman结构体
type woman struct{
name string
age int8
}
// 定义接口
type sayer interface {
say()
}
// say方法,man
func (m man) say(){
fmt.Println("man say ...", m.name)
}
// say方法, woman
func (w woman) say(){
fmt.Println("woman say ...", w.name)
}
// beat打
func beat (arg sayer){
arg.say()
}
func main(){
var m1 = man{name: "小芳"}
beat(m1)
var w1 = woman{name:"大黄", age: 18}
beat(w1)
}
13.3值接受者,指针接受者
13.3.1值接受者
//定义man结构体
type man struct{
name string
}
// say方法,man
func (m man) say(){
fmt.Println("man say ...", m.name)
}
var m1 = man{name: "小芳"}
beat(m1)
值接收者实现接口之后,不管是man结构体还是结构体指针*man类型的变量都可以赋值给该接口变量。因为Go语言中有对指针类型变量求值的语法糖,man指针m1
内部会自动求值*m1
。
13.3.2指针接受者
//定义man结构体
type man struct{
name string
}
// say方法,man
func (m *man) say(){
fmt.Println("man say ...", m.name)
}
var m1 = &man{name: "小芳"}
beat(m1)
13.4类型与接口关系
- 一个类型可以实现多个接口
// sayer接口
type sayer interface{
say()
}
//runner接口
type runer interface{
run()
}
//定义dog结构体
type dog struct{}
// dog实现sayer接口
func (d dog) say(){
fmt.Println("dog say...")
}
// dog实现runner接口
func (d dog) run(){
fmt.Println("dog run...")
}
func main(){
var x sayer
var y runer
var a = dog{}
x = a
y = a
x.say()
y.run()
}
-
多个类型可以实现一个接口
// sayer接口 type sayer interface{ say() }
//定义dog结构体 type dog struct{} //定义cat结构体 type cat struct{}
func (d dog)say(){ fmt.Println("dog say...") } // cat实现say() func (c cat)say(){ fmt.Println("cat say...") }
一个接口的方法,不一定需要由一个类型完全实现,接口的方法可以通过在类型中嵌入其他类型或者结构体来实现。
// WashingMachine 洗衣机接口
type WashingMachine interface {
wash()
dry()
}
// 甩干器
type dryer struct{}
// 实现WashingMachine接口的dry()方法
func (d dryer) dry() {
fmt.Println("甩干器")
}
// 海尔洗衣机
type haier struct {
dryer //嵌入甩干器
}
// 实现WashingMachine接口的wash()方法
func (h haier) wash() {
fmt.Println("洗衣机")
}
13.5接口嵌套
// Speaker 接口
type Speaker interface {
say()
}
// Runner 接口
type Runner interface {
move()
}
// 接口嵌套,得到动物接口,能说能动的就是动物
type animal interface {
Speaker
Runner
}
13.6空接口
空接口是指没有定义任何方法的接口。因此任何类型都实现了空接口。
空接口类型的变量可以存储任意类型的变量。
var x interface{}
y := "xiaosheng"
x = y
z := 18
x = z
c := make(map[string]int, 16)
x = c
//空接口作为函数参数
func test(t interface{}){
}
//用空接口实现可以保存任意类型的字典
var dic = make(map[string]interface{})
13.7断言
一个接口的值(简称接口值)是由一个具体类型
和具体类型的值
两部分组成的。这两部分分别称为接口的动态类型
和动态值
。
想获取一个接口里面的值可以用断言
x.(type)
var x int
v, ok = x.(int)
func main() {
var x interface{}
x = "Hello"
v, ok := x.(string)
if ok {
fmt.Println(v)
} else {
fmt.Println("类型断言失败")
}
}
func justifyType(x interface{}) {
switch v := x.(type) {
case string:
fmt.Printf("type of x is string,value is %v\n", v)
case int:
fmt.Printf("type of x is int is %v\n", v)
case bool:
fmt.Printf("type of x is bool is %v\n", v)
default:
fmt.Println("error ")
}
}