go 笔记

package main

import (  
    "fmt"
    "container/list" 
    "rect"// 导入自定义包
    "time"
    "sync"
)

var a string = "阿里云大学"
var b string = "edu.aliyun.com"
//var c bool
//全局变量是允许声明但不使用。
var aa, bb, cc int

//多变量可以在同一行进行赋值,如
var aaa, bbb, ccc = 55, 77, "abc"

const(
    // 定义每分钟的秒数
    SecondsPerMinute = 60
    // 定义每小时的秒数
    SecondsPerHour = SecondsPerMinute * 60
    // 定义每天的秒数
    SecondsPerDay = SecondsPerHour * 24
)

// 结构体
type Employee struct {

  firstname,lastname string
  age, salary int
}


func main() {

    //常量
    const LENGTH int = 10
    const WIDTH int = 5   
    const cl1, cl2, cl3 = 1, false, "str" //多重赋值
    var area int
    area = LENGTH * WIDTH
  

    // 变量
    var c, d int = 1, 2
    var e, f = 123, "hello"

    //如果你想要交换两个变量的值,则可以简单地使用 a, b = b, a。
    a, b = b, a

    g, h := 456, "lalala" // g 和 h 的类型(int 和 string)将由编译器自动推断。这是使用变量的首选形式,但是它只能被用在函数体内 

    // 计算
   var ajs int = 21
   var bjs int = 10
   var cjs int
   cjs = ajs + bjs
   fmt.Printf("第一行 - cjs 的值为 %d\n", cjs )
   cjs = ajs - bjs
   fmt.Printf("第二行 - cjs 的值为 %d\n", cjs )

    //g, h := 456, "lalala" 这种不带声明格式的只能在函数体中出现
    fmt.Println(a, b,c,d,e,f,g, h,&d)
    println(cl1, cl2, cl3)
    fmt.Printf ("常量为 cl1 = %d, cl3 = %s and area = %d\n", cl1, cl3, area)


   //调用自定义函数
   var ret int // 先定义一个变量,不然报错
   ret = max(ajs, bjs)
   fmt.Printf( "最大值是 : %d\n", ret)

   // 数组
  // var n [10]int /* n 是一个长度为 10 的数组 */
   var j int

   var balance = [5]float32{1000.1, 2.0, 3.4, 7.0, 50.0}
   fmt.Println(balance[0])
   for j = 0; j < 5; j++ {
       fmt.Printf("shuzu:%f\n", balance[j])
   }
//for range 语法上类似于其它语言中的 foreach 语句
   // 打印索引和元素
   for i, v := range a{
       fmt.Printf("range打印数组%d %d\n", i, v)
   }

   // 仅打印元素
   for _, v := range a{
       fmt.Printf("元素:%d\n",v)
   }

   // for 循环
   // 创建一个整型切片
   // 其长度和容量都是 4 个元素
    slice := []int{10, 20, 30, 40}
    // 从第三个元素开始迭代每个元素
    for index := 2; index < len(slice); index++ {
        fmt.Printf("Index: %d Value: %d\n", index, slice[index])
    }


   /* 创建切片 */
   numbers := []int{0,1,2,3,4,5,6}  
   /* 打印原始切片 */
   fmt.Println("numbers ==", numbers)
    /* 打印子切片从索引1(包含) 到索引4(不包含): 元素第一个索引为0*/
   fmt.Println("numbers[1:4] ==", numbers[1:4]) // numbers[1:4] == [1 2 3]
    /* 默认下限为 0 :从0开始一直到索引为3 结束  */
   fmt.Println("numbers[:3] ==", numbers[:3])  // numbers[:3] == [0 1 2]
    /* 默认上限为 len(s)  4 指的是索引 :从索引为4开始一直到最后 */
   fmt.Println("numbers[4:] ==", numbers[4:]) // numbers[4:] == [4 5 6 7 8]



   //Go语言从切片中删除元素
   //从开头位置删除
   numbers = numbers[1:] // 删除开头1个元素
   fmt.Println("del1 ==", numbers) 
   //从中间位置删除
   numbers = append(numbers[:3], numbers[4:]...) // 删除中间第4个元素
   fmt.Println("del2 ==", numbers) // del1 == [1 2 3 4 5 6]   del2 == [1 2 3 5 6]

   //从尾部删除
   numbers = numbers[:len(numbers)-1] // 删除尾部1个元素
   fmt.Println("del3 ==", numbers) 
   //a = a[:len(a)-N] // 删除尾部N个元素
   // 指定删除位置   定一个变量
    index := 2
    // 查看删除位置之前的元素和之后的元素
    fmt.Println(numbers[:index], numbers[index+1:])
     // 将删除点前后的元素连接起来
    numbers = append(numbers[:index], numbers[index+1:]...)
    fmt.Println("del4 ==", numbers) 


   // 区间
//fmt.Println(numbers[1:4])
// 中间到尾部的所有元素
//fmt.Println(numbers[3:])
// 开头到中间指定位置的所有元素
//fmt.Println(numbers[:3])

   
   numbers1 := make([]int,0,5)
   printSlice(numbers1)

    /* 打印子切片从索引 2(包含) 到索引 5(不包含) */
   number3 := numbers[2:5]
   printSlice(number3)

    /* 允许追加空切片 */
   numbers = append(numbers, 7)
   fmt.Println("numbers ==", numbers)
   /* 同时添加多个元素 */
   numbers = append(numbers, 8,9,10)
   fmt.Println("numbers ==", numbers) 

   var numbers4 []int
   /* 同时添加多个元素 */
   numbers4 = append(numbers4, 2,3,4)
   numbers4 = append(numbers4, 5)
   /* 创建切片 numbers1 是之前切片的两倍容量*/
   numbers5 := make([]int, len(numbers4), (cap(numbers4))*2)
   //numbers5 = append(numbers5, 6)
   /* 拷贝 numbers 的内容到 numbers1 */
   copy(numbers5,numbers4)
   printSlice(numbers5)

    aK, _ := GetData() // 100
    _, bK := GetData() // 200
    fmt.Println(aK, bK)

   // 直接声明新的切片
   // 声明字符串切片
   var strList []string
   // 声明整型切片
   var numlist []int
   // 声明一个空切片
   var numlistempty = []int{}
   // 输出3个切片
   fmt.Printf("kongqiepian:%s = %d = %d\n",strList, numlist, numlistempty)


    // 指针
    var house = "zhizhenyinyong"
    ptr := &house

     // 打印ptr的类型
    //fmt.Printf("ptr type: %T\n", ptr)
    // 打印ptr的指针地址
    //fmt.Printf("address: %p\n", ptr)
    // 对指针进行取值操作
    value := *ptr
    fmt.Printf("address: %p\n", value)

    // 多维数组
    // 声明一个二维整型数组,两个维度的长度分别是 4 和 2
    var array[4][2]int
    // 使用数组字面量来声明并初始化一个二维整型数组
    array = [4][2]int{{10,11}, {20,21}, {30,31}, {40,41}}
    // 声明并初始化数组中索引为 1 和 3 的元素
    array = [4][2]int{1: {20, 21}, 3: {40, 41}}
    fmt.Println(array)

    // 创建一个整型切片,多维切片
    slice2 := [][]int{{10}, {100, 200}}
    // 为第一个切片追加值为 20 的元素
    slice2[0] = append(slice2[0], 20)
    fmt.Println(slice2)

    // map 映射,就是关联数组
     var mapLit map[string]int
     mapLit = map[string]int{"one": 1, "two": 2}
fmt.Println(mapLit)
     mapCreated := make(map[string]float32)
     //mapCreated := make(map[string]float)等价于mapCreated := map[string]float{} 
     mapCreated["key1"] = 4.5
     mapCreated["key2"] = 3.14159
     mapCreated["key3"] = 5
     /*fmt.Println(mapCreated["key2"])
     */
// 如果需要特定顺序的遍历结果,正确的做法是先排序,代码如下:
// 声明一个切片保存map数据
    //var sceneList []string
    // 将map数据遍历复制到切片中
    /*for k := range mapCreated {
        sceneList = append(sceneList, k)
    }*/
    // 对切片进行排序
    //sort.Strings(sceneList)
    // 输出
    //fmt.Println(sceneList)
    //使用 delete() 函数从 map 中删除键值对
    delete(mapCreated, "key2")
    for k, v := range mapCreated {
         fmt.Println(k, v)
     }

     // 初始化列表 方式1
     list := list.New()
     // 初始化列表 方式2
     //var list2 list2.List

     //双链表支持从队列前方或后方插入元素,分别对应的方法是 PushFront 和 PushBack。
     // 尾部添加
     list.PushBack("canon")
     // 头部添加
     list.PushFront(67)
    
      // 尾部添加后保存元素句柄
    element := list.PushBack("fist")
     // 在fist之后添加high
    list.InsertAfter("high", element) 
    // 在fist之前添加noon
    list.InsertBefore("noon", element)
     // 使用
    list.Remove(element)
    for i := list.Front(); i != nil; i = i.Next() {
        fmt.Println(i.Value)
    }

      // 遍历, 决定处理第几行
      for y := 1; y<=9; y++ {
            // 遍历, 决定这一行有多少列
            for x := 1; x<=y; x++ {
                 fmt.Printf("%d*%d = %d ",x,y,x*y)
            }

            // 手动生成回车,打印一个空行,实际作用就是换行。
          fmt.Println()

      }

      var sw = "hello"
      switch sw {
      case "hello":
           fmt.Println(1)
      case "world":
           fmt.Println(2)
      default:
           fmt.Println(3)
      }

      var r int = 11
        switch {
        case r > 10 && r < 20:
            fmt.Println(r)
        }

    //冒泡排序
    arr := [...]int{21,32,12,33,34,34,87,24} //让编译器为你自动计算数组长度,[5]int 和 [25]int 是不同类型
    var n = len(arr)
    fmt.Println("--------没排序前--------\n",arr)
    for i := 0; i <= n-1; i++ {
   
        for j := i; j <= n-1; j++ {
           if arr[i] > arr[j] {
                t := arr[i]
                arr[i] = arr[j]
                arr[j] = t
            }
           // fmt.Println(arr)
        }
    }
    fmt.Println("--------最终结果--------\n",arr)


    // 将返回值作为打印参数
    fmt.Println(resolveTime(1000))
    // 只获取消息和分钟
    _, hour, minute := resolveTime(18000)
    fmt.Println(hour, minute)
    // 只获取天
    day, _, _ := resolveTime(90000)
    fmt.Println(day)

    var rectlen, rectwidth float64 = 6,7
    ff := rect.Area(rectlen, rectwidth)
    fmt.Printf("area of rect %.2f\n", ff)

    num := 11
    if num % 2 == 0 {
       fmt.Println("the number is even") 
    } else {
       fmt.Println("the number is odd")
    }

    for k :=1; k<=10; k++ {
      if k==5 || k==6 || k==7 {
        continue
      }
      fmt.Printf("%d",k)
    }

var i int

for{

  if i>10{
    fmt.Println("\ndayu10")
    break
  }
  i++

}
//精简for
for i<=10{
  fmt.Println("\n精简for")
  i++
}
    // 结构体
    emp1 := Employee{
      firstname: "sam",
      age: 25,
      salary: 500,
      lastname: "suibian",
    }

    emp2 := Employee{"firstlala", "lastlala", 29, 600}
    fmt.Println("\nemp1:", emp1)
     fmt.Println("emp2:", emp2)
     //创建匿名结构体
     emp3 := struct{
      first1,fist2 string
      age int
     }{
      first1: "niming1",
      fist2: "fist2",
      age: 31,
     }
     fmt.Println("\nemp3:", emp3)
     //访问结构体的字段
     fmt.Println("\nfirst1:", emp3.first1)
     //调用别的包里的结构体
     var spce rect.Spec
     spce.Maker = "apple"
     spce.Price = 666
     fmt.Printf("rectbao%s,%d", spce.Maker,spce.Price)
      go hello()
       time.Sleep(1 * time.Second)
    fmt.Println("\nmain function\n")
    //信道
   // data := <- a // 读取信道 a  
    //a <- data // 写入信道 a
     
    done := make(chan bool) //创建了一个 bool 类型的信道 done
    go hello2(done)   //,并把 done 作为参数传递给了 hello 协程
    <-done
    //我们通过信道 done 接收数据。这一行代码发生了阻塞,除非有协程向 done 写入数据,
    //否则程序不会跳到下一行代码。于是,这就不需要用以前的 time.Sleep 来阻止 Go 主协程退出了
    //现在我们的 Go 主协程发生了阻塞,等待信道 done 发送的数据。该信道作为参数传递给了协程hello
    
    fmt.Println("xindao")
    //缓冲信道
    ch := make(chan string, 2)
    ch <- "naveen"
    ch <- "paul"
    fmt.Println(<- ch)
    fmt.Println(<- ch)

    //WaitGroup
    no := 3
    var wg sync.WaitGroup
    for i:=0; i<no; i++ {
      wg.Add(1)
      go process(i,&wg)
    }
    wg.Wait()
     fmt.Println("All go routines finished executing")

//select 语句用于在多个发送/接收信道操作中进行选择
     output1 := make(chan string)
     output2 := make(chan string)
     go server1(output1)
     go server2(output2)
     time.Sleep(4 * time.Second)
     select {
        case s1 := <-output1:
             fmt.Println(s1)
        case s2 := <-output2:
             fmt.Println(s2)
         default:
            fmt.Println("no value received")
     }


}

func server1(ch chan string) {
  time.Sleep(6 * time.Second)
  ch <- "from server1"
}

func server2(ch chan string) {
  time.Sleep(3 * time.Second)
  ch <- "from server2"
}



func process(i int, wg *sync.WaitGroup) {  
    fmt.Println("started Goroutine ", i)
    time.Sleep(2 * time.Second)
    fmt.Printf("Goroutine %d ended\n", i)
    wg.Done()
}

func hello() {
   fmt.Println("\nHello world goroutine\n")
}

func hello2 (done chan bool) {
// ,hello 打印出 Hello world goroutine
    fmt.Println("Hello world gxindao")
    //接下来向 done 写入数据。当完成写入时,Go 主协程会通过信道 done 接收数据,
    //于是它解除阻塞状态,打印出文本 xindao。
    done <- true
}

// 将传入的“秒”解析为3种时间单位
func resolveTime(seconds int) (day int,hour int, minute int) {
    day = seconds / SecondsPerDay
    hour = seconds / SecondsPerHour
    minute = seconds / SecondsPerMinute
    return
}

/* 函数返回两个数的最大值 */
func max(num1, num2 int) int {
   /* 声明局部变量 */
   var result int

  if (num1 > num2) { // 左大括号 { 一般不能单独放一行
      result = num1   
  } else {
      result = num2   
  }
   return result 
}


/*Go 语言指针*/
func zhizhen() {
   var zza int= 20   /* 声明实际变量 */
   var ip *int        /* 声明指针变量 */

   ip = &zza  /* 指针变量的存储地址 */

   fmt.Printf("a 变量的地址是: %x\n", &zza  )

   /* 指针变量的存储地址 */
   fmt.Printf("ip 变量储存的指针地址: %x\n", ip )

   /* 使用指针访问值 */
   fmt.Printf("*ip 变量的值: %d\n", *ip )
}

func printSlice(x []int){
   fmt.Printf("len=%d cap=%d slice=%v\n",len(x),cap(x),x)
}

func GetData() (int, int) {
    return 100, 200
}