GO语言基础语法 | 青训营笔记

49 阅读2分钟
  • 基础语法--hello world!
package main

import "fmt"

func main() {
   fmt.Println("hello world")
}

package main表示该文件属于main包的一部分,mian包即程序的入口包,该文件即程序的入口文件。

导入标准库的fmt包:主要往屏幕输入输出字符串,格式化字符串(该操作类似C的导入头文件)

func main 即主函数,调用fmt的Println输出

运行该程序使用go run命令

生成二进制文件使用go build命令

鼠标放在Println上可以链接跳转包的官方文档,查看其他方法的使用方法,类似idea

  • 基础语法--变量

字符串是内置类型,类似string,可以直接用 + 拼接,也可以用 = 去比较两个字符串

变量的声明:var 【name】 = 【value】

比如: var a = "initial"

会根据value自动匹配变量的类型,如果想直接确定类型,可以在【name】后直接将类型名标注

比如: var b, c int = 1, 2

或者【变量名】 := 【value】

声明常量时,将var改为const

可以声明多个类型不同的变量(类型由初始化表达式推导):

var i, j, k int // int, int, int

var b, f, s = true, 2.3, "four"// bool, float64, string
package main

import (
   "fmt"
   "math"
)

func main() {
   var a = "initial"
   var b, c int = 1, 2
   var d = true
   var e float64
   f := float32(e)
   g := a + "foo"
   fmt.Println(a, b, c, d, e, f) // initial 1 2 true 0 0
   fmt.Println(g)                // initialfoo
   const s string = "constant"
   const h = 500000000
   const i = 3e20 / h
   fmt.Println(s, h, i, math.Sin(h), math.Sin(i)) // constant 500000000 6e+11 -0.28470407323754404 0.7591864109375384
}
  • 基础语法--switch

go语言中Switch后面的变量名和if一样不需要括号,和C语言不同的是,C语言case语句后没有break默认走完所有case,而go语言默认是不走的。

在go中Switch还有更加高级的用法,可以在Switch后不加任何的变量名,而在case后添加条件判断,可以代替if语句使条件的选择更加清晰,代码更加美观。

package main

import (
   "fmt"
   "time"
)

func main() {
   a := 2
   switch a {
   case 1:
      fmt.Println("one")
   case 2:
      fmt.Println("two")
   case 3:
      fmt.Println("three")
   case 4, 5:
      fmt.Println("four or five")
   default:
      fmt.Println("other")
   }
   t := time.Now()
   switch {
   case t.Hour() < 12:
      fmt.Println("It's before noon")
   default:
      fmt.Println("It's after noon")
   }
}
  • 基础语法--map

使用过程中用到的最多的数据结构,使用make创建

m :=make(map[string]int)
m["one"] =1
m["two"] =2

其中string是key的类型,int是value的类型,初始化一些map中的值

ages :=map[string]int{
"alice": 31,
"charlie": 34,
}

使用delete去删除

delete(m, "one")

在使用时可以在变量后面加一个ok来获取对应key索引的value是否存在如果存在变量为value,ok为true,否则,变量为对应类型的零值,ok为false

r, ok :=m["unknow"]
fmt.Println(r, ok) // 0 false

map是无序的,多次迭代会得到不同的结果。

  • 基础语法--range

一个迭代工具,可以快速遍历数组,切片,map等,类似java的foreach快速遍历

在迭代时可以同时输出对应的key和value

如果不需要索引可以用下划线free

package main

import "fmt"

func main() {
   nums := []int{2, 3, 4}
   sum := 0
   for i, num := range nums {
      sum += num
      if num == 2 {
         fmt.Println("index:", i, "num:", num) // index: 0 num: 2
      }
   }
   fmt.Println(sum) // 9
   m := map[string]string{"a": "A", "b": "B"}
   for k, v := range m {
      fmt.Println(k, v) // b 8; a A
   }
   for k := range m {
      fmt.Println("key", k) // key a; key b
   }
}
  • 基础语法--指针

go语言也有指针,其使用形式大致和Cpp相同,但功能相对简单,一般用于函数间传参时改变变量的值,传参时用&,解引用时用*

但要注意的是,go语言是不支持指针运算的,如果想进行指针运算,需要引入特殊包,直接对内存进行操作

  • 基础语法--错误处理

错误,一种类似java中的异常却不完全相同的类型

go语言通常将错误作为返回值

不同于java的异常,go的错误会清楚的显示错误发生的行与列,并能通过简单的if else语句初期错误

例如,在参数列表中加入err类型,如果返回正常,error即返回nil,否则,new一个错误并返回

在主函数中同样也要有变量来接收err的值,并主函数中对错误进行相应的处理以保证程序的稳定性

package main

import (
   "errors"
   "fmt"
)

type user struct {
   name string
   password string
}

func findUser(users []user, name string) (v *user, err error) {
   for _, u := range users {
      if u.name == name {
         return &u, nil
      }
   }
   return nil, errors.New("not found")
}

func main() {
   u, err := findUser([]user{{"wang", "1024"}}, "wang")
   if err != nil {
      fmt.Println(err)
      return
   }
   fmt.Println(u.name) // wang
   if u, err := findUser([]user{{"wang", "1024"}}, "li"); err != nil {
      fmt.Println(err) // not found
      return
   } else {
      fmt.Println(u.name)
   }
}
  • 基础语法--字符串操作

在go语言的strings包里包含了许多有关于字符串的操作,需要使用时导包即可

Contains:查找是否包含某一字符串,返回布尔值

Count:统计某个字符串在原字符串中出现的次数

Index:定位

Join:将一个字符串拼接到另一个字符串后面

Repeat:重复多次字符串

len:内置函数,统计字符串中的字符个数,注意中文可能一个字对应多个字符

package main

import (
   "fmt"
   "strings"
)

func main() {
   a := "hello"
   fmt.Println(strings.Contains(a, "ll"))                // true
   fmt.Println(strings.Count(a, "l"))                    // 2
   fmt.Println(strings.HasPrefix(a, "he"))               // true
   fmt.Println(strings.HasSuffix(a, "llo"))              // true
   fmt.Println(strings.Index(a, "ll"))                   // 2
   fmt.Println(strings.Join([]string{"he", "llo"}, "-")) // he-llo
   fmt.Println(strings.Repeat(a, 2))                     // hellohello
   fmt.Println(strings.Replace(a, "e", "E", -1))         // hEllo
   fmt.Println(strings.Split("a-b-c", "-"))              // [a b c]
   fmt.Println(strings.ToLower(a))                       // hello
   fmt.Println(strings.ToUpper(a))                       // HELLO
   fmt.Println(len(a))                                   // 5
   b := "你好"
   fmt.Println(len(b)) // 6
}
  • 基础语法--字符串格式化

在标准库fmt下就有字符串格式化函数,常见的有Println,打印并换行。还有熟悉的C语言中的Printf,其语法和C语言类似,比较方便的一点是,go语言只需要%v即可输出任意类型数据。可以用%+v , %#v来得到更加详细的结构。

package main

import "fmt"

type point struct {
   x, y int
}

func main() {
   s := "hello"
   n := 123
   p := point{1, 2}
   fmt.Println(s, n)        // hello 123
   fmt.Println(p)           // {1 2}
   fmt.Printf("s=%v\n", s)  // s=hello
   fmt.Printf("n=%v\n", n)  // n=123
   fmt.Printf("p=%v\n", p)  // p={1 2}
   fmt.Printf("p=%+v\n", p) // p={x:1 y:2}
   fmt.Printf("p=%#v\n", p) // p=main.point{x:1, y:2}
   f := 3.141592653
   fmt.Println(f)          // 3.141592653
   fmt.Printf("%.2f\n", f) // 3.14
}
  • 基础语法--json处理

定义结构体时,所有变量用大写

给结构体赋值后,用Marshal进行序列化,或者用MarshalIndent函数产生整齐缩进的序列化

输出时,用string做强制类型转换,否则输出为一串16进制编码

也可以用Unmarshal函数进行反序列化,将json数据解码为字节切片

如果在输出时想让输出与结构体成员名不同,需要在结构体声明时在对应结构体成员后加tag标签进行标注

package main

import (
   "encoding/json"
   "fmt"
)

type userInfo struct {
   Name  string
   Age   int `json:":age"`
   Hobby []string
}

func main() {
   a := userInfo{
      Name:  "wang",
      Age:   18,
      Hobby: []string{"Golang", "TypeScript"},
   }
   buf, err := json.Marshal(a)
   if err != nil {
      panic(err)
   }
   fmt.Println(buf)         // [123 34 78 97 ...]
   fmt.Println(string(buf)) // {"Name":"wang",":age":18,"Hobby":["Golang","TypeScript"]}

   buf, err = json.MarshalIndent(a, "", "\t")
   if err != nil {
      panic(err)
   }
   fmt.Println(string(buf))
   // {
   //        "Name": "wang",
   //        ":age": 18,
   //        "Hobby": [
   //                "Golang",
   //                "TypeScript"
   //        ]
   //}
   var b userInfo
   err = json.Unmarshal(buf, &b)
   if err != nil {
      panic(err)
   }
   fmt.Printf("%#v\n", b) // main.userInfo{Name:"wang", Age:18, Hobby:[]string{"Golang", "TypeScript"}}
}
  • 基础语法--时间处理

时间的处理要引入time包

通过time.Now()获取当前时间

通过time.Date去构造一个带时区的时间

构造完成后可以用【变量名】.Year , 【变量名】.Month 等等去获取时间中的年月日时分秒

Sub函数将两个时间相减获得到时间差 用.Minutes(),.Seconds()可以将时间差转换为分,秒

时间格式化,必须将"2006-01-02 15:04:05"放入,否则不成功

这里有两种格式化方法:

t.Format("2006-01-02 15:04:05")
t3, err :=time.Parse("2006-01-02 15:04:05", "2022-03-27 01:25:36")

在系统交互时,可以用.Unix()去获取一个时间戳

package main

import (
   "fmt"
   "time"
)

func main() {
   now := time.Now()
   fmt.Println(now) // 2022-03-27 18:04:59.433297 +0800 CST m=+0.000087933
   t := time.Date(2022, 3, 27, 1, 25, 36, 0, time.UTC)
   t2 := time.Date(2022, 3, 27, 2, 30, 36, 0, time.UTC)
   fmt.Println(t) // 2022-03-27 01:25:36 +0000 UTC
   fmt.Println(t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute()) // 2022 March 27 1 25
   fmt.Println(t.Format("2006-01-02 15:04:05")) // 2022-03-27 01:25:36
   diff := t2.Sub(t)
   fmt.Println(diff) // 1h5m0s
   fmt.Println(diff.Minutes(), diff.Seconds()) // 65 3900
   t3, err := time.Parse("2006-01-02 15:04:05", "2022-03-27 01:25:36")
   if err != nil {
      panic(err)
   }
   fmt.Println(t3 == t) // true
   fmt.Println(now.Unix()) // 1648738080
}
  • 基础语法--数字解析

对于字符串和数字的转化解析,需要引入strconv包

使用ParseFloat将字符串转化为浮点数,64代表精度

f, _ :=strconv.ParseFloat("1.234", 64)
fmt.Println(f) // 1.234

使用ParseInt将字符串转化为整数,第二个参数代表进制,如果为0代表自动推测,64代表精度

n, _ :=strconv.ParseInt("111", 10, 64)
fmt.Println(n) // 111
n, _=strconv.ParseInt("0x1000", 0, 64)
fmt.Println(n) // 4096

使用Atoi进行快速转化,也可以Itoa转化

package main

import (
   "fmt"
   "strconv"
)

func main() {
   n2, _ := strconv.Atoi("123") // string转int
   fmt.Println(n2)              // 123
   string_number := 97
   result := strconv.Itoa(string_number) // int转string
   fmt.Println(result)
   fmt.Printf("%T\n", result)
}

如果失败会返回错误

n2, err :=strconv.Atoi("AAA")
fmt.Println(n2, err) // 0 strconv.Atoi: parsing "AAA": invalid syntax
  • 基础语法--进程信息

要导入对应的os,os/exec包

os.Args:获取当前进程的命令行参数,命令行参数包括了程序路径本身,以及通常意义上的参数。程序中os.Args的类型是[]string

os.Getenv:检索由键命名的环境变量的值。它返回值,如果变量不存在,该值将为空。

os.Setenv: 函数可以设置名为 key 的环境变量,如果出错会返回该错误。

package main

import (
   "fmt"
   "os"
   "os/exec"
)

func main() {
   fmt.Println(os.Args)               // [C:\Users\hp-pc\AppData\Local\Temp\GoLand___go_build_test_go.exe]
   fmt.Println(os.Getenv("PATH"))     // /usr/local/go/bin...
   fmt.Println(os.Setenv("AA", "BB")) // <nil>
   buf, err := exec.Command("grep", "127.0.0.1", "/etc/hosts").CombinedOutput()
   if err != nil {
      panic(err)
   }
   fmt.Println(string(buf)) // 127.0.0.1 localhost
}