zoukankan      html  css  js  c++  java
  • go 学习 (三):函数 & 指针 & 结构体

    一、函数

    函数声明

    // 声明语法:Go 中函数传递的参数都是值传递(将形参的值拷贝一份给函数内部使用, 形参与实参是相互独立互不影响的),其包括普通函数、lambda函数(匿名函数)、方法
     func 函数名(参数) 返回值 {
       函数体
     }
    
    // eg: 斐波那契数列(递归)
    func fibonacci(n int) int {
        if n < 2 {
            return n    
        } else {
            return fibonacci(n-2) + fibonacci(n-1)
        }
    }

    函数返回值

    // 一个返回值的函数
    func max(num1 int, num2 int) int {
       if num1 > num2 {
          return num1
       } else {
          return  num2
       }
    }
    
    
    
    // 多个返回值的函数
    func allValue(num int, name string) (int, string) {
        fmt.Println("In allValue function num: ", num)
        fmt.Println("In allValue function name: " + name)
        return num, name
    }
    
    
    func main() {
        num1 := 10
        num2 := 22
        result := max(num1, num2)
        fmt.Println("result: ", result)
    
        num, name := allValue(num2, "power")
        fmt.Println("In main function num: ", num)
        fmt.Println("In main function name: ", name)
    
    }

    函数参数

    • 值传递是指在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数。
    func valueFunc(num1 int, num2 int) {
        num1, num2 = num2, num1
    }
    
    
    // 当参数中多个参数类型一致时, 可简写参数的类型
    func f1(x, y int, m, n string, i, j bool) int { 
        return x + y
    }
    
    
    func main() {
        fmt.Println("值传递交换前 num1 的值: ", num1)
        fmt.Println("值传递交换前 num2 的值: ", num2)
        valueFunc(num1, num2)
        fmt.Println("值传递交换后 num1 的值: ", num1)
        fmt.Println("值传递交换后 num2 的值: ", num2)
    }
    
    
    // [Output]:值传递交换前 num1 的值:  20
    // [Output]:值传递交换前 num2 的值:  10
    // [Output]:值传递交换后 num1 的值:  20
    // [Output]:值传递交换后 num2 的值:  10
    • 引用传递是指在调用函数时将实际参数的地址传递到函数中,那么在函数中对参数所进行的修改,将影响到实际参数。
    func pointFunc(prt1 *int, prt2 *int) {
        *prt1, *prt2 = *prt2, *prt1
    }
    
    
    func main(){    
        num1, num2  := 10, 20
        var prt1 *int = &num1
        var prt2 *int = &num2
    
        fmt.Println("交换前 num1 的值: ", num1)
        fmt.Println("交换前 num2 的值: ", num2)
        pointFunc(prt1, prt2)                                // 指针作为函数参数,传递的是参数的地址
        fmt.Println("交换后 num1 的值: ", num1)
        fmt.Println("交换后 num2 的值: ", num2)
    }        
    
    
    // [Output]: 交换前 num1 的值:  10
    // [Output]: 交换前 num2 的值:  20
    // [Output]: 交换后 num1 的值:  20
    // [Output]: 交换后 num2 的值:  10
    • 默认情况下,Go 语言使用的是值传递,即在调用过程中不会影响到实际参数。

    可变参数:必须放在函数参数的最后, Go 语言中没有默认参数概念

    // 接收相同类型的可变参数的函数
    func argsSameFunc(args ... string) {
        fmt.Print("same type elem: ")
        for _, param := range args {
            fmt.Print(param, ", ")
        }
        fmt.Println()
    }
    
    // 接受不同类型的可变参数的函数
    func argsDifferenceFunc(args ... interface{}) {
        fmt.Print("difference type elem: ")
        for _, param := range args {
            fmt.Print(param, ",")
        }
        fmt.Print("
    ")
    }
    
    // 接收可变数量的参数, 类型约束为字符串
    func joinStrings(slist ...string) string {
       // 定义一个字节缓冲, 快速地连接字符串
       var b bytes.Buffer
       // 遍历可变参数列表slist, 类型为[]string
       for _, s := range slist {
          // 将遍历出的字符串连续写入字节数组
          b.WriteString(s)
       }
       // 将连接好的字节数组转换为字符串并输出
       return b.String()
    }
    
    
    func main() {
    
        // 接受相同类型的可变参数函数
        argsSameFunc("power")
        argsSameFunc("forever", "topOne")
        argsSameFunc("selina", "hebe", "ella")
    
        // 接受不同类型的可变参数函数
        argsDifferenceFunc("power", 220)
        argsDifferenceFunc("selina", 1031, "hebe", 330, "ella", 618)
    
      fmt.Println(joinStrings("Asia ", "sky", " crops:", "S.H.E"))
      fmt.Println(joinStrings("They ", "gave ", "me ", "the ", "courage "))
      fmt.Print(reflect.TypeOf(num1))    // 可获取变量的类型
    }

    函数作为参数、返回值

    // 函数作为参数传递
    func calc(x, y int, op func(int, int) int) int { // 接收两个int类型的参数, 和 一个拥有 2个int类型参数、1个int类型返回值的函数类型 参数
        return op(x, y)
    }
    
    // 函数作为返回值 func do(s string) (func(int, int) int, error) { switch s { case "+": return add, nil case "-": return sub, nil default: err := errors.New("无法识别的操作符") return nil, err } } func add(x, y int) int { return x + y } func sub(x, y int) int { return x - y }

    全局、局部变量

    1、全局变量:定义在函数外部的变量, 在程序的整个运行周期内都有效, 在函数中可访问到全局变量。
    2、局部变量: 分为两种, 第一种 函数内定义的变量无法在该函数外使用; 如果局部变量和全局变量重名,优先访问局部变量
    3、局部变量: 第二种 语句块内定义的变量只能在语句块中生效(ifforswitch)

    闭包

    // 闭包: 闭包是一个函数 它包含这个函数 和 它外部作用域的变量(与其相关的引用环境) 组合而成的实体, 闭包=函数+引用环境; 底层原理: 函数可作为返回值; 函数内部查找变量的顺序, 先在函数内部找, 再往函数外部找
    
    // 无参闭包
    func adder() func(int) int { // 返回值的函数声明 与 return后的匿名函数 是一样的
        var x int
        return func(y int) int {
            x += y
            return x
        }
    }
    
    // 带参闭包
    func adder2(x int) func(int) int {
        return func(y int) int {
            x += y
            return x
        }
    }
    
    // 参数为函数引用的闭包
    func ft(x, y int) {
        fmt.Println("
    This is ft function.")
        fmt.Printf("ft(x - %v, y - %v)", x, y)
    }
    
    func adders(f func(int, int), x, y int) func() {
        tmp := func() {
            f(x, y)
        }
        return tmp
    }
    func main() {
    // 1、无参闭包 var f = adder() // 此时接收到的是 adder 函数返回的 匿名函数的引用 fmt.Println("closesure f(10) result: ", f(10)) // 此前并未给闭包内的x赋值, 所以x声明后为默认的零值, 此行代码运行过后, x已被赋值, x=0, y=10, x+=y, x=10 fmt.Println("closesure f(20) result: ", f(20)) // 在程序并未结束前, 前一句代码给闭包内的x所赋予的值都有效, 所以此行结果为: x=10, y=20, x+=y, x=30 var f1 = adder() // 重新赋值, 从头再来 fmt.Println("closesure f1(30) result: ", f1(30)) // x=0, y=30, x+=y, x=30 fmt.Println("closesure f1(50) result: ", f1(50)) // x=30, y=50, x+=y, x=80 fmt.Println() // 2、带参闭包 var fp = adder2(10) // x=10 fmt.Println("closesure fp(10) result: ", fp(10)) // x=10, y=10, x+=y, x=20 fmt.Println("closesure fp(30) result: ", fp(30)) // x=20, y=30, x+=y, x=50 var fp1 = adder2(20) fmt.Println("closesure fp1(50) result: ", fp1(50)) // x=20, y=50, x+=y, x=70 fmt.Println("closesure fp1(20) result: ", fp1(20)) // x=70, y=20, x+=y, x=90 // 3、参数为函数引用的闭包 var ft1 = adders(ft, 2, 3) ft1() }

    匿名函数

    // 匿名函数: 没有函数名的函数, 它无法像普通函数那样调用, 需要将匿名函数保存到某个变量, 或作为立即执行的函数 [匿名函数多用于回调函数和闭包]
    // 定义语法
    func(参数列表)(返回参数列表){
        // 函数体
    }
    
    // 匿名函数 -- 作为执行函数(只执行一次), 函数定义完之后 加上() 将会立即执行    func(a, b int) {
        fmt.Println("self excuting function a*b result: ", a*b)
    }(2, 3)
    
    
    // 匿名函数 -- 作为回调函数
    func visit(list []int, f func(int)) {
        for _, elem := range list {
            f(elem)
        }
    }
    
    func main() {
        // 匿名函数
        // 声明时调用
        func(name string) {
            fmt.Println("Hello ", name)
        } ("power")        // ---> 括号内是匿名函数执行传递的参数
    
        // 将匿名函数赋值给变量,通过 变量()  调用
        innominateFunc := func(name string) string {
            fmt.Println("Hello ", name)
            receiving := "Hello" + name
            return receiving
        }
        innominateFunc("hebe")
    
        // 匿名函数作为回调函数        打印切片中的所有元素
        visit([]int {313, 618, 1031}, func(v int) {            // params: 切片,匿名函数(注意,此处的匿名函数在 visit函数的参数括号内,是作为参数传递给 visit 的)
            fmt.Println(v)
        })
    }

    方法

    // 结构体
    type Circle struct {
        radius float64
    }
    
    // 方法
    func (circle Circle) method(msg string) float64 {
        fmt.Println("The radius of the circle is: ", circle.radius)
        return 3.14 * circle.radius * circle.radius
    }
    
    
    func main() {    
        var circle Circle
        circle.radius = 10.00
        area := circle.method("This is a way of finding the area of a circle")
        fmt.Println("The area of the circle is: ", area)
    
        fmt.Print("
    ")    
    ?

    二、指针

    package main
    
    import "fmt"
    
    
    const count int = 5
    
    
    func pointFunc(prt1 *int, prt2 *int) {
        *prt1, *prt2 = *prt2, *prt1
    }
    
    
    
    func main() {
    
        // 指针声明
        var ip *int
        var fp *float32
        var ipNum int
        var fpFloat float32
    
        ipNum = 618
        fpFloat = 3.13
        // 指针赋值
        ip = &ipNum
        fp = &fpFloat
    
        fmt.Println("ip: ", ip)
        fmt.Println("fp: ", fp)
    
        // 空指针
        var prt *string
        fmt.Println("prt: ", prt)
        if (prt != nil){
            fmt.Println("prt isn't empty pointer.")
        } else {
            fmt.Println("prt is empty pointer.")
        }
    
        fmt.Print("
    ")
    
        // 指针数组
        var array = [] int{1, 3, 5, 7, 9}
        var ptr [count]*int
        zero := 0
        for t:=0; t<count; t++ {
            ptr[t] = &array[t]
        }
        for r:=0; r<count; r++ {
            // 打印数组内元素内存地址赋值给指针数据后的所有内存地址
            fmt.Print(array[r], "	")
            fmt.Print(*ptr[r], "	")
            fmt.Print(ptr[r], "	")
    
            // 修改指针数组内所有元素的内存地址
            ptr[r] = &zero
            fmt.Print(ptr[r], "	")
            fmt.Println(*ptr[r])
        }
    
    
        fmt.Print("
    ")
    
        // 指向指针的指针变量
        var a = 22
        var aptr1 *int
        var aptr2 **int
        aptr1 = &a
        aptr2 = &aptr1
    
        fmt.Println("a value: ", a)
        fmt.Println("a memory address: ", &a)
        fmt.Println("aptr1 value: ", aptr1)
        fmt.Println("*aptr1 value: ", *aptr1)
        fmt.Println("&aptr1 memory address: ", &aptr1)
        fmt.Println("aptr2 value: ", aptr2)
        fmt.Println("*aptr2 value: ", *aptr2)
        fmt.Println("**aptr2 value: ", **aptr2)
        fmt.Println("&aptr2 memory address: ", &aptr2)
    
        fmt.Print("
    ")
    
        // 指针作为函数的参数
        num1, num2  := 10, 20
        var prt1 *int = &num1
        var prt2 *int = &num2
    
        fmt.Println("指针传递交换前 num1 的值: ", num1)
        fmt.Println("指针传递交换前 num2 的值: ", num2)
        pointFunc(prt1, prt2)
        fmt.Println("指针传递交换后 num1 的值: ", num1)
        fmt.Println("指针传递交换后 num2 的值: ", num2)
    
    
    }

    三、结构体 

    // 声明语法
    type 结构体名称 struct {
            字段名1  字段1类型
            字段名2  字段2类型
            字段名3  字段3类型
             ...
    }    
    
    
    // 示例1:每行声明一个字段
    type Member struct {
        name string
        age int
        weight float64
        height float32
    }
    
    
    // 示例2:同类型字段声明在同一行
    type Test struct {
        one, two, three int
        four string
        five float32
        six float64
        seven bool
    }
    
    
    // 第一种方式实例化结构体
    var members Member
    members.name = "power"
    members.age = 20
    members.weight = 47
    
    // 第二种方式实例化结构体
    member := Member{"top", 18, 45, 1.65}
    member := Member{"name": "top", "age": 18, "weight": 45, "height": 1.65}

    // 打印结构体的每个字段值 func printMemberPoint(memberPoint *Member) { fmt.Println("memberPoint: ", memberPoint) fmt.Println("memberPoint.name: ", memberPoint.name) fmt.Println("memberPoint.age: ", memberPoint.age) fmt.Println("memberPoint.weight: ", memberPoint.weight) fmt.Println("memberPoint.height: ", memberPoint.height) fmt.Print(" ") }
    // 第一种方式实例化指针类型的结构体:new pointMember := new(Member) memberPoint.name = "power" memberPoint.age = 20 memberPoint.weight = 47 memberPoint.height = 1.73 printMemberPoint(memberPoint)
    // 第二种方式实例化指针类型的结构体:取址 & memberPoint := &Member{} memberPoint.name = "top" memberPoint.age = 18 memberPoint.weight = 45 memberPoint.height = 1.68 printMemberPoint(memberPoint) var memberPoint *Member memberPoint = &members printMemberPoint(memberPoint) // 匿名结构体 stone := struct { nickname string skill string }{"small stone", "fly"} fmt.Println("stone.nickname:", stone.nickname) fmt.Println("stone.skill:", stone.skill)
    // 结构体的方法 func (structObject *structName) method(param paramType...) (returnType...) {
      
    // do something

    }
    returnValue := member.method(param)
  • 相关阅读:
    灌水小程序(aspx)
    网页内容,图片及连接 抓取通用类
    net2.0中使用Cookie保存中文出现乱码的解决方法
    jQuery + Json 无刷新分页
    JSON 简单应用实例
    漂亮的折叠效果(jQuery)
    IEnumerable与IEnumerator区别(带实例)
    如何在SqlSever2008中新建用户并给予登入权限
    很实用的jQuery事件 toggle() 方法
    DataList控件中使用Xml数据源
  • 原文地址:https://www.cnblogs.com/hsmwlyl/p/11772499.html
Copyright © 2011-2022 走看看