zoukankan      html  css  js  c++  java
  • Go(二)函数

    自定义类型

    两种用户定义的类型

    • 结构类型
    • 基于一个已有的类型,将其作为新类型的类型说明

    结构体变量定义和初始化

    type struct_variable_type struct {
       member definition
       member definition
       ...
       member definition
    }

    一旦定义了结构体类型,它就能用于变量的声明,语法格式如下:

    variable_name := structure_variable_type {value1, value2...valuen}
    //
    variable_name := structure_variable_type { key1: value1, key2: value2..., keyn: valuen}

    实例

    package main
    
    import "fmt"
    
    type Person struct {
        name string
        sex byte
        age int
    }
    
    func main() {
    
        // 顺序初始化,必须全部初始化完整
        var person Person = Person{"wang", 'f', 29}
        fmt.Println(person)
    
        // 部分初始化
        person1 := Person{name: "zhao", sex: 'm'}
        fmt.Println(person1.name)
    }

    赋值、比较和传参

    使用.索引成员变量

        // 部分初始化
        person1 := Person{name: "zhao", sex: 'm'}
        fmt.Println(person1.name)
    
        person1.name = "li"
        fmt.Println(person1.name)

    比较

    只能使用 == 和 !=,不能使用 > < >= <=

        // 结构体比较
        person2 := Person{name: "zhao", sex: 'm', age: 18}
        person3 := Person{name: "zhao", sex: 'm', age: 18}
        person4 := Person{name: "zhao", sex: 'm', age: 181}
        fmt.Println(person2 == person3) // true
        fmt.Println(person3 == person4) // false

    相同类型的结构体可以进行赋值

    相同类型结构体:成员变量的类型、个数、顺序一致

    var tmp Person
    tmp = person1
    fmt.Println(tmp.name)

     因此函数体内部可以使用结构体传参,因为实参可以赋值给相同结构体类型的形参,值传递。几乎不用,内存消耗大,效率低。

    func test(person Person)  {
        println(person.name)
    }
    
    func main() {
    
        var temp Person
        test(temp)
    
    
    }

    结构体指针

    结构体指针变量定义和初始化

    1.顺序初始化和部分初始化

        var man *Person  = &Person{"zhao", 'm', 18}
        fmt.Println(man.name)
        var man1 *Person  = &Person{name: "zhao", sex: 'm'}
        fmt.Println(man1.name)

    2.使用new

    var  man2 *Person = new(Person);
    man2.name = "zhao"
    man2.sex = 0
    man2.age = 16

    使用.指针索引成员变量

    结构体变量的地址就是结构体首个元素的地址

        fmt.Printf("&tmp = %p 
    ", &tmp)
        fmt.Printf("&tmp.name = %p 
    ", &tmp.name)

    结果

    &tmp = 0xc000004500
    &tmp.name = 0xc000004500

    结构体指针的值就是结构体首个元素的地址

    fmt.Printf("man2 = %p
    ", man2)
    fmt.Printf("&man2.name = %p
    ", &man2.name)

    结果

    man2 = 0xc00008e080
    &man2.name = 0xc00008e080

    结构体指针作为函数参数

    import "fmt"
    
    type Person struct {
        name string
        sex byte
        age int
    }
    
    func test1(person * Person)  {
        person.name = "wang"
    }
    
    func main() {
    
        fmt.Println("man2:", man2)
        test1(man2)
        fmt.Println("man2", man2)
    
    }

    结果

    man2: &{zhao 0 16}
    man2 &{wang 0 16}

    发现通过指针变量可以修改结构体,传引用,使用频率高

    也是实参拷贝值给形参,不过这次拷贝的是地址值

     或

    fmt.Println(person1.name)
    test1(&person1)
    fmt.Println(person1.name)

    结果

    li
    wang

    函数是一等公民

    与其他主要编程语言的差异

    1.可以有多个返回值

    2.所有参数都是值传递

           slice、map、channel会有传引用是错觉,如切片背后是数组,是一个数据结构,里面包含了指向对应数组的指针,数据结构被复制,指针操作的仍是同一块空间,感觉像是传引用

    3.函数可以作为变量的值

    4.函数可以作为参数和返回值

    package fun_test
    
    import (
        "fmt"
        "math/rand"
        "testing"
        "time"
    )
    
    // 多个返回值
    func returnMultiValues()(int, int)  {
        return rand.Intn(10), rand.Intn(20)
    }
    
    // 函数可以作为参数和返回值
    // 计算inner函数运行的时间
    func timeSpent(inner func(op int)int) func(opt int) int  {
        return func(n int) int {
            start := time.Now()
            ret := inner(n)
            fmt.Println("time spent:", time.Since(start).Seconds())
            return ret
        }
    }
    
    func slowFun(op int)int{
        time.Sleep(time.Second*1)
        return op
    }
    
    func TestFn(t *testing.T){
        a, _ := returnMultiValues()
        t.Log(a)
        tsSF := timeSpent(slowFun)
        t.Log(tsSF(10))
    }

    结果:

    === RUN TestFn
    time spent: 1.0000582
    --- PASS: TestFn (1.00s)
    func_test.go:32: 1
    func_test.go:34: 10
    PASS

    可变参数及defer

     可变参数会被转换为数组,通过数组变量来完成

    func sum(ops ...int) int  {
        s := 0
        for _, op := range ops{
            s += op
        }
        return s
    }
    
    func TestParam(t *testing.T)  {
        s := sum(1, 2, 3, 4, 5)
        fmt.Println(s)
    }

    === RUN TestParam
    15
    --- PASS: TestParam (0.00s)
    PASS

    defer

    func clear()  {
        fmt.Println("clear resources")
    }
    
    func TestDefer(t *testing.T)  {
        defer clear()
        fmt.Println("Start")
        panic("Fatal error") //defer仍会执行
        println("Stop")
    }

    === RUN TestDefer
    Start
    clear resources
    --- FAIL: TestDefer (0.00s)
    panic: Fatal error [recovered]
    panic: Fatal error

    会发现出现了异常,clear()依然会执行,

    异常之前的fmt.Println("Start")被执行

    异常之后的fmt.Println("Stop")没有被执行

  • 相关阅读:
    CF1359D Yet Another Yet Another Task
    【数据结构】fhq_treap
    AtCoder Beginner Contest 182 题解
    UVA11992 Fast Matrix Operations
    双指针例题
    python使用国内镜像库
    APP元素定位工具之——Weditor
    安卓ADB的常见命令的使用
    函数进阶之迭代器,递归
    函数基础之对象,嵌套,名称空间和作用域
  • 原文地址:https://www.cnblogs.com/aidata/p/11875771.html
Copyright © 2011-2022 走看看