Go学习笔记(三)

2019-08-05  本文已影响0人  dev_winner

Go函数

func(input1 string ,input2 string) string

加入type关键字和一个标识符作为名称,就变成了一个函数类型声明

type MyFunc func(input1 string ,input2 string) string
func myFunc(part1 string, part2 string) (result string) {
    result = part1 + part2
    return
}
// 另一种常规写法:
func myFunc(part1 string, part2 string) string {
    return part1 + part2
}  
var splice func(string, string) string // 等价于 var splice MyFun
// 然后把函数myFunc赋给它:
splice = myFunc
// 然后就可以调用该函数
splice("1", "2")
// 使用了一个匿名函数来初始化splice变量,
var splice = func(part1 string, part2 string) string {
    return part1 + part2
}
// 省去splice变量
var result = func(part1 string, part2 string) string {
    return part1 + part2
}("1", "2")   
// 注意,result变量的类型不是函数类型,而与后面的匿名函数的结果类型是相同的。
package main

import (
    "fmt"
    "strconv"
    "sync/atomic"
)

// 员工ID生成器,定义别名
type EmployeeIdGenerator func(company string, department string, sn uint32) string

// 默认公司名称
var company = "Gophers"

// 序列号
var sn uint32

// 生成员工ID
func generateId(generator EmployeeIdGenerator, department string) (string, bool) {
    // 若员工ID生成器不可用,则无法生成员工ID,应直接返回。
    if generator == nil {
        return "", false
    }
    // 使用代码包 sync/atomic 中提供的原子操作函数可以保证并发安全。
    newSn := atomic.AddUint32(&sn, 1)
    return generator(company, department, newSn), true
}

// 字符串类型和数值类型不可直接拼接,所以提供这样一个函数作为辅助转换。
func appendSn(firstPart string, sn uint32) string {
    return firstPart + strconv.FormatUint(uint64(sn), 10)
}

func main() {
    var generator EmployeeIdGenerator // 声明一个函数类型
    generator = func(company string, department string, sn uint32) string { // 对应的一个实现
        return appendSn(company+"-"+department+"-", sn)
    }
    fmt.Println(generateId(generator, "RD"))
}
// 输出结果:Gophers-RD-1 true

Go语言的结构体(Struct)

type Person struct {
    Name   string
    Gender string
    Age    uint8
}  
p := struct {
    Name   string
    Gender string
    Age    uint8
}{"Robert", "Male", 33}
func (person *Person) Grow() {
    person.Age++
} 
p := Person{"Robert", "Male", 33}
p.Grow() 

直接在Person类型的变量p之上应用调用表达式来调用它的方法Grow。注意,Grow方法的接收者标识符person指代的正是变量p的值。这也是“当前值”这个词的由来。在Grow方法的接收者声明中的那个类型是*Person,而不是Person。实际上,前者是后者的指针类型。与对象不同的是,结构体类型(以及任何类型)之间都不可能存在继承关系。实际上,在Go语言中并没有继承的概念。

package main

import "fmt"

type Person struct {
    Name    string
    Gender  string
    Age     uint8
    Address string
    
}

// 表示为结构体person的方法
func (person *Person) Move(newAddress string) string {
        old := person.Address
        person.Address = newAddress
        return old
}

func main() {
    p := Person{"Robert", "Male", 33, "Beijing"}
    oldAddress := p.Move("San Francisco")
    fmt.Printf("%s moved from %s to %s.\n", p.Name, oldAddress, p.Address)
}

Go语言的接口

type Animal interface {
  // 若干方法的声明
    Grow()
    Move(string) string
}
p := Person{"Robert", "Male", 33, "Beijing"}
v := interface{}(&p)

注意:表达式&p(&是取址操作符)的求值结果是一个*Person类型的值,即p的指针。在这之后,我们就可以在v上应用类型断言了,即h, ok := v.(Animal)。 类型断言表达式的求值结果可以有两个:第一个结果是被转换后的那个目标类型(这里是Animal)的值,而第二个结果则是转换操作成功与否的标志(bool 类型),用来判定实现关系的重要依据!

package main

import "fmt"

type Animal interface {
    Grow()
    Move(string) string
}

// 创建一个Cat结构体
type Cat struct {
    Name string
    Age uint8
    Location string
}

// 定义结构体Cat的一个Grow方法 
func (cat *Cat) Grow() {
    cat.Age++
}

// 定义结构体Cat的一个Move方法
func (cat *Cat) Move(new string) string {
    old := cat.Location
    cat.Location = new
    return old
}

// 结构体Cat实现了Animal接口

func main() {
    myCat := Cat{"Little C", 2, "In the house"}
    animal, ok := interface{}(&myCat).(Animal) // 转换成空接口类型值,应用断言表达式判断实现关系
    fmt.Printf("%v, %v\n", ok, animal)  // 输出结果:true, &{Little C 2 In the house}
}

Go语言指针

func (person Person) Grow() {
    person.Age++
}
// then operate below
p := Person{"Robert", "Male", 33, "Beijing"}
p.Grow()
fmt.Printf("%v\n", p)
// 输出结果可以发现,Age值不变,说明传的是一个值拷贝,而不是地址拷贝

原因是方法的接收者标识符所代表的是该方法当前所属的那个值的一个副本,而不是该值本身。若传入的是一个指针类型值,这时的person代表的是p的值的指针的副本指针的副本仍会指向p的值

package main

import "fmt"

type MyInt struct {
    n int
}

func (myInt *MyInt) Increase() {
    myInt.n++
}

func (myInt *MyInt) Decrease() {
    myInt.n--
}

func main() {
    mi := MyInt{}
    mi.Increase()
    mi.Increase()
    mi.Decrease()
    mi.Decrease()
    mi.Increase()
    fmt.Printf("%v\n", mi.n == 1)
}
package main

import "fmt"

type Pet interface {
    Name() string
    Age() uint8
}

type Dog struct {
    name string
    age uint8
}

// 结构体Dog实现Animal接口中的方法
// 只要有一个是指针方法,dog类型就不可能是Pet接口的实现类型。
// Name()定义为值方法
func (dog Dog) Name() string {
    return dog.name
}

// Age()定义为值方法
func (dog Dog) Age() uint8 {
    return dog.age
}

func main() {
    myDog := Dog{"Little D", 3}
    _, ok1 := interface{}(&myDog).(Pet) // 将指针类型转化为空接口类型值,即使其实现的都是值方法,依然实现了Pet接口。
    _, ok2 := interface{}(myDog).(Pet) // 其实现方法都为值方法,否则为false
    fmt.Printf("%v, %v\n", ok1, ok2) // true, true
}
上一篇下一篇

猜你喜欢

热点阅读