golang学习

项目组织结构

/GOPATH
  /src   #源代码
    main.go  #主函数
    /myPackage  #自己的包 
      myfile.go
  /pkg   #引入的包
  /bin   #可执行文件

变量声明

iota的使用:

iota 比较特殊,可以被认为是一个可被编译器修改的常量.
在每一个 const 关键字出现时被重置为0,
然后在下一个 const 出现之前,每出现一次 iota ,其所代表的数字会自动增1.

const后面跟括号

表明其余的变量都重复第一个变量的表达式!

枚举的定义

下面是星期的定义,最后一个代表日期数,而且是包内私有的.

示例代码:

    const (
        Sunday = iota
        Monday
        Tuesday
        Wednesday
        Thursday
        Friday
        Saturday
        numberOfDays
    )

数组


package main

import (
    "fmt"
)

func main() {
    array := [5]int{1, 1, 1, 1, 1}
    modifyArray(array)
    fmt.Println("修改后的数组是:", array)
}

func modifyArray(array [5]int) {
    array[0] = 10 //试图修改第一个元素的值
    fmt.Println("在修改函数中,数组的值是:", array)
}

    const (
        Sunday = iota
        Monday
        Tuesday
        Wednesday
        Thursday
        Friday
        Saturday
        numberOfDays
    )
    

slice 数组切片

从数组中创建

    var mArray [5]int = [5]int{5, 5, 5, 5, 5}
    var mSlice []int = mArray[:3]

    fmt.Println("mArray is:")
    for _, v := range mArray {
        fmt.Print(v, " ")
    }

    fmt.Println("\nmSlice is:")
    for _, v := range mSlice {
        fmt.Print(v, " ")
    }

    mSlice2 := []int{1, 2, 3, 4, 5, 6}

    for i, v := range mSlice2 {
        fmt.Println("slice:", i, "is:", v)
    }

数组切片的CRUD


    mslice := make([]int, 5, 10)
    fmt.Println("len(mint):", len(mslice))
    fmt.Println("cap(mint):", cap(mslice))

    mslice = append(mslice, 1, 2, 3)
    fmt.Println("mint:", mslice)

    mslice = mslice[:len(mslice) - 1]
    fmt.Println("切片移除最后一位:", mslice)

    mslice = append(mslice[:5 - 1], mslice[5 + 1:]...)
    fmt.Println("删除索引5:", mslice)


map的使用

map简单例子

package main

import (
    "fmt"
)

/**
类型: 个人信息
 */
type PersonInfo struct {
    ID      string
    Name    string
    Address string
}

func main() {
    //定义一个map
    var personDB map[string]PersonInfo
    //用make函数创建一个map
    personDB = make(map[string]PersonInfo)

    //插入几条数据
    personDB["123"] = PersonInfo{"123", "xiaoming", "aaa strt"}
    personDB["124"] = PersonInfo{"124", "xiaoli", "fsdfsdfs"}

    //查找map
    fmt.Println("ID为:123的人是:", personDB["123"])

    // ok是一个返回的bool型,返回true表示找到了对应的数据
    person, ok := personDB["124"]
    if ok {
        fmt.Println("找到了人:", person)
    } else {
        fmt.Println("没找到")
    }
}

map 例子

package main

import (
    "fmt"
)

/**
类型: 个人信息
 */
type PersonInfo struct {
    ID      string
    Name    string
    Address string
}

func main() {
    //定义一个map
    var personDB map[string]PersonInfo
    //用make函数创建一个map
    personDB = make(map[string]PersonInfo)

    //插入几条数据
    personDB["123"] = PersonInfo{"123", "xiaoming", "aaa strt"}
    personDB["124"] = PersonInfo{"124", "xiaoli", "fsdfsdfs"}

    //查找map
    fmt.Println("ID为:123的人是:", personDB["123"])

    // ok是一个返回的bool型,返回true表示找到了对应的数据
    person, ok := personDB["124"]
    if ok {
        fmt.Println("找到了人:", person)
    } else {
        fmt.Println("没找到")
    }


    //删除元素
    fmt.Println("删除前:", personDB)
    delete(personDB, "123")
    fmt.Println("删除后:", personDB)
}

goto跳转

跳转到指定的标记位置

package main

import "fmt"

func main() {
    i := 0
    //一个标记位
    FLAG:
    fmt.Println(i)
    i++
    if i < 10 {
        //跳转到标记位置
        goto FLAG
    }
}

func函数

创建函数

package mymath

import (
    "errors"
)

func Add(a int, b int) (result int, err error) {
    if a < 0 || b < 0 {
        //假设只支持正数
        err = errors.New("只能输入正数!")
        return
    }

    result = a + b
    return
}

任意类型不定参数

package main

import "fmt"
/**
任意类型的不定参数
 */

/**
interface{}: 任意类型的参数
...  代表不定长度
 */
func MyPrintf(args ...interface{}) {
    for _, arg := range args {
        switch arg.(type){
        case int:
            fmt.Println(arg, "is an int value")
        case int8:
            fmt.Println(arg, "is an int8 value")
        case string:
            fmt.Println(arg, "is string value")
        default:
            fmt.Println(arg, "is an unknow type")
        }

    }
}

func main() {
    var a int = 1
    var b int8 = 121
    var c string = "fsdfsf"
    var d map[string]string = make(map[string]string)

    MyPrintf(a, b, c, d)

}

匿名函数与闭包

package main

import (
    "fmt"
)

func main() {
    var j int = 5
    //a是一个返回函数的函数立即执行的结果,所以a最终是一个函数.
    a := func() (func()) {
        var i int = 10
        return func() {
            fmt.Printf("i,j : %d,%d \n", i, j)
        }
    }()
    a()
    j *= 2
    a()
}

执行结果:
i,j : 10,5
i,j : 10,10

错误处理

defer

func copyFile(dst, src string) (w int64, err error) {
    srcFile, err := os.Open(src)
    if err != nil {
        return
    }

    //这个收尾工作,一定会执行,而且是从后往前执行!
    defer srcFile.Close()

    dstFile, err := os.Create(dst)
    if err != nil {
        return
    }

    defer dstFile.Close()

    return io.Copy(dstFile, srcFile)

}

panic recover

调用panic后程序就真的挂了,再也无法执行了!
所以尽量还是用return error 的形式处理错误.

package main

import (
    "fmt"
    "log"
)

func foo() {
    fmt.Println("a")
    panic("我报错啦!")
    fmt.Println("b")
}

func main() {

    defer func() {
        if r := recover(); r != nil {
            log.Printf("Runtime Error caught: %v", r)
        }
    }()
    
    foo()
    
    fmt.Println("c")

}

输出结果:
a
2016/11/26 21:31:58 Runtime Error caught: 我报错啦!

Process finished with exit code 0

flag 用户参数解析

在执行二进制文件时, 输入 -o -i 等参数.

package main

import (
    "flag"
    "fmt"
)

// 第二个参数是默认值
var infile *string = flag.String("i", "infile", "File contais values for sorting")
var outfile *string = flag.String("o", "outfile", "File to receive sorted values")
var algorithm *string = flag.String("a", "qsort", "Sort algorithm")

func main() {
    flag.Parse()

    if infile != nil {
        fmt.Println("infile:", *infile, " outfile:", *outfile, " algorithm:", *algorithm)
    }

}

面向对象编程

简单例子

package main

import "fmt"

type Hero struct {
    name      string
    mana      int
    skill     string
    skillCost int
    horse     *Horse
}

//receiver使用指针类型,可以改变实例的属性,否则不能.
func (hero *Hero) useSkill() {
    fmt.Println(hero.name + "发动技能:" + hero.skill)
    hero.mana -= hero.skillCost
}

func (hero *Hero) sayMana() {
    fmt.Printf("%s还有%d%%的魔法值!", hero.name, hero.mana)
}

/**
玩家的马
 */
type Horse struct {
    name   string //名字
    hungry int    //饥饿度
    speed  int    //跑速
}

func (horse *Horse) run() {
    fmt.Println(horse.name, "跑起来了,当前饥饿度:", horse.hungry)
    horse.hungry -= 1
}

func main() {
    gailun := &Hero{name:"盖伦", mana:500, skill:"大保剑", skillCost:60}
    chitu := &Horse{"赤兔", 100, 5}

    gailun.horse = chitu

    for i := 0; i < 5; i++ {
        gailun.useSkill()
        gailun.sayMana()
        gailun.horse.run()
    }
}

接口

接口查询

判断一个实例对象是不是某一种类型(接口或对象的指针)

if file5, ok := file1.(two.IStream); ok {
...
}

var file1 Writer = ...
if file6, ok := file1.(*File); ok {
...
}

类型查询

var v1 interface{} = ...
switch v := v1.(type) {
case int:
// 现在v的类型是int
case string: // 现在v的类型是string
...
}

goroutin 并发编程

chan通信

核心理念: 不要通过共享内存来通信,而应该通过通信来共享内存
无缓冲channel: 任何读写操作都会使当前goroutin立即阻塞,直到该channel被读取或被写入为止.

package main

import "fmt"

func count(ch chan int) {
    ch <- 1
    fmt.Println("counting")
}

func main() {
    //定义一个存放channel的数组
    chs := make([]chan int, 10)

    //初始化并启动chan数组
    for i, _ := range chs {
        chs[i] = make(chan int)
        go count(chs[i])
    }

    //读取chan数组
    for i, _ := range chs {
        <-chs[i]
    }
}

带缓冲的channel

第2个参数如果不加就是不带缓冲的.
c := make(chan int, 1024)

select机制

case 语句里必须是一个IO操作.(chan操作?)
case 是同时随机判断的,没有判断顺序.
当一个case满足条件时,整个select退出.
当所有case都不满足时,走default.

package main

import "fmt"

func main() {
    ch1 := make(chan int)
    ch2 := make(chan int)

    go func() {
        ch2 <- 2
        ch1 <- 1
    }()

    select {
        case <-ch1:
            fmt.Println("ch1")
        case <-ch2:
            fmt.Println("ch2")
    }

}

超时机制

// 首先,我们实现并执行一个匿名的超时等待函数
timeout := make(chan bool, 1)

go func() {
    time.Sleep(1e9) // 等待1秒钟
    timeout <- true
}()

// 然后我们把timeout这个channel利用起来
select {
    case <-ch:
    // 从ch中读取到数据
    case <-timeout:
    // 一直没有从ch中读取到数据,但从timeout中读取到了数据
}

多核并行

真正意义上的并发,直接使用多个CPU.
runtime.GOMAXPROCS(runtime.NumCPU())
fmt.Println(runtime.NumCPU())

sync.Once 全局唯一性操作

once 的 Do() 方法可以保证在全局范围内只调用指定的函数一次(这里指匿名函数),
而且所有其他goroutine在调用到此语句时,将会先被阻塞,直至全局唯一的once.Do() 调用结束后才继续。

once := sync.Once{}
once.Do(func() {
fmt.Println("aaa")
})

sync.Mutex 加锁机制

采用加锁的机制,即通过共享内存来实现通信,不推荐这种方式

package main

import (
    "fmt"
    "sync"
    "time"
)

//申明一个锁,同时锁住读写,
var mutex sync.Mutex
var count int = 0

/**
采用加锁的机制,即通过共享内存来实现通信,不推荐这种方式    
 */
func main() {
    for i := 0; i < 5; i++ {
        go visit()
    }

    time.Sleep(10 * time.Second)

}

func visit() {
    //加锁
    mutex.Lock()
    //释放锁
    defer mutex.Unlock()
    count += 1
    fmt.Println(count)
}

你可能感兴趣的:(golang学习)