Go语言学习笔记(7)——函数和方法

 Go语言中同时有函数和方法!

函数 go程序必须要包含一个main函数。main函数不能有任何参数和返回值!

1. 定义方法示例:

func max(num1, num2 int) int {    // 形参类型相同时,可以只写一个类型
                                  // 后面的int代表返回值类型 
        /* 定义局部变量 */ 
         var result int
         if (num1 > num2) {
               result = num1
         } else {
               result = num2
         }
         return result
 }
------------------------------------------      
func sssss(x int, y string) (string, int) {
           return y, x
}
------------------------------------------
func SumAndProduct(A, B int) (Add int, Multiplied int) {
          Add = A+B
          Multiplied = A*B
          return
}
--------------------------------------------------------------
×××××× import(
                "fmt"
                "math"
           )
/* 声明函数变量 */
getSquareRoot := func(x float64) float64 {return math.Sqrt(x)}
/* 使用函数 */
fmt.Println(getSquareRoot(9))                                                        

  

2. 当函数有多个返回值时,也可以使用空白标识符 _ 来丢弃某个/些值。

3. 可变参——接受变参的函数是有着形参数量不确定的函数。。。

    定义方法:

    func func_name(arg ...int) {} // 这里arg ...int标志此函数可以接收不定数量的int类型的实参

                  // 在函数体中,arg是一个int类型的切片(arg也可以换成args)

4. 参数传递——值传递和引用传递

值传递——就是普通的值传递啊。。

引用传递——使用指针——实质也是值传递。。。

扫描二维码关注公众号,回复: 6869345 查看本文章

var x int = 2 则若实参为地址 &x, 则形参为 *int 型。 传内存地址比较轻量级(8bytes),我们可以用指针传递体积大的结构体。 如果用参数值传递的话, 在每次copy上面就会花费相对较多的系统开销(内存和时间)。 所以当你要传递大的结构体的时候,用指针是一个明智的选择。

 

5 闭包: Go语言支持匿名函数,闭包的表现形式一般是匿名函数,通过函数返回一个函数。 闭包会使函数中的变量都被保存在内存中!消耗内存

×××只要闭包还在使用,那么被闭包引用的变量就会一直存在!!! 

func getSequence() func() int { 
         i := 0 
         return func() int {
             i += 1 
             return i 
         } 
} 

func main() {    
            /* nextNumber 为一个函数 */
            // var nextNumber = getSequence()   或者
    nextNumber := getSequence()

            /* 调用 nextNumber 函数,i 变量自增 1 并返回 */
            fmt.Println(nextNumber())
            fmt.Println(nextNumber())
            fmt.Println(nextNumber())
  ​
            /* 创建新的函数 nextNumber1,并查看结果 */
            nextNumber1 := getSequence()
            fmt.Println(nextNumber1())
            fmt.Println(nextNumber1())
}
  ​
打印结果:
            1
            2
            3
            1
            2                     

  

6. 可以声明一个函数类型;然后函数就可以作为值传递了! type testInt func(int) bool   // 声明了一个函数类型testInt, 接收一个int型参数,返回值为bool类型

7. panic和recover: Go语言没有像Java那样的异常机制,不能抛出异常,而是使用panic和recover机制。 panic(...)——当函数F调用panic,函数F的执行被中断,但是F中的延迟函数会正常执行,然后F返回到调用它的地方。在调用的地方,F的行为就像调用了panic。这一过程继续向上,直到发生panic的goroutine中所有调用的函数返回,此时程序退出。

recover()让进入恐慌的goroutine恢复过来。recover仅在延迟函数中有效。在正常的执行过程中,调用recover会返回nil,并且没有其它任何效果。


方法

1. 定义方法: func (t Type) method(parameter list) { //其中t是一个接收器,可以接收结构体或者非结构体类型 ... }

示例代码: 
package main
import "fmt"  ​
type Employee struct {
      name     string
      salary   int
      currency string
}
  ​
/*
  displaySalary()的方法接收器为Employee结构体类型
*/
func (e Employee) displaySalary() {
        fmt.Printf("Salary of %s is %s%d", e.name, e.currency, e.salary)
}
  ​
func main() {
     emp1 := Employee {
                         name:   "Sam Adolf",
                         salary:   5000,
                         currency:   "$",
                      }
     emp1.displaySalary()        // 调用displaySalary() 方法
}

可以定义相同的方法名:相同名称的方法可以在不同的类型上定义,而具有相同名称的函数是不允许的!

package main
import (
          "fmt"
          "math"
)
type Rectangle struct {
        width, height float64
}
type Circle struct {
        radius float64
}
// 该 method 属于 Rectangle 类型对象中的方法
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())
}

  

2. 变量作用域:
       函数内定义的变量称为局部变量,它们的作用域只在函数体内(参数和返回值变量也是局部变量
       函数外定义的变量称为全局变量,首字母大写全局变量可以在整个包甚至外部包(被导出后)使用
  ​
3. 用指针可以改变值!!

package main
import (
      "fmt"
)
  ​
type Rectangle struct {
       width, height int
}
  ​
func (r *Rectangle) setVal() {
       r.height = 20
}
  ​
func main() {
     p := Rectangle{1, 2}
     s := p                  // 此时只是将p的数据拷贝给s了一份,即二者并不是指向同一数据的关系
                             // p是p,s是s,改变p不会影响s
     p.setVal()
     mt.Println(p.height, s.height)
}

4. 继承: 如果匿名字段实现了一个method,那么包含这个匿名字段的struct也能调用该method.

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()
}

  


  ​
5. 重写: (就近原则)

package main
  ​
import "fmt"
type Human struct {
     name  string
     age   int
     phone string
}
type Student struct {
     Human  //匿名字段
     school string
}
type Employee struct {
     Human   //匿名字段
     company string
}
//Human定义method
func (h *Human) SayHi() {
     fmt.Printf("Hi, I am %s you can call me on %s\n", h.name, h.phone)
}
//Employee的method重写Human的method
func (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

  

猜你喜欢

转载自www.cnblogs.com/skzxc/p/11242948.html