2.Go 语言原理与实践 | 青训营

62 阅读5分钟

1.go语言基础语法

1.1 point 指针

指针的主要用途是对传入的参数进行修改,下面第14到16行的函数试图将变量a加2,但这种写法实际上是无效的,这种传递参数是值的拷贝。有效做法是将传入的变量定义为指针类型,并在调用函数时使用相匹配的变量类型。

package main

import (
   "fmt"
)

func main() {
   a := 5
   add(a)
   fmt.Println(a)
   addptr(&a)
   fmt.Println(a)
}
func add(a int) {
   a = a + 1 //
}
func addptr(a *int) {
   *a = *a + 1
}

1.2 struct 结构体

结构体是带类型的字段的集合,可以用结构体的名称初始化结构体变量,在初始化的时候需要传入每个字段的值。结构体也能作为函数的参数,有指针和非指针两种用法,用指针的话,可以实现对结构体的修改,某些情况下也能避免大结构体的开销。

package main

import (
   "fmt"
)

type user struct {
   name     string
   password string
}

func main() {
   a := user{name: "wang", password: "123456"}
   b := user{name: "fan"}
   c := user{"fan", "1024"}
   var d user
   d.name = "Liu"
   d.password = "123456"
   fmt.Println(a, b, c, d)
   fmt.Println(checkPassword(a, "hahahahaha"))
   checkPassword2(&a, "hhhh")
   fmt.Println(a)
}
func checkPassword(a user, password string) bool {
   return a.password == password
}
func checkPassword2(a *user, password string) {
   a.password = password
}

1.3 struct-method 结构体函数

在goland里面可以用结构体去定义一些方法,这会非常类似其它语言的类成员函数。

package main

import (
   "fmt"
)

type user struct {
   name     string
   password string
}

func main() {
   a := user{name: "wang", password: "123456"}
   b := user{name: "fan"}
   c := user{"fan", "1024"}
   var d user
   d.name = "Liu"
   d.password = "123456"
   fmt.Println(a, b, c, d)
   fmt.Println(a.checkPassword("hahahahaha"))
   a.resetPassword("hahahahaha")
   fmt.Println(a.checkPassword("hahahahaha"))
}
func (a user) checkPassword(password string) bool {
   return a.password == password
}
func (a *user) resetPassword(password string) {
   a.password = password
}

1.4 错误处理

在goland里面符合语言错误处理的习惯是使用单独的返回值来传递错误信息,不同于java里面使用的异常机制,go语言的处理方式能够很清晰的知道那个函数返回了错误,而且能够用简单的if,else去处理错误。我们可以在函数的返回值里加上一个error,代表函数可能出现错误。

package main

import (
   "errors"
   "fmt"
)

type user struct {
   name     string
   password string
}

func main() {
   u, err := findUser([]user{{"wang", "1234"}}, "wang")
   if err != nil {
      fmt.Println(err)
      return
   }
   fmt.Println(u.name)
   if u, err := findUser([]user{{"wang", "1024"}}, "li"); err != nil {
      fmt.Println(err) // not found
      return
   } else {
      fmt.Println(u.name)
   }
}
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")
}

1.5 字符串操作

在标准库strings包里面有非常多的字符串工具函数。

ackage main

import (
   "errors"
   "fmt"
   "strings"
)

type user struct {
   name     string
   password string
}

func main() {
   a := "heello"
   fmt.Println(strings.Contains(a, "ll"))               //判断a中是否包含字符
   fmt.Println(strings.Count(a, "l"))                   //计算a中包含字符的个数
   fmt.Println(strings.HasPrefix(a, "he"))              //判断a中是否包含前缀
   fmt.Println(strings.HasSuffix(a, "llo"))             //判断a中是否包含后缀
   fmt.Println(strings.Index(a, "ll"))                  //计算a中字符的下标
   fmt.Println(strings.Join([]string{"he", "llo"}, "")) //将两个字符串通过字符连接起来
   fmt.Println(strings.Repeat(a, 2))                    //复制n次字符串
   fmt.Println(strings.Replace(a, "e", "E", 1))         //替换a中的n个字符
   fmt.Println(strings.Split("a-b-c", "-"))             //通过指定字符分割字符串
   fmt.Println(strings.ToLower(a))                      //将字符串中的字符变成小写字符
   fmt.Println(strings.ToUpper(a))                      //将字符串中的字符变成大写字符
   fmt.Println(len(a))                                  //计算字符长度
}

1.6 字符串格式化

在标准库的fmt包里面有非常多的字符串格式化的相关方法,最常用的如下面的代码所示。

package main

import (
   "fmt"
)

type point struct {
   x, y int
}

func main() {
   s := "hello"
   n := 123
   p := point{1, 2}
   fmt.Println(s, n)
   fmt.Println(p)
   fmt.Printf("s=%v\n", s)
   fmt.Printf("n=%v\n", n)
   fmt.Printf("p=%v\n", p)
   fmt.Printf("p=%+v\n", p)
   fmt.Printf("p=%#v\n", p)

   f := 3.1415926
   fmt.Printf("%.2f\n", f)
}

1.7 json处理

goland里的json处理非常简单,只需要在结构体中每个字段首字母大写,那么这个结构体就能够序列化,序列化后的字符串也可以进行反序列化,具体操作如下所示。

package main

import (
   "encoding/json"
   "fmt"
)

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

func main() {
   a := userInfo{"WangGang", 18, []string{"Goland", "Python", "Java"}}
   buf, err := json.Marshal(a)
   if err != nil {
      println(err)
   }
   fmt.Println(buf)
   fmt.Println(string(buf))
   buf, err = json.MarshalIndent(a, "", "\t")
   if err != nil {
      println(err)
   }
   fmt.Println(buf)
   fmt.Println(string(buf))
   var b userInfo
   err = json.Unmarshal(buf, &b)
   if err != nil {
      panic(err)
   }
   fmt.Printf("%#v\n", b)
}

1.8 时间处理

package main

import (
   "fmt"
   "time"
)
func main() {
   now := time.Now()
   fmt.Println(now)
   t1 := time.Date(2022, 7, 12, 14, 30, 25, 0, time.UTC)
   t2 := time.Date(2022, 3, 28, 11, 25, 36, 0, time.UTC)
   fmt.Println(t1)
   fmt.Println(t2.Year(), t2.Month(), t2.Day(), t2.Hour(), t2.UTC())
   fmt.Println(t1.Format("2006-01-02 15:04:05"))
   diff := t2.Sub(t1)
   fmt.Println(diff)
   fmt.Println(diff.Minutes(), diff.Seconds())
   t3, err := time.Parse("2006-01-02 15:04:05", "2022-07-12 14:30:25")
   if err != nil {
      panic(err)
   }
   fmt.Println(t3 == t1)   // true
   fmt.Println(now.Unix()) // 1648738080
}

1.9 数字解析

  1. ParseInt函数 func ParseInt(s string, base int, bitSize int) (i int64, err error) 返回字符串表示的整数值,接受正负号。 base指定进制(2到36),如果base为0,则会从字符串前置判断,"0x"是16进制,"0"是8进制,否则是10进制;bitSize指定结果必须能无溢出赋值的整数类型,0、8、16、32、64 分别代表 int、int8、int16、int32、int64;返回的err是*NumErr类型的,如果语法有误,err.Error = ErrSyntax; 如果结果超出类型范围err.Error = ErrRange。
  2. Atoi函数 func Atoi(s string) (i int, err error) Atoi是ParseInt(s, 10, 0)的简写
package main

import (
   "fmt"
   "strconv"
)

func main() {
   f, _ := strconv.ParseFloat("1.345", 64)
   fmt.Println(f)
   n, _ := strconv.ParseInt("111", 10, 64)
   fmt.Println(n)

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

   n2, _ := strconv.Atoi("123")
   fmt.Println(n2) // 123

   n3, err := strconv.Atoi("AAA")
   fmt.Println(n3, err) // 0 strconv.Atoi: parsing "AAA": invalid syntax
}