golang

理解GOPATH

go env # 查看go环境变量

window下设置环境变量:
   set GOPATH=F:\goprojects
window下查看环境变量:
   echo %GOPATH%

$GOPATH目录约定有三个子目录

src存放源代码(比如: .go .c .h .s等)
pkg编译后生成的文件
bin编译后生成的可执行文件(为了方便可以把此目录加到$PATH中)

go get 下载包

go get github.com/beego/bee
下载到本地:
$GOPATH/src/github.com/beego/bee

自己写一个包

$GOPATH目录下新建/src/test/print_hello.go文件

package test
import "fmt"
func Hello() {
    fmt.Printf("你好")
}

$GOPATH目录下main.go引入test包
package main
import (
    "test"
)
func main() {
    test.Hello()
}

GO语言基础

变量声明

var关键字(类型声明放到变量后面):
var x int = 0

简短声明(无法定义于函数体外部):
x := 0

常量

const name string = 'zhorz'
const PI = 3.14

数据类型

bool, rune, int8, int16, int32, int64
byte, uint8, uint16, uint32, uint64
float32, float64
complex64 complex128 (支持复数运算)
string, array, slice, map (相当于php中的array)

golang数组

1.普通声明
var a [10]int
a[0] = 1
fmt.Printf("%v", a);
2.速记声明
a := [...]int{} // 可以不用执行数组内容和长度, 不指定内容初始值为0, [...]表示自动计算长度 
fmt.Printf("%v", a)
3.数组的长度是数组类型的一部分
a := [3]int{5, 78, 8}
var b [5]int
b = a //[5]int 和 [25]int 是两个不同类型的数组
4.数组是值类型
a := [...]string{"USA", "China", "India", "Germany", "France"}
b := a
b[0] = "Singapore"// 不会改变原数组a, 数组做为函数参数也是值传递
5.内置函数len可以获取数组长度
6.循环数组
a := [...]float64{67.7, 89.8, 21, 78}
for i := 0; i < len(a); i++ {
    fmt.Printf("%d th element of a is %.2f\n", i, a[i])
}
或者
a := [...]float64{67.7, 89.8, 21, 78}
for i, v:=range a {
    fmt.Printf("%d th element of a is %.2f\n", i, v)
}

golang切片

1.普通声明(元素类型为 T 的切片表示为: []T)
a := []int{1,2,3}
2.从数组创建切片
a := [5]int{76, 77, 78, 79, 80}
var b []int = a[1:4]// 创建了一个a[1]到a[3]的切片
3.对切片进行的任何修改都将反映在底层数组中
func main() {
    a := [5]int{76, 77, 78, 79, 80}
    fmt.Println(a)
    var b []int = a[1:4]
    for i,_ := range b {
        b[i]++
    }
    fmt.Println(a)
}
4.切片的长度和容量
a.切片的长度是指切片中元素的个数
b.切片的容量是指从切片的起始元素开始到其底层数组中的最后一个元素的个数(内置函数cap返回切片容量)
6.make创建切片(make用于内建类型map, slice,channel..的内存分配)
i := make([]int, 5, 5)
fmt.Println(i)
7.动态给切片添加元素
a := [5]int{76, 77, 78, 79, 80}
b := a[:]
b = append(b, 10)
fmt.Println(b)
8.一个 nil 切片的长度和容量都为 0
var b []string // b还么占据内存, 所以还是nil
fmt.Println(b==nil)
9.切片复制
countries := []string{"USA", "Singapore", "Germany", "India", "Australia"}
neededCountries := countries[:len(countries)-2]
countriesCpy := make([]string, len(neededCountries))
copy(countriesCpy, neededCountries)

golang的map

1.创建语法 make(map[KeyType]ValueType)
var class map[string]int // class == nil, map 的 0 值为 nil。试图给一个 nil map 添加元素给会导致运行时错误。因此 map 必须通过 make 来初始化
class = make(map[string]int)
或使用速记方式声明
class := make(map[string]int)
class["name"] = 1
fmt.Println(class)

2.元素赋值
    personSalary := map[string]int {
        "steve": 12000,
        "jamie": 15000,
    } // 这种方式不用make了?
    personSalary["mike"] = 9000
    fmt.Println("personSalary map contents:", personSalary)
3.如何检测一个键是否存在于一个 map 中呢
value, ok := map[key]  // ok为true则存在, 否则不存在
4.可以用for range遍历map
    personSalary := map[string]int {
        "steve": 12000,
        "jamie": 15000,
        "mike" : 9000,
    }
    for key,value := range personSalary {
        fmt.Printf("%s salary is:%d\n", key, value)
    }
5.删除元素
delete(map, key) 用于删除 map 中的 key。delete 函数没有返回值
6.用内置函数 len 获取 map 的大小
7.map和slice一样是引用赋值
8.map 不能通过 == 操作符比较是否相等。== 操作符只能用来检测 map 是否为 nil, 比较两个 map 是否相等的方式是一一比较它们的元素是否相等

golang流程语句

1.for语句
for语句也可以像while一样使用
    x := 1
    for {
        x++
    }
2.switch语句, 默认加了break, 如果不break, 使用fallthrough
    x := 1
    switch x {
        case 1:
            fmt.Print("hello 1")
            fallthrough
        case 2:
            fmt.Print("hello 2")
        default:
            fmt.Print("hello 3")
    }
3.range也可以遍历字符串
    str := "zhoujinglun"
    for _, v := range str {
        fmt.Printf("%c", v)
    }

golang函数

格式:
func funcName(input1 type1,input2 type2) (type1, type2) {
    // 可以返回多个值
    return value1,value2
}

例子:
func swap(a int, b int) (int, int) {
    var tmp int
    tmp = a
    a = b
    b = tmp
    return a,b
}
func main() {
    a := 1
    b := 2
    c,d := swap(a, b)
    fmt.Printf("%d %d", c, d)
}
指针:
func pointer(a *int) {
    (*a)++
}
func main() {
    a := 1
    pointer(&a)
    fmt.Printf("%d", a)
}
数组:
func sum_arr(arr []int)(int) {
    var sum int
    for i:=0;i<len(arr);i++ {
        sum += arr[i]
    }
    return sum
}
func main() {
    arr := []int{}
    for i:=0; i<100; i++ {
        arr = append(arr, i)
    }
    result := sum_arr(arr)
    fmt.Println(result)
}
匿名函数:
func main() {
    f := func (x int, y int) int {
        return x+y
    }
    fmt.Println(f(1,2))
}
defer(延迟执行):
    for i:=1; i<=5; i++ {
        defer func(a int) {
            fmt.Println(a)
        }(i)
    }
GO的异常处理方式: panic和recover
// todo


声明函数为一种类型, 类似c语言的typedef
func main() {
    type sum func(x int, y int)int
    var f sum
    f = func(x int, y int)int {
        return x+y
    }
    fmt.Print(f(1,2))
}

golang的结构体struct

# 结构体包含map
type Human struct {
    name string
    age int
    weight int
}
type Student struct {
    Human // 匿名字段, 默认包含Human所有字段
    special string
    job map[string]string
}

func main() {
    jane := Student {
        Human: Human {
            name: "jane", 
            age: 20, 
            weight: 99,
        },
        special: "somthing",
        job: map[string]string {
            "name": "doctor",
        },
    }
    zhorz := Student { 
        Human {"zhorz", 10, 11},
        "test",
    }
    fmt.Printf("%v, %v", zhorz.Human, jane.special)
}

# map包含结构体
type people struct {
    name string
    age int
}

student := map[string]people {
    "mike": people {
        name: "zhorz",
        age: 20,
    },
}
fmt.Println(student)

# map数组
student := map[string][]int {
    "mike": {1,2,3},
}
fmt.Println(student)

golang没有private, protect, public关键字, 要使某个符号对其他包可以访问, 需要将该符号定义为大写字母开头

# 举个例子
# 类型和作用在它上面的方法必须在同一个包定义, 不能在int float类型中定义方法
type Dick struct {
    length int
}

func (this Dick) getLength() int {
    return this.length + 999
}

type Student struct {
    dick Dick # 仅仅写Dick就是继承, 否则dick只是一个类型为Dick成员对象
    name string
    age int
}

func (this Student) getName() string{
    return this.name
}

func (this *Student) setName(name string){
    this.name = name
}

func main() {
    student := Student {
        name: "zhorz",
        age : 20,
        dick : Dick {
            length : 0,
        },
    }
    student.setName("other")
    # 其他类的初始化方式 
    stu := new(Student)
    stu := &Student{}
    stu := &Student{age:20}
    stu := Student{age:20}
    fmt.Printf("%v", student.dick.getLength())
}

非侵入式实现接口

type People interface {
    getName() string
    getAge() int
}
type Student struct {
    name string
    age int
}
func (this Student) getName() string {
    return this.name
}
func (this Student) getAge() int {
    return this.age
}
func main() {
    var p People
    stu := Student {
        name: "zhorz",
        age: 23,
    }
    p = stu
    fmt.Println(p.getName())
}

golang任何对象类型都满足空接口(interface{})

var v1 interface{}
v1 = "string" // v1可以等于任何类型变量, 应该任何类型变量都实现了interface接口

// 类型查询语法v1
if v,ok := v1.(string); ok {

}
// 类型查询语法v2
switch v1.(type) {
    case int:
    case string:
    case map:
    case slice:
    ...
}

golang并发编程之协程

package main

import (
    "fmt"
    "time"
)

func test() {
    fmt.Println("test")
}

func main() {
    for i:=1;i<=10;i++ {
        go test() // 开启了协程
    }
    time.Sleep(1)
}

golang并发编程之channel

// golang在语言级别提供的协程间通信方式
// 声明: var chanName chan ElementType; chanName = make(chan ElementType)
// 或使用: chanName := make(chan ElementType)

// channel的读和写 (通过阻塞实现协程间同步?)
// ch <- c 写(阻塞)
// c := <-ch 读(阻塞)

// demo1
var complete := make(chan int)
func loop() {
    for i := 0; i < 10; i++ {
        fmt.Printf("%d ", i)
    }
    complete <- 0 // 执行完毕了,发个消息
}
func main() {
    go loop()
    <- complete // 直到线程跑完, 取到消息. main在此阻塞住
}

// demoe2
func alert(i int, ch chan int) {
    fmt.Println(i*i)
    ch <- 1
}

func main() {

    chs := make([]chan int, 10)

    for i:= 0; i < 10; i++ {
        chs[i] = make(chan int)
        go alert(i, chs[i])
    }

    for _,v := range chs {
        <- v
    }
}

// demo3 带缓冲channel
func alert() {
    ch <- 1
    fmt.Println("alert 1")
    ch <- 1
    fmt.Println("alert 2")
    ch <- 1
    fmt.Println("alert 3")
}
var ch chan int
func main() {
    ch = make(chan int, 2)
    go alert()
    // time.Sleep(2*time.Second)   
    fmt.Println("main")
    <- ch
    time.Sleep(time.Second)   
}

协程让出或阻塞

import(
    "fmt"
    "runtime"
)
func main() {
    ch1 := make(chan int)
    ch2 := make(chan int)

    go func () {
        for i:=1; i<100; i++ {
            if i == 1 {
                runtime.Gosched()
            }
            fmt.Println(i)
        }
        ch1<-1
    }()

    go func () {
        for i:=100; i<200; i++ {
            fmt.Println(i)
        }
        ch2<-2
    }()

    <-ch1
    <-ch2
}

golang值select

// 基本用法
select {
    case <-ch1: // 如果ch1成功读取数据
    case ch2<-1: // 如果成功向ch2写入数据
    default: // 如果上面都没执行, 则进入default
}

// 经典处理阻塞超时的select用法
func main() {
    ch := make(chan int)
    timeout := make(chan int)

    go func (timeout chan int) {
        time.Sleep(5*time.Second)
        timeout <- 1
    }(timeout)

    select {
        case <- ch:
            fmt.Println("hello")
        case <- timeout:
            fmt.Println("timeout after 5 second")
        case <- time.After(2*time.Second):
            fmt.Println("timeout after 2 second")
    }
}

golang的json和md5

package main

import (
    "fmt"
    "encoding/json"
    "crypto/md5"
)

func main() {
    // 数组类型json
    array := []int {1,2,3,4,5}
    array_json, err := json.Marshal(array)
    if (err != nil) {
        panic(err)
    }
    fmt.Println(string(array_json))

    // json解码示例
    var array_decode interface{}
    json.Unmarshal(array_json, &array_decode)
    fmt.Println(array_decode)

    // map类型json
    maps := map[string]int {
        "zhorz" : 1,
    }
    // maps["zhorz"] = 1

    maps_json, err := json.Marshal(maps)
    if (err != nil) {
        panic(err)
    }
    fmt.Println(string(maps_json))

    // 结构体类型json
    type Student struct {
        Name string // 大写开头的字段才会被json格式化
        Age int `json:"student_age"` // 替换json格式化后的字段名称
        sex string
    }
    student := Student {"zhorz", 23, "man"}
    student_json, err := json.Marshal(student)
    if (err != nil) {
        panic(err)
    }
    fmt.Println(string(student_json))

    var student_decode interface{}
    json.Unmarshal(student_json, &student_decode)
    fmt.Println(student_decode) // 结构体json_decode成了map

    // md5示例
    
    Md5 := md5.New()
    Md5.Write([]byte("zhorz"))
    res := Md5.Sum([]byte(""))
    fmt.Printf("%x\n", res)
}

golang之http

http服务器

// 引入包 net/http
// 注册路由
http.HandleFunc("/hello", func(w http.ResponseWriter, r *http.Request) {
    w.Write([]byte("hello world"))
})

http.HandleFunc("/zhorz", func(w http.ResponseWriter, r *http.Request) {
    w.Write([]byte("hello zhorz"))
})

// 开启简单http服务器
http.ListenAndServe("127.0.0.1:8080", nil)  

http请求

package main

import(
    "fmt"
    "net/http"
    "io/ioutil"
)

func main() {
    // get请求
    response, err := http.Get("http://www.baidu.com")
    // post请求
    response, err := http.Post(
        "http://www.baidu.com", 
        "application/x-www-form-urlencoded", 
        strings.NewReader("name=zhorz&age=1"),
    )


    if (err != nil) {
        panic(err)
    }
    defer response.Body.Close()
    body, err := ioutil.ReadAll(response.Body)
    fmt.Println(string(body))
}

golan之正则表达式

golang正则参考: http://www.cnblogs.com/golove/p/3269099.html

// go语言标准库提供的regexp包
import(
    "fmt"
    "regexp"
)

func main() {

    // 语法
    // func Match(pattern string, b []byte) (matched bool, err error)
    // func MatchString(pattern string, s string) (matched bool, err error)

    // func MustCompile(str string) *RegExp

    // func (re *RegExp) FindAllString(s string, n int) []string
    // func (re *RegExp) FindAllStringSubmatch(s string, n int) []string

    isMatch, _ := regexp.MatchString(`[\w]{5}`, "zhorz")

    fmt.Println(isMatch)

    reg := regexp.MustCompile(`[\w]{1,5}`) // 如果是""\w需要转义\\w, ``则不需要

    result := reg.FindAllString(`zho1rza(bc)`, -1) // -1 表示返回所有匹配的内容

    fmt.Println(result)

    // 捕获正则表达式
    // (exp) 匹配ext, 并捕获文本到自动命名组里
    // (?<name>exp),(?'name'exp)  匹配ext, 并捕获文本到名称name的组里
    // (?:exp) 匹配exp, 不捕获匹配的文本, 也不给此分组分配组号
}

golang的mysql增删改查

package main

import(
    "fmt"
    "database/sql"
    _ "github.com/go-sql-driver/mysql"
)

func main() {
    // 链接数据库DNS格式
    // user@unix(/path/to/socket)/dbname?charset=utf8
    // 1.链接
    db, err := sql.Open("mysql", "root:@tcp(127.0.0.1:3306)/fcurd?charset=utf8")
    defer db.Close()
    if err != nil { panic(err) }
    // 2.增
    stmt, err := db.Prepare("INSERT admin_user SET username=?,real_name=?")
    if err != nil { panic(err) }
    res, err := stmt.Exec("golang", "go语言")
    if err != nil { panic(err) }
    id, err := res.LastInsertId()
    if err != nil { panic(err) }
    fmt.Println(id)

    // 3.改
    stmt, err := db.Prepare("UPDATE admin_user SET username=? WHERE id=?")
    if err != nil { panic(err) }
    res, err := stmt.Exec("golang_update", "7")
    if err != nil { panic(err) }
    rows, err := res.RowsAffected()
    if err != nil { panic(err) }
    fmt.Println(rows)

    // 4.查询
    rows, err := db.Query("SELECT id,username,real_name FROM admin_user")
    defer rows.Close()
    if err != nil {
        panic(err)
    }
    for rows.Next() {
        var id int
        var username string
        var real_name string
        rows.Scan(&id, &username, &real_name)
        fmt.Println(id, username, real_name)
    }

    // 5.删除
    stmt,err := db.Prepare("DELETE FROM admin_user WHERE id=?")
    if err != nil { panic(err) }
    res, err := stmt.Exec("8")
    if err != nil { panic(err) }
    rows, err := res.RowsAffected()
    if err != nil { panic(err) }
    fmt.Println(rows)


    // 6.单条记录
    var name string
    err = db.QueryRow("SELECT username FROM admin_user WHERE id = ?", 7).Scan(&name)
    fmt.Println(name)

    // 7.事务
    tx := db.Begin()
    tx.Rollback()
    tx.Commit()
}

golang聊天室(1)

# server端
package main

import(
    "fmt"
    "net"
)

func CheckError(err error) {
    if (err != nil) {
        panic(err)
    }
}

func ProcessInfo(conn net.Conn) {
    // 创建缓冲区
    buf := make([]byte, 1024)
    defer conn.Close()

    for {
        numOfBytes, _ := conn.Read(buf)
        if numOfBytes == 0 {
            break
        }
        fmt.Printf("has received %s", string(buf))
    }
}

func main() {
    socket, err := net.Listen("tcp", "127.0.0.1:8080")
    CheckError(err)
    defer socket.Close()
    fmt.Println("starting....")
    for {
        conn, err := socket.Accept()
        CheckError(err)
        go ProcessInfo(conn)
    }
    
}
# client端
package main

import(
    "fmt"
    "net"
)

func CheckError(err error) {
    if (err != nil) {
        panic(err)
    }
}


func main() {
    conn, err := net.Dial("tcp", "127.0.0.1:8080")
    CheckError(err)
    defer conn.Close()
    conn.Write([]byte("hello world"))
    fmt.Println("had send the message")
}

golang聊天室(2)

# server端
package main

import(
    "fmt"
    "net"
)

func CheckError(err error) {
    if (err != nil) {
        panic(err)
    }
}

func ProcessInfo(conn net.Conn) {
    // 创建缓冲区
    buf := make([]byte, 1024)
    defer conn.Close()

    for {
        numOfBytes, err := conn.Read(buf)
        if err != nil {
            break
        }
        if numOfBytes != 0 {
            remoteAddr := conn.RemoteAddr()
            fmt.Printf(remoteAddr.String())
            fmt.Println(" server has received:" + string(buf[:numOfBytes]))
            conn.Write([]byte("you just say: " + string(buf[:numOfBytes])))
        }
    }
}

func main() {
    socket, err := net.Listen("tcp", "127.0.0.1:8080")
    CheckError(err)
    defer socket.Close()
    fmt.Println("starting....")
    for {
        conn, err := socket.Accept()
        CheckError(err)
        go ProcessInfo(conn)
    }
    
}
# client端
package main

import(
    "fmt"
    "net"
    "bufio"
    "os"
    "strings"
)

func CheckError(err error) {
    if (err != nil) {
        panic(err)
    }
}

func MessageSend(conn net.Conn) {
    var input string
    for {
        reader := bufio.NewReader(os.Stdin)
        data, _, _ := reader.ReadLine()
        input = string(data)
        if strings.ToUpper(input) == "EXIT" {
            conn.Close()
            break
        }
        _, err := conn.Write([]byte(input))
        if err != nil {
            conn.Close()
            fmt.Println("client connect fail" + err.Error())
        }
    }
}

func main() {
    conn, err := net.Dial("tcp", "127.0.0.1:8080")
    CheckError(err)
    defer conn.Close()
    go MessageSend(conn)
    buf := make([]byte, 1024)
    for {
        numOfBytes, err := conn.Read(buf)
        CheckError(err)
        if numOfBytes != 0 {
            fmt.Println("client has received: " + string(buf))
        }
    }

    fmt.Println("client process end!")
}

内置log包记录日志信息

    // 创建文件
    var logFile *os.File
    var logger *log.Logger
    logFile, err := os.OpenFile("./debug.log", os.O_RDWR | os.O_APPEND, 0)
    if err != nil {
        panic(err)
    }
    defer logFile.Close()
    // 记录日志
    logger = log.New(logFile, "", log.Ldate|log.Ltime|log.Llongfile)
    logger.Println("log file")

标签: none