怎样做网站的用户分析百度学术官网论文查重免费
6. 类型系统
参考 李文塔<<Go语言核心编程>>,非原创
6.1 命名类型和未命名类型

## 6.2 类型赋值
// a是类型T1的一个变量,或者a就是一个字面常量或者nil
//如果以下的语句可以执行,则称之为T1可以赋值给T2类型
var b T2 = a
a可以赋值给变量必须满足如下条件的一个
- T1和T2的类型完全相同
- T1和T2都有相同的底层类型,并且其中有一个是类型字面量
package mainimport "fmt"// 定义了一个新类型Map,它的底层类型是map[string]string
type Map1 map[string]string// 给新类型Map 扩展了一个Print方法
func (m Map1) Print() {for _, key := range m {fmt.Println(key)}
}func main() {mp := make(map[string]string, 10)mp["hi"] = "data"// mp 和 ma有相同的底层类型, mp是未命名类型, 可以直接赋值var ma Map1 = mpfmt.Println(ma["hi"])}
package main/*** 不可已赋值 */
import "fmt"// 定义了一个新类型Map,它的底层类型是map[string]string
type Map2 map[string]string// 给新类型Map 扩展了一个Print方法
func (m Map2) Print() {for _, key := range m {fmt.Println(key)}
}type Map21 Map2// 给新类型Map 扩展了一个Print方法
func (m Map21) Print() {for _, key := range m {fmt.Println(key)}
}func main() {mp := make(map[string]string, 10)mp["hi"] = "data"// mp 和 ma有相同的底层类型, mp是未命名类型, 可以直接赋值var ma Map2 = mpfmt.Println(ma["hi"])// ma 和 maa都有相同底层类型map[string]string, 但是不满足其中一个是类型字面量的条件// var maa Map21 = ma// 因为底层类型一样,可以强制类型转换var maa Map21 = (Map21) (ma)
}
- T2是接口类型,T1是具体类型,T1的方法集是T2方法集的超集
package mainimport "fmt"// 定义了一个新类型Map,它的底层类型是map[string]string
type Map3 map[string]string// 给新类型Map 扩展了一个Print方法
func (m Map3) Print() {for _, key := range m {fmt.Println(key)}
}func (m Map3) Print2() {for _, key := range m {fmt.Println(key)}
}func main() {mp := make(map[string]string, 10)mp["hi"] = "data"// mp 和 ma有相同的底层类型, mp是未命名类型, 可以直接赋值var ma Map3 = mp// Map实现了Print(), 所以可以复制给接口类型变量var i interface{Print()} = mai.Print()}
- a是nil,T2是复合类型
- a是一个字面常量值,可以用来表示类型T的值
package mainimport "fmt"type Map4 map[string]string// 给新类型Map 扩展了一个Print方法
func (m Map4) Print() {for _, key := range m {fmt.Println(key)}
}func main() {var ma Map4 = make(map[string]string)ma["hi"] = "chs"
}
6.3 类型方法
类型方法是Go语言实现面向对象编程的基础
6.3.1 自定义类型
自定义类型,并且进行初始化
package mainimport "fmt"type Person struct {name stringage int// 匿名字段*string
}func main() {// 空的初始化a := Person{}fmt.Println(a.age)a1 := Person{name: "chs",age: 15,}fmt.Println(a1.age)
}
6.3.2 方法
自定义类型是对类型的数据的扩充,仅仅是对数据的扩充是不够的,还需要对行为进行扩充,方法就是对于类型的行为的扩充。 方法将显式的将对象的实例或者指针作为函数的第一个参数,并且参数名可以自己指定,这个对象实例或指针称为方法的接收者。
//类型方法接收者是值类型
func (t TypeName)MethodName(ParamList)(Returnlist){// body
}
// 类型方法接收者是指针类型
func (t *TypeName)MethodName(ParamList)(Returnlist) {
}
类型方法的特点如下:
- 可以为命名类型增加方法,非命名类型不能自定义方法
- 为类型增加方法有一个限制,就是方法的定义必须和类型的定义在同一个包中。不能为预声明类型增加方法,因为他们是全局的
- 方法的命名空间可见性和变量一样,大写开头的方法在包外访问,否则在包内。
- 使用type自定义类型是一个新类型,不能继承旧类型方法,但是可以支持旧类型的运算操作
type MyInt intvar a MyInt := 10
var b MyInt := 20
c := a + b
6.3.3 方法调用
- 一般调用
package mainimport "fmt"type T struct {a int
}func (t T) Get() int {return t.a
}// 为什么这里要传指针呢?
// 这里如果不传指针,修改之后,读取的数据是无效的
func (t *T) Set(i int) {t.a = i
}func main() {var t = &T{}fmt.Println(t.Get())t.Set(2)fmt.Println(t.Get())
}
- 方法值
package mainimport "fmt"type T1 struct {a int
}func (t T1) Get() int {return t.a
}func (t *T1) add() {t.a++
}func (t *T1) Print() {fmt.Printf("%p, %v, %d n", t, t, t.a)
}func main() {var t = &T1{}f := t.addf()t.Print()f()t.Print()
}
- 方法表达式
package mainimport "fmt"type T3 struct {a int
}func (t T3) Get() int {return t.a
}// 为什么这里要传指针呢?
func (t *T3) Set(i int) {t.a = i
}func main() {var t = T3{a:1}t.Get()T3.Get(t)f1 := T3.Getf1(t)(*T3).Set(&t, 1)// 方法表达式f3 := (*T3).Setf3(&t, 1)}
- 组合
package mainimport "fmt"type X struct {a int
}type Y struct {Xb int
}func main() {x := X{a: 1}y := Y{X: x,b: 2,}fmt.Println(y.a)
}
参考<<Go语言核心编程>>