Golang通脉之编制概略

2026-07-21 03:51:44/时尚/6157 阅读

编制和领受者

Go言语中的通脉编制(Method)是一种感染于特定圭表类型变量的函数  。这类特定圭表类型变量叫做领受者(Receiver)  。编制概领受者的通脉定见就近似于其他言语中的this或 self 。

Go 言语中同时有函数和编制。编制概逐浅近例就是通脉一个包含了领受者的函数 ,领受者可所以定名圭表类型或筹划体圭表类型的编制概一个值或是一个指针 。全数给定圭表类型的通脉编制属于该圭表类型的编制集

编制只是一个函数,它带有一个出格的编制概领受器圭表类型  ,它是通脉在func关头字和编制名之间编写的 。领受器可所以struct圭表类型或非struct圭表类型 。编制概领受方可以在编制内部访谒  。通脉

编制能给用户自定义的编制概圭表类型添加新的行动 。它和函数的通脉分辨在于编制有一个领受者,给一个函数添加一个领受者,编制概那么它就变成了编制。通脉领受者可所以值领受者 ,也可所以指针领受者。

在调用编制的时辰  ,值圭表类型既可以调用值领受者的编制 ,也可以调用指针领受者的编制;指针圭表类型既可以调用指针领受者的编制,也可以调用值领受者的编制  。

也就是说,非论编制的领受者是甚么圭表类型 ,该圭表类型的值和指针都可以调用 ,不必严格契合领受者的圭表类型 。

编制的定义格式以下:

func (t Type) methodName(parameter)(return) {   }

个中

  • t :领受者中的参数变量名在定名时,官方建议独霸领受者圭表类型称号首字母的小写 ,而不是self、this之类的定名。
  • Type:领受者圭表类型和参数近似,可所以指针圭表类型和非指针圭表类型 。
  • methodName 、parameter  、return :具体格式与函数定义不异。
//Person 筹划体type Person struct {  name string age  int8} //NewPerson 构造函数func NewPerson(name string, age int8) *Person {  return &Person{   name: name,  age:  age, }} //Dream Person做梦的编制func (p Person) Dream() {  fmt.Printf("%s的胡想是学好Go言语!\n", p.name)} func main() {  p1 := NewPerson("张三", 25) p1.Dream()}

编制与函数的分辨是 ,函数不属于任何圭表类型 ,编制属于特定的圭表类型。

可以定义不异的编制名 :

type Rectangle struct {  width, height float64}type Circle struct {  radius float64}  func (r Rectangle) area() float64 {  return r.width * r.height}//该 method 属于 Circle 圭表类型对象中的编制func (c Circle) area() float64 {  return c.radius * c.radius * math.Pi}func main() {  r1 := Rectangle{ 12, 2} r2 := Rectangle{ 9, 4} c1 := Circle{ 10} c2 := Circle{ 25} fmt.Println("Area of r1 is: ", r1.area()) fmt.Println("Area of r2 is: ", r2.area()) fmt.Println("Area of c1 is: ", c1.area()) fmt.Println("Area of c2 is: ", c2.area())}

运转下场 :

Area of r1 is:  24
Area of r2 is:  36
Area of c1 is:  314.1592653589793
Area of c2 is:  1963.4954084936207

  • 当然method的名字千篇一概,可是假定领受者不一样 ,那么method就不一样
  • method里面可以访谒领受者的字段
  • 调用method经由过程.访谒 ,就像struct里面访谒字段一样

指针圭表类型的领受者

指针圭表类型的领受者由一个筹划体的指针构成,因为指针的特点,调用编制时改削领受者指针的肆意成员变量,在编制停止前,改削都是有效的。这类编制就特别很是接近于其他言语中面向对象中的this或self :

type Rectangle struct {  width, height int} func (r *Rectangle) setVal() {  r.height = 20} func main() {  p := Rectangle{ 1, 2} s := p p.setVal() fmt.Println(p.height, s.height)}

下场:

20 2

值圭表类型的领受者

当编制感染于值圭表类型领受者时 ,Go言语会在代码运转时将领受者的值复制一份 。在值圭表类型领受者的编制中可以掉落踪掉落踪领受者的成员值,但改削独霸只是针对副本 ,没法改削领受者变量本身  。

type Rectangle struct {  width, height int} func (r Rectangle) setVal() {  r.height = 20} func main() {  p := Rectangle{ 1, 2} s := p p.setVal() fmt.Println(p.height, s.height)  // 2 2}

甚么时辰理应独霸指针圭表类型领受者

  • 需求改削领受者中的值
  • 领受者是拷贝价搏斗劲除夜的除夜对象
  • 担保齐截性,假如有某浅近例独霸了指针领受者,那么其他的编制也理应独霸指针领受者 。

编制和函数

已有了函数 ,为甚么还要独霸编制?

type Employee struct {       name     string    salary   int    currency string} /* displaySalary() method converted to function with Employee as parameter*/func displaySalary(e Employee) {       fmt.Printf("Salary of %s is %s%d", e.name, e.currency, e.salary)} func main() {       emp1 := Employee{         name:     "Sam Adolf",        salary:   5000,        currency: "$",    }    displaySalary(emp1)}

不才面的法度圭表类型中 ,displaySalary编制被转换为一个函数 ,而Employee struct作为参数传递给它 。这个法度圭表类型也产生发火了不异的输进:Salary of Sam Adolf is $5000.。

为甚么可以用函数来写不异的法度圭表类型呢?有以下几个启事 :

Go不是一种地道面向对象的编程言语,它不支撑类。是以  ,圭表类型的编制是一种完成近似于类的行动的编制。
不异称号的编制可以在不合的圭表类型上定义,而具有不异称号的函数是禁尽予的。

肆意圭表类型添加编制

在Go言语中 ,领受者的圭表类型可所以任何圭表类型 ,不单仅是筹划体 ,任何圭表类型都可以具有编制。 举个例子 ,我们基于内置的int圭表类型独霸type关头字可以定义新的自定义圭表类型,然后为我们的自定义圭表类型添加编制  。

//MyInt 将int定义为自定义MyInt圭表类型type MyInt int //SayHello 为MyInt添加一个SayHello的编制func (m MyInt) SayHello() {  fmt.Println("Hello, 我是一个int。")}func main() {  var m1 MyInt m1.SayHello() //Hello, 我是一个int。 m1 = 100 fmt.Printf("%#v  %T\n", m1, m1) //100  main.MyInt}

寄看事项: 非外埠圭表类型不克不及定义编制,也就是说我们不克不及给此外包的圭表类型定义编制 。

编制延续

编制是可以延续的,假定匿名字段完成了逐浅近例 ,那么包含这个匿名字段的struct也能调用该编制

type Human struct {  name  string age   int phone string}type Student struct {  Human  //匿名字段 school string}type Employee struct {  Human   //匿名字段 company string} func (h *Human) SayHi() {  fmt.Printf("Hi, I am %s you can call me on %s\n", h.name, h.phone)}func main() {  mark := Student{ Human{ "Mark", 25, "222-222-YYYY"}, "MIT"} sam := Employee{ Human{ "Sam", 45, "111-888-XXXX"}, "Golang Inc"} mark.SayHi() sam.SayHi()}

运转下场:

Hi, I am Mark you can call me on 222-222-YYYYHi, I am Sam you can call me on 111-888-XXXX

编制重写

type Human struct {  name  string age   int phone string}type Student struct {  Human  //匿名字段 school string}type Employee struct {  Human   //匿名字段 company string} //Human定义methodfunc (h *Human) SayHi() {  fmt.Printf("Hi, I am %s you can call me on %s\n", h.name, h.phone)} //Employee的method重写Human的methodfunc (e *Employee) SayHi() {  fmt.Printf("Hi, I am %s, I work at %s. Call me on %s\n", e.name,  e.company, e.phone) //Yes you can split into 2 lines here.}func main() {  mark := Student{ Human{ "Mark", 25, "222-222-YYYY"}, "MIT"} sam := Employee{ Human{ "Sam", 45, "111-888-XXXX"}, "Golang Inc"} mark.SayHi() sam.SayHi()}

运转下场:

Hi, I am Mark you can call me on 222-222-YYYY
Hi, I am Sam, I work at Golang Inc. Call me on 111-888-XXXX

  • 编制是可以延续和重写的
  • 存在延续相干时 ,屈就就近绳尺 ,举办调用

筹划体和编制补偿

因为slice和map这两种数据圭表类型都包含了指向底层数据的指针,是以在需求复制它们时要出格寄看 :

type Person struct {  name   string age    int8 dreams []string} func (p *Person) SetDreams(dreams []string) {  p.dreams = dreams} func main() {  p1 := Person{ name: "张三", age: 18} data := []string{ "喷饭", "睡觉", "打豆豆"} fmt.Printf("%p\n",data)  //0xc00006e360 p1.SetDreams(data)      //传的是 data 的内存地址,此时p.dreams和data指向不合块内存空间 fmt.Printf("%p\n",p1.dreams) //0xc00006e360  // 你真的想要改削 p1.dreams 吗
? data[1] = "不睡觉"    //data值的改削会影响person筹划体的dream字段 fmt.Println(p1.dreams)  // [喷饭 不睡觉 打豆豆]}

切确的做法是在编制中独霸传进的slice的拷贝举办筹划体赋值 。

func (p *Person) SetDreams(dreams []string) {  p.dreams = make([]string, len(dreams)) copy(p.dreams, dreams)}

一样的问题也存在于前去值slice和map的气候,在理论编码过程中必定要寄看这个问题。

到此这篇关于Golang通脉编制概略的文章就引见到这了,更多相干Go言语通脉编制内容请搜刮完竣下载之前的文章或延续不雅不雅不雅不雅鉴赏上面的相干文章希看大年夜师往后多多支撑完竣下载  !

#免责声明#

本站提供的一切资源、教程和内容信息仅限用于学习和研究目的;不得将上述内容用于商业或者非法用途,否则,一切后果请用户自负。本站信息来自网络收集整理,版权争议与本站无关。