zoukankan      html  css  js  c++  java
  • 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. 参数传递——值传递和引用传递

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

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

    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
    ", 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
    ", 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
    ", 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

      

    ///纵有疾风起,人生不言弃///
  • 相关阅读:
    Qt助手---摘录
    Qt随记
    前端编码规范之CSS(转)
    给QT新手的练手项目——基于QT的GIF播放器(转)
    Qt收藏
    C++开发者都应该使用的10个C++11特性(转)
    为学Linux,我看了这些书(转)
    Qt去掉view项的焦点虚线框的方法(转)
    QTableWidget详解(样式、右键菜单、表头塌陷、多选等)(转)
    JZOJ 3085. 图的计数
  • 原文地址:https://www.cnblogs.com/skzxc/p/11242948.html
Copyright © 2011-2022 走看看