GO 语言快速学习 | PHP转GO笔记

web框架

流行度排行

https://github.com/speedwheel/awesome-go-web-frameworks/blob/master/README.md#popularity

beego

https://beego.me/products

echo

https://echo.labstack.com/

gin
go社区文档

https://learnku.com/docs/gin-gonic/2019

看云gin文档

https://www.kancloud.cn/shuangdeyu/gin_book/949418

gin快速使用

https://www.jianshu.com/p/98965b3ff638

gin-admin-vue

https://www.gin-vue-admin.com/docs/gorm

官网

https://golang.org/dl/

中文官网

https://go-zh.org/pkg/

go常用库

https://github.com/jobbole/awesome-go-cn

查看版本号

go version

查看env

go env

==拉不下来包==

export GOPATH=/usr/local/go/bin
export GOPROXY=https://goproxy.io
export PATH=$PATH:$GOPATH
export GO111MODULE=on

开启module

go env -w GO111MODULE=on

设置代理

go env -w GOPROXY=https://goproxy.io,direct

微服务框架

go-kit

go micro

go-zero

常用网址

go基础知识

go基础知识v1

go基础知识v2---micro

菜鸟GO

文档和技术论坛

gomod 详细使用

go官网库

==go官方pkg中文==

github对pgk的使用例子

go mod使用

基本数据类型

字符串操作

本地gorm struct生成

https://github.com/xxjwxc/gormt.git

本地struct生成

https://github.com/hantmac/fuckdb.git

1 使用docker-composer方式启动
2 遇到docker容器不能链接本地mysql的时候 
在本地mysql
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'root' WITH GRANT OPTION;
FLUSH PRIVILEGES

struct 生成

go get -u github.com/gohouse/converter

err := converter.NewTable2Struct().
    SavePath("./model.go").
    Dsn("root:root@tcp(127.0.0.1:3306)/foroo_beta_shopify?charset=utf8").
    TagKey("db").
    EnableJsonTag(true).
    Table("fr_store").
    Run()
fmt.Println(err)
return

基础

变量或者方法使用小写相当于protect 首字母大写 相当于public

使用+来拼接字符串

变量声明 var age int;

常量中的数据类型只可以是布尔型、数字型(整数型、浮点型和复数)和字符串型。

可以将 var f string = "Runoob" 简写为 f := "Runoob":

函数外的每个语句都必须以关键字开始(var、const、func等)

:=不能使用在函数外。

多用于占位,表示忽略值。import _ "./hello" 用占位只会执行导入包内的init,其他方法都不能调用

iota是go语言的常量计数器,只能在常量的表达式中使用

strconv.Itoa(97) 将一个数字转成字符串类型 string(97)go自带的会把数字转换成对应的ascii码

  const (
            n1 = iota //0
            n2        //1
            n3        //2
            n4        //3
        )

map、slice、chan、指针、interface默认以引用的方式传递。

互斥锁 var lock sync.Mutex

var x int64
var wg sync.WaitGroup
var lock sync.Mutex

func add() {
    for i := 0; i < 5000; i++ {
        lock.Lock() // 加锁
        x = x + 1
        lock.Unlock() // 解锁
    }
    wg.Done()
}
func main() {
    wg.Add(2)
    go add()
    go add()
    wg.Wait()
    fmt.Println(x)
}

读写互斥锁 需要注意的是读写锁非常适合读多写少的场景,如果读和写的操作差别不大,读写锁的优势就发挥不出来。

var (
    x      int64
    wg     sync.WaitGroup
    lock   sync.Mutex
    rwlock sync.RWMutex
)

func write() {
    // lock.Lock()   // 加互斥锁
    rwlock.Lock() // 加写锁
    x = x + 1
    time.Sleep(10 * time.Millisecond) // 假设读操作耗时10毫秒
    rwlock.Unlock()                   // 解写锁
    // lock.Unlock()                     // 解互斥锁
    wg.Done()
}

func read() {
    // lock.Lock()                  // 加互斥锁
    rwlock.RLock()               // 加读锁
    time.Sleep(time.Millisecond) // 假设读操作耗时1毫秒
    rwlock.RUnlock()             // 解读锁
    // lock.Unlock()                // 解互斥锁
    wg.Done()
}

func main() {
    start := time.Now()
    for i := 0; i < 10; i++ {
        wg.Add(1)
        go write()
    }

    for i := 0; i < 1000; i++ {
        wg.Add(1)
        go read()
    }

    wg.Wait()
    end := time.Now()
    fmt.Println(end.Sub(start))
}

sync.Once其实内部包含一个互斥锁和一个布尔值,互斥锁保证布尔值和数据的安全,而布尔值用来记录初始化是否完成。这样设计就能保证初始化操作的时候是并发安全的并且初始化操作也不会被执行多次。

var icons map[string]image.Image

var loadIconsOnce sync.Once

func loadIcons() {
    icons = map[string]image.Image{
        "left":  loadIcon("left.png"),
        "up":    loadIcon("up.png"),
        "right": loadIcon("right.png"),
        "down":  loadIcon("down.png"),
    }
}

// Icon 是并发安全的
func Icon(name string) image.Image {
    loadIconsOnce.Do(loadIcons)
    return icons[name]
}

==goroutine高并发下 操作map 要用 sync.Map 来操作==

//sync.Map内置了诸如Store、Load、LoadOrStore、Delete、Range等操作方法
var m = sync.Map{}

func main() {
    wg := sync.WaitGroup{}
    for i := 0; i < 20; i++ {
        wg.Add(1)
        go func(n int) {
            key := strconv.Itoa(n)
            m.Store(key, n)
            value, _ := m.Load(key)
            fmt.Printf("k=:%v,v:=%v\n", key, value)
            wg.Done()
        }(i)
    }
    wg.Wait()
}

==代码中的加锁操作因为涉及内核态的上下文切换会比较耗时、代价比较高。针对基本数据类型我们还可以使用原子操作来保证并发安全,因为原子操作是Go语言提供的方法它在用户态就可以完成,因此性能比加锁操作更好。Go语言中原子操作由内置的标准库sync/atomic提供。==

// 原子操作版加函数
func atomicAdd() {
    atomic.AddInt64(&x, 1)
    wg.Done()
}

make只用于slice、map以及channel的初始化,返回的还是这三个引用类型本身

变量之间使用引用地址直接可以改变

package main
func swap(a, b *int) {
    var temp int
    temp = *a
    *a = *b
    *b = temp
}

func main() {
    var a, b = 1, 2
    swap(&a, &b)

    fmt.Println(a)
    fmt.Println(b)
}
//指针小案例
var a int
fmt.Println(&a)
var p *int
p = &a
*p = 20
fmt.Println(a)

在参数赋值时可以不用用一个一个的赋值,可以直接传递一个数组或者切片,特别注意的是在参数后加上“…”即可

package main

import (
    "fmt"
)

func test(s string, n ...int) string {
    var x int
    for _, i := range n {
        x += i
    }

    return fmt.Sprintf(s, x)
}

func main() {
    s := []int{1, 2, 3}
    res := test("sum: %d", s...)    // slice... 展开slice
    println(res)
}

"_"标识符,用来忽略函数的某个返回值

没有参数的 return 语句返回各个返回变量的当前值。这种用法被称作“裸”返回。

func add(a, b int) (c int) {
    c = a + b
    return
}

func calc(a, b int) (sum int, avg int) {
    sum = a + b
    avg = (a + b) / 2

    return
}

func main() {
    var a, b int = 1, 2
    c := add(a, b)
    sum, avg := calc(a, b)
    fmt.Println(a, b, c, sum, avg)
}

命名返回参数允许 defer 延迟调用通过闭包读取和修改。

defer 是先进后出

package main

func add(x, y int) (z int) {
    defer func() {
        z += 100
    }()

    z = x + y
    return
}

func main() {
    println(add(1, 2)) 
}

定义一维数组

var a [5]int = [5]int{1,2,5,6,7}
var a = [...]int{1,2,3,5,6}
 d := [...]struct {
        name string
        age  uint8
    }{
        {"user1", 10}, // 可省略元素类型。
        {"user2", 20}, // 别忘了最后一行的逗号。
    }

定义二维数组 第 2 纬度不能用 "..."

var b [3][2]int = [3][2]int{{1,2},{3,4},{5,6}}
var arr1 [2][3]int = [...][3]int{{1, 2, 3}, {7, 8, 9}}

定义slice

全局:
var arr = [...]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
var slice0 []int = arr[start:end] 
var slice1 []int = arr[:end]        
var slice2 []int = arr[start:]        
var slice3 []int = arr[:] 
var slice4 = arr[:len(arr)-1]      //去掉切片的最后一个元素
局部:
arr2 := [...]int{9, 8, 7, 6, 5, 4, 3, 2, 1, 0}
slice5 := arr[start:end]
slice6 := arr[:end]        
slice7 := arr[start:]     
slice8 := arr[:]  
slice9 := arr[:len(arr)-1] //去掉切片的最后一个元素
//通过make来创建切片
var slice []type = make([]type, len)
slice  := make([]type, len)
slice  := make([]type, len, cap)

定义map

    scoreMap := make(map[string]int)
    scoreMap["张三"] = 90
    scoreMap["小明"] = 100
    // 如果key存在ok为true,v为对应的值;不存在ok为false,v为值类型的零值
    v, ok := scoreMap["张三"]
    if ok {
        fmt.Println(v)
    } else {
        fmt.Println("查无此人")
    }
    //使用delete()函数删除键值对
      delete(scoreMap, "小明")//将小明:100从map中删除

数组按照下标排序输出

    tetcc := make(map[int]string,5)
    tetcc[1] = "smallsha"
    tetcc[5] = "smallsha1"
    tetcc[3] = "smallsha2"
    sli := []int{}
    for i := range tetcc {
        sli = append(sli,i)
    }
    sort.Ints(sli)
    for i := 0; i < len(tetcc); i++ {
        fmt.Println("内容",tetcc[sli[i]])
    }

    fmt.Printf("%#v\n", sli)
    return

if判断

    if test2 :=19; test2> 20 {
        fmt.Println("test11212121212")
    }else if test2 < 20 {
        fmt.Println("test1111")
    }

switch使用

    test3 := 80
    switch test3 {
    case 80:
        fmt.Println("1")
        fallthrough  //可以使用fallthrough强制执行后面的case代码。
    case 90:
        fmt.Println("2")
    case 100:
        fmt.Println("3")
    default:
        fmt.Println("default")

    }

多个参数调用

   func test(s string, n ...int) string {
    var x int
    for _, i := range n {
        x += i
    }

    return fmt.Sprintf(s, x)
}
     s := []int{1, 2, 3}
    res := test("sum: %d", s...)    // slice... 展开slice
    println(res)

闭包使用

func a() func() int  {
    i := 0
    b := func() int{
        i++
        fmt.Println(i)
        return i
    }
    return b
}

    ccccc := a()
    ccccc()
    ccccc()
    return

关键字 defer 用于注册延迟调用。

这些调用直到 return 前才被执。因此,可以用来做资源清理。

多个defer语句,按先进后出的方式执行

惯例是:导致关键流程出现不可修复性错误的使用 panic,其他使用 error。

func main() {
    test()
}

func test() {
    defer func() {
        if err := recover(); err != nil {
            println(err.(string)) // 将 interface{} 转型为具体类型。
        }
    }()

    panic("panic error!")
}

表达式

package main

import "fmt"

type User struct {
    id   int
    name string
}

func (self *User) Test() {
    fmt.Printf("%p, %v\n", self, self)
}

func main() {
    u := User{1, "Tom"}
    u.Test()

    mValue := u.Test
    mValue() // 隐式传递 receiver

    mExpression := (*User).Test
    mExpression(&u) // 显式传递 receiver
}

定义error
http://www.topgoer.com/%E6%96%B9%E6%B3%95/%E8%87%AA%E5%AE%9A%E4%B9%89error.html

//返回异常
package main

import (
   "errors"
   "fmt"
)

func getCircleArea(radius float32) (area float32, err error) {
   if radius < 0 {
      // 构建个异常对象
      err = errors.New("半径不能为负")
      return
   }
   area = 3.14 * radius * radius
   return
}

func main() {
   area, err := getCircleArea(-5)
   if err != nil {
      fmt.Println(err)
   } else {
      fmt.Println(area)
   }
}

//系统抛异常
package main

import "fmt"

func test01() {
   a := [5]int{0, 1, 2, 3, 4}
   a[1] = 123
   fmt.Println(a)
   //a[10] = 11
   index := 10
   a[index] = 10
   fmt.Println(a)
}

func getCircleArea(radius float32) (area float32) {
   if radius < 0 {
      // 自己抛
      panic("半径不能为负")
   }
   return 3.14 * radius * radius
}

func test02() {
   getCircleArea(-5)
}

//
func test03() {
   // 延时执行匿名函数
   // 延时到何时?(1)程序正常结束   (2)发生异常时
   defer func() {
      // recover() 复活 恢复
      // 会返回程序为什么挂了
      if err := recover(); err != nil {
         fmt.Println(err)
      }
   }()
   getCircleArea(-5)
   fmt.Println("这里有没有执行")
}

func test04()  {
   test03()
   fmt.Println("test04")
}

func main() {
   test04()
}
//自定义error
package main

import (
    "fmt"
    "os"
    "time"
)

type PathError struct {
    path       string
    op         string
    createTime string
    message    string
}

func (p *PathError) Error() string {
    return fmt.Sprintf("path=%s \nop=%s \ncreateTime=%s \nmessage=%s", p.path,
        p.op, p.createTime, p.message)
}

func Open(filename string) error {

    file, err := os.Open(filename)
    if err != nil {
        return &PathError{
            path:       filename,
            op:         "read",
            message:    err.Error(),
            createTime: fmt.Sprintf("%v", time.Now()),
        }
    }

    defer file.Close()
    return nil
}

func main() {
    err := Open("/Users/5lmh/Desktop/go/src/test.txt")
    switch v := err.(type) {
    case *PathError:
        fmt.Println("get path error,", v)
    default:

    }

}

interface 应用

// 空接口作为函数参数
func show(a interface{}) {
    fmt.Printf("type:%T value:%v\n", a, a)
}

// 空接口作为map值
    var studentInfo = make(map[string]interface{})
    studentInfo["name"] = "李白"
    studentInfo["age"] = 18
    studentInfo["married"] = false
    fmt.Println(studentInfo)

go调度 sync.WaitGroup

var wg sync.WaitGroup

func hello(i int) {
    defer wg.Done() // goroutine结束就登记-1
    fmt.Println("Hello Goroutine!", i)
}
func main() {

    for i := 0; i < 10; i++ {
        wg.Add(1) // 启动一个goroutine就登记+1
        go hello(i)
    }
    wg.Wait() // 等待所有登记的goroutine都结束
}

go runtime.Gosched()

//让出CPU时间片,重新等待安排任务(大概意思就是本来计划的好好的周末出去烧烤,但是你妈让你去相亲,两种情况第一就是你相亲速度非常快,见面就黄不耽误你继续烧烤,第二种情况就是你相亲速度特别慢,见面就是你侬我侬的,耽误了烧烤,但是还馋就是耽误了烧烤你还得去烧烤)
package main

import (
    "fmt"
    "runtime"
)

func main() {
    go func(s string) {
        for i := 0; i < 2; i++ {
            fmt.Println(s)
        }
    }("world")
    // 主协程
    for i := 0; i < 2; i++ {
        // 切一下,再次分配任务
        runtime.Gosched()
        fmt.Println("hello")
    }
}

runtime.Goexit()

//退出当前协程(一边烧烤一边相亲,突然发现相亲对象太丑影响烧烤,果断让她滚蛋,然后也就没有然后了)
package main

import (
    "fmt"
    "runtime"
)

func main() {
    go func() {
        defer fmt.Println("A.defer")
        func() {
            defer fmt.Println("B.defer")
            // 结束协程
            runtime.Goexit()
            defer fmt.Println("C.defer")
            fmt.Println("B")
        }()
        fmt.Println("A")
    }()
    for {
    }
}

runtime.GOMAXPROCS

//Go1.5版本之后,默认使用全部的CPU逻辑核心数
///两个任务只有一个逻辑核心,此时是做完一个任务再做另一个任务。 将逻辑核心数设为2,此时两个任务并行执行,代码如下。
func a() {
    for i := 1; i < 10; i++ {
        fmt.Println("A:", i)
    }
}

func b() {
    for i := 1; i < 10; i++ {
        fmt.Println("B:", i)
    }
}

func main() {
    runtime.GOMAXPROCS(2)
    go a()
    go b()
    time.Sleep(time.Second)
}

通道

1.对一个关闭的通道再发送值就会导致panic。

2.对一个关闭的通道进行接收会一直获取值直到通道为空。

3.对一个关闭的并且没有值的通道执行接收操作会得到对应类型的零值。

4.关闭一个已经关闭的通道会导致panic。

5.chan<- int是一个只能发送的通道,可以发送但是不能接收;

6 <-chan int是一个只能接收的通道,可以接收但是不能发送。

func counter(out chan<- int) {
    for i := 0; i < 100; i++ {
        out <- i
    }
    close(out)
}

func squarer(out chan<- int, in <-chan int) {
    for i := range in {
        out <- i * i
    }
    close(out)
}
func printer(in <-chan int) {
    for i := range in {
        fmt.Println(i)
    }
}

func main() {
    ch1 := make(chan int)
    ch2 := make(chan int)
    go counter(ch1)
    go squarer(ch2, ch1)
    printer(ch2)
}

通道使用案例

type Job struct {
    Id      int
    RandNum int
}
type Result struct {
    job *Job
    sum int
}

func createPool(num int, jobChan chan *Job,resultChan chan *Result) {
    for i := 0; i < num; i++ {
        go func(jobChan chan *Job,resultChan chan *Result) {
            for i2 := range jobChan {
                r_num := i2.RandNum
                
                var sum int
                for r_num !=0 {
                    tmp := r_num % 10
                    sum += tmp
                    r_num /= 10
                }
                r := &Result{
                    job: i2,
                    sum: sum,
                }
                resultChan <- r
            }
        }(jobChan,resultChan)
    }
}

func main() {
    flag.Parse()

    jobChan := make(chan *Job, 128)
    resultChan := make(chan *Result, 128)
    createPool(64, jobChan, resultChan)
    // 4.开个打印的协程
    go func(resultChan chan *Result) {
        // 遍历结果管道打印
        for result := range resultChan {
            fmt.Printf("job id:%v randnum:%v result:%d\n", result.job.Id,
                result.job.RandNum, result.sum)
        }
    }(resultChan)
    var id int
    // 循环创建job,输入到管道
    for {
        id++
        // 生成随机数
        r_num := rand.Int()
        job := &Job{
            Id:      id,
            RandNum: r_num,
        }
        jobChan <- job
    }
    return
    }

select 监听通道

    select {
    case <-chan1:
       // 如果chan1成功读到数据,则进行该case处理语句
    case chan2 <- 1:
       // 如果成功向chan2写入数据,则进行该case处理语句
    default:
       // 如果上面都没有成功,则进入default处理流程
    }

flag使用 和 os.args

   var name string
    var age int
    var married bool
    var delay time.Duration
    flag.StringVar(&name, "name", "张三", "姓名")
    flag.IntVar(&age, "age", 18, "年龄")
    flag.BoolVar(&married, "married", false, "婚否")
    flag.DurationVar(&delay, "d", 0, "延迟的时间间隔")
    或者使用
    name := flag.String("name", "张三", "姓名")
    age := flag.Int("age", 18, "年龄")
    married := flag.Bool("married", false, "婚否")
    delay := flag.Duration("d", 0, "时间间隔")
    
    
    //解析命令行参数
    flag.Parse()
    fmt.Println(name, age, married, delay)
    //返回命令行参数后的其他参数
    fmt.Println(flag.Args())
    //返回命令行参数后的其他参数个数
    fmt.Println(flag.NArg())
    //返回使用的命令行参数个数
    fmt.Println(flag.NFlag())
    
    
    //os.args
        if len(os.Args) > 0 {
        for index, arg := range os.Args {
            fmt.Printf("args[%d]=%v\n", index, arg)
        }
    }

Log文件

    logFile, err := os.OpenFile("./smallsha.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
    if err != nil {
        fmt.Println("open log file failed, err:", err)
        return
    }
    log.SetOutput(logFile)  //设置日志文件写入
    log.SetFlags(log.Llongfile | log.Lmicroseconds | log.Ldate)
    log.SetPrefix("[smallsha]")
    log.Printf("%s","smallsha")
    log.Println("test")
    //log.Panic("test1")
    //log.Fatalln("test2")

    logger := log.New(os.Stdout, "<New>", log.Lshortfile|log.Ldate|log.Ltime)
    logger.Println("这是自定义的logger记录的日志。")

循环操作

arr := [5]int{1,2,4,5,6,8}
for i,num :=range arr {
    fmt.Println(i,num)
}
//while for 循环配合通道
    var (
        ch11 = make(chan int)
        ch12 = make(chan int)
    )

    go func() {
        for i := 0; i < 10; i++ {
            ch11 <- i
        }
        close(ch11)
    }()

    go func() {
        for {
            i, ok := <-ch11
            if !ok {
                break
            }
            ch12 <- i * i
        }
        close(ch12)
    }()

    for i := range ch12 {
         fmt.Println(i)
    }

指针

const MAX int =3
func main(){
    a :=[]int{1,3,5}
    var ptr [MAX]*int;
      for  i = 0; i < MAX; i++ {
      ptr[i] = &a[i] /* 整数地址赋值给指针数组 */
   }

   for  i = 0; i < MAX; i++ {
      fmt.Printf("a[%d] = %d\n", i,*ptr[i] )
   }
}

strconv 使用

    s3, _ := strconv.ParseBool("1")
    fmt.Printf("%# v\n", pretty.Formatter(s3))
    return
    //int 转 string
    s2 := 100
    i2 := strconv.Itoa(s2)
    fmt.Printf("%# v\n", pretty.Formatter(i2))
    return
    //string 转 int
    s1 := "100"
    i1, err := strconv.Atoi(s1)
    if err != nil {
        fmt.Println(err)
        return
    }
    fmt.Printf("%# v\n", pretty.Formatter(i1))
    return

template使用可以注册http

package logic

import (
    "fmt"
    "html/template"
    "net/http"
)

func init() {
    http.HandleFunc("/",sayHello)
    err := http.ListenAndServe(":9090", nil)
    if err != nil {
        fmt.Println(err)
        return
    }
}
type UserInfo struct {
    Name   string
    Gender string
    Age    int
}

func sayHello(w http.ResponseWriter,r *http.Request)  {
    // 解析指定文件生成模板对象
    tmpl, err := template.ParseFiles("./hello.html")
    if err != nil {
        fmt.Println("create template failed, err:", err)
        return
    }
    // 利用给定数据渲染模板,并将结果写入w
    user := UserInfo{
        Name:   "枯藤",
        Gender: "男",
        Age:    18,
    }
    // 利用给定数据渲染模板,并将结果写入w
    tmpl.Execute(w, user)
}

定义结构体

package main

import "fmt"

type Books struct {
   title string
   author string
   subject string
   book_id int
}

func main() {
   var Book1 Books        /* 声明 Book1 为 Books 类型 */
   var Book2 Books        /* 声明 Book2 为 Books 类型 */

   /* book 1 描述 */
   Book1.title = "Go 语言"
   Book1.author = "www.runoob.com"
   Book1.subject = "Go 语言教程"
   Book1.book_id = 6495407

   /* book 2 描述 */
   Book2.title = "Python 教程"
   Book2.author = "www.runoob.com"
   Book2.subject = "Python 语言教程"
   Book2.book_id = 6495700

   /* 打印 Book1 信息 */
   printBook(&Book1)

   /* 打印 Book2 信息 */
   printBook(&Book2)
}
func printBook( book *Books ) {
   fmt.Printf( "Book title : %s\n", book.title)
   fmt.Printf( "Book author : %s\n", book.author)
   fmt.Printf( "Book subject : %s\n", book.subject)
   fmt.Printf( "Book book_id : %d\n", book.book_id)
}

//结构体new 和赋值
 type Person struct {
    Username string `json:"username"`
    Password string `json:"password"`
}

//声明构造方法
func newPerson(username string, password string) *Person {
    return &Person{
        Username: username,
        Password: password,
    }
}
//定义修改结构体的方法
func (p *Person) setUsername(username string) {
    p.Username = username
}



map操作

package main

import "fmt"

func main() {
    var countryCapitalMap map[string]string /*创建集合 */
    countryCapitalMap = make(map[string]string)

    /* map插入key - value对,各个国家对应的首都 */
    countryCapitalMap [ "France" ] = "巴黎"
    countryCapitalMap [ "Italy" ] = "罗马"
    countryCapitalMap [ "Japan" ] = "东京"
    countryCapitalMap [ "India " ] = "新德里"

    /*使用键输出地图值 */
    for country := range countryCapitalMap {
        fmt.Println(country, "首都是", countryCapitalMap [country])
    }

    /*查看元素在集合中是否存在 */
    capital, ok := countryCapitalMap [ "American" ]
    /*删除元素*/ delete(countryCapitalMap, "France")
    /*如果确定是真实的,则存在,否则不存在 */
    /*fmt.Println(capital) */
    /*fmt.Println(ok) */
    if (ok) {
        fmt.Println("American 的首都是", capital)
    } else {
        fmt.Println("American 的首都不存在")
    }
}

声明变量
    package main
    import "fmt"
    func main() {
        var a string = "Runoob"
        fmt.Println(a)
    
        var b, c int = 1, 2
        fmt.Println(b, c)
    }
    
声明方法
    package main
    import "fmt"
    func swap(x, y string) (string, string) {
       return y, x
    }
    func main() {
       a, b := swap("Google", "Runoob")
       fmt.Println(a, b)
    }
定义数组
    var balance = [5]float32{1000.0, 2.0, 3.4, 7.0, 50.0}
    var balance = [...]float32{1000.0, 2.0, 3.4, 7.0, 50.0}
    package main
    import "fmt"
    func main() {
       var n [10]int /* n 是一个长度为 10 的数组 */
       var i,j int
       /* 为数组 n 初始化元素 */        
       for i = 0; i < 10; i++ {
          n[i] = i + 100 /* 设置元素为 i + 100 */
       }
       /* 输出每个数组元素的值 */
       for j = 0; j < 10; j++ {
          fmt.Printf("Element[%d] = %d\n", j, n[j] )
       }
    }

Go 语言结构体

package main

import "fmt"

type Books struct {
   title string
   author string
   subject string
   book_id int
}

func main() {
   var Book1 Books        /* 声明 Book1 为 Books 类型 */
   var Book2 Books        /* 声明 Book2 为 Books 类型 */

   /* book 1 描述 */
   Book1.title = "Go 语言"
   Book1.author = "www.runoob.com"
   Book1.subject = "Go 语言教程"
   Book1.book_id = 6495407

   /* book 2 描述 */
   Book2.title = "Python 教程"
   Book2.author = "www.runoob.com"
   Book2.subject = "Python 语言教程"
   Book2.book_id = 6495700

   /* 打印 Book1 信息 */
   fmt.Printf( "Book 1 title : %s\n", Book1.title)
   fmt.Printf( "Book 1 author : %s\n", Book1.author)
   fmt.Printf( "Book 1 subject : %s\n", Book1.subject)
   fmt.Printf( "Book 1 book_id : %d\n", Book1.book_id)

   /* 打印 Book2 信息 */
   fmt.Printf( "Book 2 title : %s\n", Book2.title)
   fmt.Printf( "Book 2 author : %s\n", Book2.author)
   fmt.Printf( "Book 2 subject : %s\n", Book2.subject)
   fmt.Printf( "Book 2 book_id : %d\n", Book2.book_id)
}

结构体作为函数参数
    func printBook( book Books ) {
       fmt.Printf( "Book title : %s\n", book.title)
       fmt.Printf( "Book author : %s\n", book.author)
       fmt.Printf( "Book subject : %s\n", book.subject)
       fmt.Printf( "Book book_id : %d\n", book.book_id)
    }

声明函数和方法区别

#函数
func main() {
    sum := add(1, 2)
    fmt.Println(sum)
}
 
func add(a, b int) int {
    return a + b
}
#方法
type person struct {
    name string
}
 
func (p person) String() string{
    return "the person name is "+p.name
}

func main() {
    p:=person{name:"张三"}
    fmt.Println(p.String())
}

#可变参数
func main() {
    print("1","2","3")
}

func print (a ...interface{}){
    for _,v:=range a{
        fmt.Print(v)
    }
    fmt.Println()
}

修改字符串 需要先转换成 byte 或者 rune

func changeString() {
    s1 := "hello"
    // 强制类型转换
    byteS1 := []byte(s1)
    byteS1[0] = 'H'
    fmt.Println(string(byteS1))

    s2 := "博客"
    runeS2 := []rune(s2)
    runeS2[0] = '狗'
    fmt.Println(string(runeS2))
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,340评论 5 467
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,762评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,329评论 0 329
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,678评论 1 270
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,583评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 47,995评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,493评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,145评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,293评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,250评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,267评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,973评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,556评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,648评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,873评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,257评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,809评论 2 339

推荐阅读更多精彩内容