YMLiang

Go 向函数传递指针参数

  • Go 语言允许向函数传递指针,只需要在函数定义的参数上设置为指针类型即可

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    package main

    import "fmt"

    func main() {
    /* 定义局部变量 */
    var a int = 100
    var b int = 200

    fmt.Printf("交换前 a 的值 : %d\n", a)
    fmt.Printf("交换前 b 的值 : %d\n", b)

    /* 调用函数用于交换值
    * &a 指向 a 变量的地址
    * &b 指向 b 变量的地址
    */
    swap(&a, &b)

    fmt.Printf("交换后 a 的值 : %d\n", a)
    fmt.Printf("交换后 b 的值 : %d\n", b)
    }

    func swap(x *int, y *int) {
    var temp int
    temp = *x /* 保存 x 地址的值 */
    *x = *y /* 将 y 赋值给 x */
    *y = temp /* 将 temp 赋值给 y */
    }
    输出结果:

    交换前 a 的值 : 100
    交换前 b 的值 : 200
    交换后 a 的值 : 200
    交换后 b 的值 : 100

自定义类型Struct

  • Go中的 struct:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    可将类型分为命名和未命名两大类。命名类型包括 bool、int、string 等,而 array、slice、map 等和具体元素类型、长度等有关,属于未命名类型。

    具有相同声明的未命名类型被视为同一类型。

    • 具有相同基类型的指针。
    • 具有相同元素类型和长度的 array。
    • 具有相同元素类型的 slice。
    • 具有相同键值类型的 map。
    • 具有相同元素类型和传送方向的 channel。
    • 具有相同字段序列 (字段名、类型、标签、顺序) 的匿名 struct。
    • 签名相同 (参数和返回值,不包括参数名称) 的 function。
    • 方法集相同 ( 方法名、方法签名相同,和次序无关) 的 interface。
  • struct 特点:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    1. 用来自定义复杂数据结构
    2. struct里面可以包含多个字段(属性)
    3. struct类型可以定义方法,注意和函数的区分
    4. struct类型是值类型
    5. struct类型可以嵌套
    6. Go语言没有class类型,只有struct类型
    7. 结构体是用户单独定义的类型,不能和其他类型进行强制转换
    8. golang中的struct没有构造函数,一般可以使用工厂模式来解决这个问题。
    9. 我们可以为struct中的每个字段,写上一个tag。这个tag可以通过反射的机制获取到,最常用的场景就是json序列化和反序列化。
  • 可以理解为面向对象编程

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    struct声明及初始化:

    声明:

    type typeName struct {
    //...
    }

    eg:
    package main

    type global struct{}

    func main() {
    type local struct{}
    }

    初始化:

    方法有几种:

    package main

    import (
    "fmt"
    )

    type Test struct {
    int
    string
    }

    var a Test

    func main() {

    b := new(Test) //同 var b *Test = new(Test)
    c := Test{1, "c"}
    d := Test{}
    e := &Test{}
    f := &Test{2, "f"} //同 var d *Test = &Test{2, "f"}

    fmt.Println(a, b, c, d, e, f)
    // 注: a b c d 返回 Test 类型变量;e f 返回 *Test 类型变量;若无初始化值,则默认为零值

    }
    输出结果:

    {0 } &{0 } {1 c} {0 } &{0 } &{2 f}
  • 初始化值可以分为两种

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    a. 有序: typeName{value1, value2, ...} 必须一一对应
    b. 无序: typeName{field1:value1, field2:value2, ...} 可初始化部分值

    栗子:

    a:有序

    type Person struct {
    name string
    age int
    sex int
    phone int
    }

    func main() {
    person := Person{"lff", 23, 1, 18135479521}
    fmt.Println(person)
    }

    b: 无序
    func main() {
    p2 := Person{age: 23} //无序,指你可以指定给p2赋哪个字段的值
    fmt.Println(person)
    }
  • 操作 struct

    1
    2
    3
    4
    5
    声明的struct与普通类型一样
    访问结构体中的一个变量名, 用 "." 来连接:
    varName.field 或 (*varName).field
    如操作上面 Person 结构体中的 age : p.age = 35
    也可以作为函数中的参数,返回值类型
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    举个栗子:
    package main

    import "fmt"

    //1. 声明一个自定义类型名为 Person 的结构体
    type Person struct {
    name string
    age int
    }

    func main() {
    //2. 初始化
    var p1 Person
    p2 := Person{}
    p3 := Person{"James", 23}
    p4 := Person{age: 23}
    fmt.Println(p1, p2, p3, p4)
    p5 := new(Person)
    p6 := &Person{}
    p7 := &Person{"James", 23}
    p8 := &Person{age: 23}
    fmt.Println(p5, p6, p7, p8)

    //3. 操作
    p1.age = 50
    p2.age = 25
    if compareAge(p1, p2) {
    fmt.Println("p1 is older than p2")
    } else {
    fmt.Println("p2 is older than p1")
    }
    }

    func compareAge(p1, p2 Person) bool {
    if p1.age > p2.age {
    return true
    }
    return false
    }
    输出:

    { 0} { 0} {James 23} { 23}
    &{ 0} &{ 0} &{James 23} &{ 23}
    p1 is older than p2
  • 匿名字段

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    匿名字段:
    声明一个 struct1 可以包含已经存在的 struct2 或者go语言中内置类型作为内置字段,称为匿名字段,即只写了 typeName,无 varName,但是 typeName 不能重复。

    匿名字段与面向对象程序语言中的继承

    声明及初始化:

    package main

    import (
    "fmt"
    )

    type Person struct {
    name string
    age int
    addr string
    }

    type Employee struct {
    Person //匿名字段
    salary int
    int //用内置类型作为匿名字段
    addr string //类似于重载
    }

    func main() {
    em1 := Employee{Person{"rain", 23, "qingyangqu"}, 5000, 100, "gaoxingqu"}

    fmt.Println(em1)
    // var em2 Person = em1
    // Error: cannot use em1 (type Employee) as type Person in assignment (没有继承, 然也不会有多态)

    var em2 Person = em1.Person // 同类型拷贝。

    fmt.Println(em2)
    }
    输出结果:

    {{Murphy 23 帝都} 5000 100 北京}
    {Murphy 23 帝都}
    操作

    访问方式也是通过 "." 来连接
    相同字段采用最外层优先访问,类似于重载
    em1.addr 访问的是 Employee 中最外层的 addr
    em1.Person.addr 访问的是 Employee 中 Person 中的 addr
    package main

    import "fmt"

    type Person struct {
    name string
    age int
    addr string
    }

    type Employee struct {
    Person //匿名字段
    salary int
    int //用内置类型作为匿名字段
    addr string //类似于重载
    }

    func main() {
    /*
    var em1 Employee = Employee{}
    em1.Person = Person{"rain", 23, "帝都"}
    em1.salary = 5000
    em1.int = 100 //使用时注意其意义,此处无
    em1.addr = "北京"
    */
    //em1 := Employee{Person{"rain", 23, "帝都"}, 5000, 100, "北京"}
    //初始化方式不一样,但是结果一样
    em1 := Employee{Person: Person{"Murphy", 23, "帝都"}, salary: 5000, int: 100, addr: "北京"}
    fmt.Println(em1)

    fmt.Println("live addr(em1.addr) = ", em1.addr)
    fmt.Println("work addr(em1.Person.addr) = ", em1.Person.addr)
    em1.int = 200 //修改匿名字段的值

    }
    输出:

    {{Murphy 23 帝都} 5000 100 北京}
    live addr(em1.addr) = 北京
    work addr(em1.Person.addr) = 帝都
    空结构 "节省" 内存, 如用来实现 set 数据结构,或者实现没有 "状态" 只有方法的 "静态类"。

    package main

    func main() {
    var null struct{}

    set := make(map[string]struct{})
    set["a"] = null
    }
    不能同时嵌入某一类型和其指针类型,因为它们名字相同。

    package main

    type Resource struct {
    id int
    }

    type User struct {
    *Resource
    // Resource // Error: duplicate field Resource
    name string
    }

    func main() {
    u := User{
    &Resource{1},
    "Administrator",
    }

    println(u.id)
    println(u.Resource.id)
    }
    输出结果:

    1
    1

 评论


博客内容遵循 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 协议

本站使用 Material X 作为主题 , 总访问量为 次 。
Copyright 2018-2019 YMLiang'BLOG   |   京ICP备 - 19039949  |  载入天数...载入时分秒...