网站地址栏图标怎么做,网站建设主机类型怎么选,长沙县住房和城乡建设局网站,WordPress设置API方法 概述1. 方法定义2. 值方法、指针方法3. 方法集合 匿名字段表达式自定义 error 上一篇#xff1a;延迟调用#xff08;defer#xff09; 概述
1. 方法定义 func (receiver T) 方法名(参数列表) (返回值列表)#xff5b;#xff5d;receiver#xff1a;接收者参数名T… 方法 概述1. 方法定义2. 值方法、指针方法3. 方法集合 匿名字段表达式自定义 error 上一篇延迟调用defer 概述
1. 方法定义 func (receiver T) 方法名(参数列表) (返回值列表)receiver接收者参数名T方法所属类型Golang 方法总是绑定对象实例并隐式地将实例作为第一实参receiver。
1. 只能为当前包内local命名类型定义方法。
2. 参数 receiver 可以任意命名若方法中未使用可省略参数名。
3. 参数 receiver 类型可以是 T值方法或 *T指针方法基类型 T 不能是接口或指针。
4. 不支持方法重载receiver 只是参数签名的组成部分。
5. 可用实例 value值或 pointer指针调用全部方法编译器自动转换。package mainimport fmttype Person struct {name string
}// 定义指针方法*T
func (p *Person) SetName(name string) {p.name name
}// 定义值方法T
func (p Person) GetName() string {return p.name
}func (p *Person) String() string {return fmt.Sprintf(Person: %s, p.name)
}// 1.只能为当前包内命名类型定义方法
// 报错cannot define new methods on non-local type float64
func (f float64) Add(i, j float64) float64 {return i j
}type Iter interface{}
// 3.receiver 类型不能是 poiter 或 interface
// 报错 invalid receiver type iter (pointer or interface type)
func (Iter) SayType() {}func main() {p : Person{} // 值类型调用类型方法前需要定义一个类型的值或指针p.SetName(国庆) // 值类型调用指针方法fmt.Println(p.name)p2 : p // 指针类型p.name 国强fmt.Println(p2.GetName()) // 指针类型调用值方法
}
2. 值方法、指针方法 值方法 接收者 receiver 是一个值而非指针 该方法操作对应 receiver 的值的副本即时使用了指针调用方法但方法的接受者是值类型所以方法内部操作还是对副本的操作而不是指针操作。 package mainimport (fmt
)type Person struct {name string
}// 指针方法
func (p *Person) SetName(name string) {fmt.Printf(指针 - addr: %p %T\n, p, p)p.name name
}// 值方法
func (p Person) SetNameByValue(name string) {fmt.Printf(值 %p %T \n, p, p)p.name name
}func main() {p : Person{中华} // 指针值fmt.Printf(P addr: %p, \n\n, p) p.SetNameByValue(华夏) // 调用值方法// p.name 中华并未改变说明 p.SetNameByValue 复制了 p 的副本进行操作。fmt.Printf(name %s\n\n, p.name)p.SetName(国庆)fmt.Printf(name %s\n, p.name) // name 国庆
} 以上代码输出如下可以看出 p.SetName指针方法中 p 的地址和 main 中 p 的地址相同为同一变量且该方法给 p.name 重新赋值后main 中 p.name 跟着改变。p.SetNameByValue值方法中 p 的地址和 main 中 p 的地址不同且调用该方法给 p.name 重新赋值后main 中 p.name 并未改变。 P addr: 0xc000024070,值 0xc000024080 test.Person
name 中华指针 - addr: 0xc000024070 *test.Person
name 国庆指针方法接收者 receiver 是一个指针 与值方法相反当接受者是指针时即使用值类型调用那么方法内部也是对指针的操作。 func main() {p : Person{中华} // 值类型fmt.Printf(P addr: %p, \n\n, p) p.SetNameByValue(华夏)fmt.Printf(name %s\n\n, p.name) // name 中华p.SetName(国庆)// 即时 p 为值类型调用指针类型时指针方法内部也是对指针操作。fmt.Printf(name %s\n, p.name) // name 国庆
} 方法与函数 方法可以看做一种特殊特定类型变量的函数。 文章开头讲过方法总是绑定对象实例并隐式地将实例作为第一实参 receiver。 func (p *Person) SetName(name string) {} 等同于 func SetName(p *Person, name string) { } 方法与函数的区别 函数不属于任何类型而方法属于特定的类型变量receiver的函数。接收者 receiver 无论是值类型或指针类型都可以调用全部方法。但函数中参数类型为值类型则只能将值类型作为参数传递参数类型为指针则只能将指针类型作为参数传递。 type Person struct {name string
}// 指针方法
func (p *Person) SetName(name string) {p.name name
}
// 该函数与方法 p.SetName 相同
func SetName(p *Person, name string) {p.name name
}// 值方法
func (p Person) GetName() {return p.name
}
// 该函数与方法 p.GetName 相同
func GetName(p Person) string {return p.name
}func main() {p : Person{}// 接收者 p 为值类型可以调用指针类型方法。反之亦然。p.SetName(中国) fmt.Println(p.GetName())// 函数中参数为指针类型只能以指针类型作为参数反之同理。SetName(p, 华夏) fmt.Println(p.GetName())fmt.Println(p.GetName(), GetName(p))
}3. 方法集合
每个类型都有与之关联的方法集这会影响到接口实现规则。一个类型的值类型的方法集合中仅包含它的所有值方法类型 T 方法集包含全部 receiver T 方法。一个类型的指针类型的方法集合囊括了所有值方法和所有指针方法类型 *T 方法集包含全部 receiver T *T 方法。
func main() {p : Person{} // 值类型m : reflect.TypeOf(p)for i : 0; i m.NumMethod(); i {method : m.Method(i)fmt.Println(Value Method:, method.Name, method.Type)}p2 : Person{} // 指针类型m reflect.TypeOf(p2)for i : 0; i m.NumMethod(); i {method : m.Method(i)fmt.Println(Pointer Method:, method.Name, method.Type)}
}输出
Value Method: GetName func(test.Person) string
Pointer Method: GetName func(*test.Person) string
Pointer Method: SetName func(*test.Person, string)
Pointer Method: String func(*test.Person) string匿名字段
参考结构体章节8.结构体匿名字段
Golang 中类型的成员字段在声明时没有字段名而只有类型那么它就是一个嵌入字段也可以被称为匿名字段。 匿名字段默认采用类型作为字段名要求字段名称必须唯一且一个类型中同种类型的匿名字段只能有一个。 任何类型都可以作为匿名字段。 匿名结构体成员可直接访问当多个匿名结构体内存在相同字段时为了避免歧义需要指定具体的内嵌结构体的字段。 推荐使用匿名方式嵌套结构体。 通过匿名字段可以实现继承实现“override”。 不可递归循环嵌套你中有我我中有你。
表达式
package mainimport fmttype Person struct {name string
}func (p *Person) SetName(name string) {p.name name
}func (p Person) SetNameByValue(name string) {p.name name
}func (p Person) GetName() string {return p.name
}func main() {p : Person{Tom}fmt.Println(p.GetName()) // 直接调用mVal : p.GetName // 隐式传递此时复制了pmExp : (*Person).GetName // 显式传递p.SetName(Jerry)fmt.Println(mVal(), mExp(p), p.GetName()) // Tom Jerry JerrymExp2 : (*Person).SetNameByValue // 值方法此时依然会复制 pmExp2(p, Lucy)fmt.Println(mExp(p), p.GetName()) // Jerry JerrymExp3 : (*Person).SetNamemExp3(p, Lucy)fmt.Println(mExp(p), p.GetName()) // Lucy Lucy
}
自定义 error
package mainimport (fmtostime
)type CustomError struct {path stringop stringcreateTime stringmessage string
}func (e *CustomError) Error() string {return fmt.Sprintf(%s %s %s: %s, e.createTime, e.op, e.path, e.message)
}func newError(path, op, msg string) *CustomError {return CustomError{path: path,op: op,createTime: time.Now().Format(2006-01-02 15:04:05),message: msg,}
}func Open(fname string) (err error) {f, err : os.Open(fname)if err ! nil {err newError(fname, open, err.Error())return}defer func() {if f.Close() ! nil {err newError(fname, close, err.Error())}}()return nil
}func main() {err : Open(./test/test.txt)fmt.Println(err)
}