快速入门Go(5)

Go·语法 2019-02-07 8035 字 1344 浏览 点赞

前言

这是我学习Go语法的笔记。由于有C和Python的基础,上手Go很快。笔记很粗糙,好在自己够用。

此篇包括了Go相关的:错误处理,字符串处理,正则,JSON,文本操作。

异常处理

error

官方errors包源码如下:

// Package errors implements functions to manipulate errors.
package errors

// New returns an error that formats as the given text.
func New(text string) error {
    return &errorString{text}
}

// errorString is a trivial implementation of error.
type errorString struct {
    s string
}

func (e *errorString) Error() string {
    return e.s
}

New()函数是返回一个errorString类型的变量,这种类型的变量拥有Error()方法,用法如下:

err := errors.New("this is a err")
fmt.Println(err.Error())
// 输出:
this is a err

另一种error来自于fmt包:

err := fmt.Errorf("%s", "this is error in fmt")
fmt.Println(err)
// 输出:
this is error in fmt

一个完整的errors的使用:

func myDiv(a, b int) (result int, err error) {
    if b == 0 {
        err = errors.New("除数不能为0")
    } else {
        result = a / b
    }
    return
}

func main() {
    result, err := myDiv(10, 0)
    if err != nil {
        fmt.Println(err.Error())
    } else {
        fmt.Println("结果为:", result)
    }

}

panic

致命错误
panic()

recover

必须放在defer后面使用。恢复程序。

func testb(x int) {
    defer func() {
        if err := recover(); err != nil {  // 只在出现panic错误的起作用
            fmt.Println(err)
        }
    }()

    var a[10] int
    a[x] = 111  // 当x>=10之后,属于越界访问
}

func main() {
    testb(100)
}
// 输出:
runtime error: index out of range

当没有错误时,recover()函数返回nil,如果有错误,则返回错误信息。

字符串处理

字符串操作(strings)

  • Contains

    // 前者(str)是否包含后者(substr)
    fmt.Println(strings.Contains("hello world", "hello"))  // true
    fmt.Println(strings.Contains("hello world", "abc"))  // false
  • Join

    // 组合,类似Python中的 "".join()
    s := []string{"abc", "zty", "guan", "suanle"}
    fmt.Println(strings.Join(s, ","))  // abc,zty,guan,suanle
  • Index

    // 子字符串在字符串中出现的位置,第一个字符的索引,不存在返回-1
    fmt.Println(strings.Index("helloworld", "wor"))  // 5
    fmt.Println(strings.Index("helloworld", "go"))  // -1
  • Repeat

    // 重复次数
    buf := strings.Repeat("zty", 3)
    fmt.Println(buf)  // ztyztyzty
  • Replace

    // 替换
    fmt.Println(strings.Replace("abcbe", "b", "!", 2))  // a!c!e
  • Split

    // 按指定sep拆分,返回切片
    str := "zty-zty-zty"
    result := strings.Split(str, "-")
    fmt.Println(result)  // [zty zty zty]
  • Trim

    // 去掉两头
    words := "fre--fre--fre"
    fmt.Println(strings.Trim(words, "fre"))  // --fre--
  • Fields

    // 去除字符串中的所有空格,返回切片
    fmt.Println(strings.Fields(" ef er 3   op"))  // [ef er 3 op]

字符串转换(strconv)

  • Append

    // 转换成字符串后追加到字节数组
    func main() {
      // 定义一个切片
      slice := make([]byte, 0, 1024)
      // 追加一个bool类型的变量
      slice = strconv.AppendBool(slice, true)
      // 追加一个1234的值,10进制
      slice = strconv.AppendInt(slice, 1234, 10)
      // 追加一个字符串
      slice = strconv.AppendQuote(slice, "hello")
    
      fmt.Printf("%s", slice)
      // 输出:true1234"hello"
    }
  • Format

    // 其他类型转化成字符串
    
    // prec控制精度(排除指数部分):
    // 对'f'、'e'、'E',它表示小数点后的数字个数;
    // 对'g'、'G',它控制总的数字个数。
    // 如果prec 为-1,则代表使用最少数量的、但又必需的数字来表示f。
    str := strconv.FormatFloat(3.14, 'f', -1, 64)
    fmt.Printf("内容:%s, 类型:%T", str, str)
    // 输出:内容:3.14, 类型:string
// 整型转字符串

num := 512
numStr := strconv.Itoa(num)
fmt.Printf("numStr的类型是 %T\n", numStr)
// 输出:numStr的类型是 string
  • Parse

    // 字符串转换成其他类型
    
    // 字符串转bool
    flag, _ := strconv.ParseBool("true")
    fmt.Printf("flag = %v,其类型为:%T\n", flag, flag)
    
    // 字符串转整型
    // base: 取值2-36,表示进位制。如果base=0,根据字符串前缀判断
    num, _ := strconv.ParseInt("512", 10, 64)
    fmt.Printf("num = %d,其类型为:%T\n", num, num)
    // num = 512,其类型为:int64
    
    anotherNum, _ := strconv.ParseInt("0xA", 0, 64)
    fmt.Printf("anotherNum = %d,其类型为:%T\n", anotherNum, anotherNum)
    // anotherNum = 10,其类型为:int64
    
    // 另一种字符串转整型
    newNum, _ := strconv.Atoi("512")
    fmt.Printf("newNum = %d,其类型为:%T\n", newNum, newNum)
    // newNum = 512,其类型为:int

正则

package main

import (
    "fmt"
    "regexp"  // 正则包
)

func main() {
    str := "12334dew32kor435md.fer"
    // 生成规则
    reg := regexp.MustCompile( `\d+`)
    // reg为空时表示失败
    if reg != nil {
        fmt.Println(reg)
    }
    // -1表示匹配所有,1表示只匹配一个
    res := reg.FindAllString(str, -1)  // 匹配
    fmt.Println(res)
    // 输出:[12334 32 435]
}

JSON

编码

通过结构体生成JSON:

package main

import (
    "encoding/json"
    "fmt"
)

// 成员变量名首字母必须大写
type IT struct {
   Company string
   Subject []string
   IsOK bool
   Price float64
}

func main() {
    ajson := IT{"alibaba", []string{"C++", "Go", "Python"}, true, 512}

    // 编码。生成json格式的文本
    buf, _ := json.MarshalIndent(ajson, "", " ")  // 保留缩进
    // buf, _ := json.Marshal(ajson)  // 无缩进信息

    fmt.Println(string(buf))
}

// 输出:
{
 "Company": "alibaba",
 "Subject": [
  "C++",
  "Go",
  "Python"
 ],
 "IsOK": true,
 "Price": 512
}
// 二次编码
type IT struct {
   Company string `json:"-"`  // 不要输出到屏幕
   Subject []string `json:"subject"`  // 变量名以subject的方式显示
   IsOK bool `json:",string"`  // 键值以字符串的格式显示
   Price float64 `json:",string"`
}

// 对应输出:
{
 "subject": [
  "C++",
  "Go",
  "Python"
 ],
 "IsOK": "true",
 "Price": "512"
}

通过map生成JSON:

func main() {
    ajson := make(map[string]interface{}, 4)
    ajson["company"] = "alibaba"
    ajson["subject"] = []string{"C++", "Go", "Python"}
    ajson["isok"] = true
    ajson["price"] = 512

    res, _ := json.Marshal(ajson)
    fmt.Println(string(res))
}

// 输出:
{"company":"alibaba","isok":true,"price":512,"subject":["C++","Go","Python"]}

解码

对于结构体:

type IT struct {
    Company string `json:"company"`
    Subject []string `json:"subject"`
    Isok bool `json:"isok"`
    Price float64 `json:"price"`
}

func main() {
    jsonstr := `{"company":"alibaba","isok":true,"price":512,"subject":["C++","Go","Python"]}`

    var it IT
    // 第二个参数必须是指针,这样才能改变里面的值
    if err := json.Unmarshal([]byte(jsonstr), &it); err != nil {
        fmt.Println(err)
    } else {
        fmt.Println(it)
    }

}

对于map:

func main() {
    jsonstr := `{"company":"alibaba","isok":true,"price":512,"subject":["C++","Go","Python"]}`

    jsonmap := make(map[string]interface{}, 4)  // 切片
    if err := json.Unmarshal([]byte(jsonstr), &jsonmap); err != nil {
        fmt.Println(err)
    } else {
        fmt.Println(jsonmap)
    }

    var (
        str string
        slice []interface{}
    )
    // 通过类型断言(反推类型),取出每个字段的内容
    for _, value := range jsonmap{
        switch data := value.(type) {
        case string:
            str = data
        case []interface{}:  // 注意为空类型的切片,而不是字符串切片
            slice = data
        }
    }

    fmt.Println(str)   // 输出:alibaba
    fmt.Println(slice)  // 输出:[C++ Go Python]
}

文本操作

写内容:

func WriteToFile(path string) {
    f , _ := os.Create(path)  // 创建一个文件

    for i :=  0; i < 10; i++ {
        s := fmt.Sprintf("this is %d\n", i)
        _, err := f.WriteString(s)  // 写入字符串
        if err != nil {
            fmt.Printf("error: %v", err)
            return
        }
    }

    defer f.Close()
}

读内容:

func ReadFromFile(path string) {
    f, _ := os.Open(path)  // 打开一个文件

    content := make([]byte, 1024 * 2)  // 创建一个切片,存放读取内容
    // n 表示读取了多少个字节
    n, err := f.Read(content)  // 读取内容
    if err != nil {
        fmt.Println(err)
        return
    }
    fmt.Println(string(content[:n]))  // content[:n] 只打印有内容的部分

    defer f.Close()
}

注意:os.Create()os.Open()都是对os.OpenFile()做了封装。

结合bufio一行一行的读取:

f, _ := os.Open(path)

bf := bufio.NewReader(f)
for {
    // 以`\n`来读
    // buf存储读取到的内容,包含`\n`
    buf, err := bf.ReadBytes('\n')
    if err != nil {
        // 文件内容读取完
        if err ==  io.EOF {
            break
        }
    }
    fmt.Printf(string(buf))
}

defer f.Close()


本文由 Guan 创作,采用 知识共享署名 3.0,可自由转载、引用,但需署名作者且注明文章出处。

还不快抢沙发

添加新评论