湖南网站营销推广设计,贺兰县住房城乡建设局网站,推销网站,wordpress跳转到老域名结构体及其方法结构体类型表示的是实实在在的数据结构。一个结构体类型可以包含若干个字段#xff0c;每个字段通常都需要有确切的名字和类型。结构体类型也可以不包含任何字段#xff0c;这样并不是没有意义的#xff0c;因为我们还可以为这些类型关联上一些方法#xff0…结构体及其方法结构体类型表示的是实实在在的数据结构。一个结构体类型可以包含若干个字段每个字段通常都需要有确切的名字和类型。结构体类型也可以不包含任何字段这样并不是没有意义的因为我们还可以为这些类型关联上一些方法这里你可以把方法看做是函数的特殊版本。方法和函数不同它需要有名字不能被当作值来看待最重要的是它必须隶属于某一个类型。方法所属的类型会通过其声明中的接收者(receiver)声明体现出来。方法隶属的类型其实并不局限于结构体类型但必须是某个自定义的数据类型并且不能是任何接口类型。方法的使用接收者声明就是在关键字func和方法名称之间的那个圆括号包裹起来的内容其中必须包含确切的名称和类型字面量。这个接收者的类型其实就是当前方法所属的那个类型而接收者的名称则用于在当前方法中引用它所属的类型的当前值。举个例子// AnimalCategory 代表动物分类学中的基本分类法type AnimalCategory struct {kingdom string // 界phylum string // 门class string // 纲order string // 目family string // 科genus string // 属species string // 种}func (ac AnimalCategory) String() string {return fmt.Sprintf(%s%s%s%s%s%s%s,ac.kingdom,ac.phylum,ac.class,ac.order,ac.family,ac.genus,ac.species)}在Go语言中我们可以通过为一个类型编写名为String的方法来自定义该类型的字符串表示形式。这个String方法不需要任何参数声明但需要有一个string类型的结果声明。所以在再用fmt包里的函数时会打印出上面自定义的字符串表示形式而无需显示的调用它的String方法。我们可以把结构体类型中的一个字段看作是它的一个属性或者一项数据再把隶属于它的一个方法看作是附加在其中数据之上的一个能力或者一项操作。将属性及其能力(或者说数据及其操作)封装在一起是面向对象编程(object-orientedprogramming)的一个主要原则。匿名字段下面声明了一个结构体类型Animal有两个字段一个是string类型的scientificName。另一个字段声明中只有AnimalCategory就是上面示例的那个结构体的名字type Animal struct {scientificName string // 学名AnimalCategory // 动物基本分类}字段声明AnimalCategory代表了Animal类型的一个嵌入字段。Go语言规范规定如果一个字段的声明中只有字段的类型名而没有字段的名称那么它就是一个嵌入字段也可以被称为匿名字段。我们可以通过此类型变量的名称后跟“.”再后跟嵌入字段类型的方式引用到该字段。也就是说嵌入字段的类型既是类型也是名称。强调一下Go语言中没有继承的概念它所做的是通过嵌入字段的方式实现了类型之间的组合。简单来说面向对象编程中的继承其实是通过牺牲一定的代码简洁性来换取可扩展性而且这种可扩展性是通过侵入的方式来实现的。类型之间的组合采用的是非声明的方式我们不需要显式地声明某个类型实现了某个接口或者一个类型继承了另一个类型。同时类型组合也是非侵入式的它不会破坏类型的封装或加重类型之间的耦合。我们要做的只是把类型当做字段嵌入进来然后坐享其成地使用嵌入字段所拥有的一切。如果嵌入字段有哪里不合心意我们还可以用“包装”或“屏蔽”的方式去调整和优化。值方法和指针方法方法的接收者类型必须是某个自定义的数据类型(不能是接口)。所谓的值方法就是接收者类型是非指针的自定义数据类型的方法。之前的示例中的方法都是值方法。下面的这个就是指针方法func (a *Animal) SetScientificName(name string) {a.scientificName name}方法的接受者类型是*Animal是一个指针类型。这时Animal可以被叫做*Animal的基本类型。可以认为指针类型的值就是指向某个基本类型值的指针。指针方法就是接收者类型是上述指针类型的方法。值方法和指针方法之间的不同点值方法的接收者是方法所属类型的一个副本。在方法内对副本的修改一般不会提现在原值上除非这个类型本身是某个引用类型。而指针方法内对的修改是一定会提现在原值上的。严格来讲通过值只能调用到值方法通过指针只能调用到指针方法。但是Go会适时的进行自动的转义使得通过值也能调用到它的指针方法。比如Animal.SetScientificName(Duck)会自动转义为(Animal).SetScientificName(Duck)即先取指针值然后再在改指针值上调用指针方法。这条和接口相关一个类型的方法集合中有哪些方法与它能实现哪些接口类型是息息相关的。如果一个基本类型和它的指针类型的方法集合是不同的那么它们具体实现的接口类型的数量就也会有差异除非这两个数量都是零。比如一个指针类型实现了某某接口类型但它的基本类型却不一定能够作为该接口的实现类型。这个是验证上述差异的示例package mainimport fmttype Cat struct {name string // 名字。scientificName string // 学名。category string // 动物学基本分类。}func New(name, scientificName, category string) Cat {return Cat{name: name,scientificName: scientificName,category: category,}}func (cat *Cat) SetName(name string) {cat.name name}func (cat Cat) SetNameOfCopy(name string) {cat.name name}func (cat Cat) Name() string {return cat.name}func (cat Cat) ScientificName() string {return cat.scientificName}func (cat Cat) Category() string {return cat.category}func (cat Cat) String() string {return fmt.Sprintf(%s (category: %s, name: %q),cat.scientificName, cat.category, cat.name)}func main() {cat : New(little pig, American Shorthair, cat)cat.SetName(monster) // (cat).SetName(monster)fmt.Printf(The cat: %s\n, cat)cat.SetNameOfCopy(little pig)fmt.Printf(The cat: %s\n, cat)type Pet interface {SetName(name string)Name() stringCategory() stringScientificName() string}_, ok : interface{}(cat).(Pet)fmt.Printf(Cat implements interface Pet: %v\n, ok) // false_, ok interface{}(cat).(Pet)fmt.Printf(*Cat implements interface Pet: %v\n, ok) // true}这里牵涉到了接口的知识点所以这个例子和下面的内容下一篇还会再讲一遍。最后的2行输出的内容说明cat没有实现Pet的接口而cat是实现了Pet的接口。因为要实现Pet接口需要实现接下的那4个方法。而Cat类型没有实现SetName方法所以cat没有实现Pet接口。代码中SetName方法是通过*Cat实现的另外其他的3个方法都已经通过Cat实现了通过*Cat也能调用(差异的第2条)所以只有指针方法实现了Pet接口的所有方法。