go语言基础语法 | 豆包MarsCode AI刷题

165 阅读10分钟

hello Go!

Go 语言的基础组成有以下几个部分:

  • 包声明
  • 引入包
  • 函数
  • 变量
  • 语句 & 表达式
  • 注释
package main
 
import (
    "fmt"
)

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

在命令行使用go run helloworld.go运行

变量

    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)                // initialapple 
    //const表示声明为常量 
    const s string = "constant"
    const h = 500000000
    const i = 3e20 / h
    fmt.Println(s, h, i, math.Sin(h), math.Sin(i))

go语言可以不显示声明变量类型,可以通过var自动的进行类型声明var a int为主要的变量声明方式,表示声明一个int类型的变量,此外,可以通过a := 2声明一个int类型,值为2的变量a。

循环

go语言主要使用for循环,go的for循环不需要加括号。和java ,c类似,第一个条件为初始化,第二个为判断语句,第三个为循环结束后运行的语句。

    i := 1
    for {
        fmt.Println("loop")
        break
    }

    for j := 7; j < 9; j++ {
        fmt.Println(j)
    }
  
    for n := 0; n < 5; n++ {
        if n%2 == 0 {
            continue
        }
        fmt.Println(n)
    }

    for i <= 3 {
        fmt.Println(i)
        i = i + 1
    }

if判断

大体和其他语言类似,但是go语言中if可以和for一样,可以初始化变量

    if 7%2 == 0 {
        fmt.Println("7 is even")
    } else {
        fmt.Println("7 is odd")
    }

  
    if 8%4 == 0 {
        fmt.Println("8 is divisible by 4")
    }
  //这里初始化num为9
    if num := 9; num < 0 {
        fmt.Println(num, "is negative")
    } else if num < 10 {
        fmt.Println(num, "has 1 digit")
    } else {
        fmt.Println(num, "has multiple digits")
    }

switch语句

go的switch语句不仅仅可以接受int char,即使是布尔类型,结构体也可以作为传参

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")
    }
	//这里替代if语句
    t := time.Now()
    switch {
    case t.Hour() < 12:
        fmt.Println("It's before noon")
    default:
        fmt.Println("It's after noon")
    }

数组

	//一维数组
	var a [5]int
    a[4] = 100
    fmt.Println("get:", a[2])
    fmt.Println("len:", len(a)) 
    //初始化一维数组
    b := [5]int{1, 2, 3, 4, 5}
    fmt.Println(b)  
	//二维数组
    var twoD [2][3]int
    for i := 0; i < 2; i++ {
        for j := 0; j < 3; j++ {
            twoD[i][j] = i + j
        }
    }
    fmt.Println("2d: ", twoD)

slice切片

go里的slice切片类似java中的集合List

// 创建一个长度为3的字符串切片
    s := make([]string, 3)
    // 向切片中添加元素
    s[0] = "a"
    s[1] = "b"
    s[2] = "c"
    // 打印切片的第三个元素
    fmt.Println("get:", s[2]) // c
    // 打印切片的长度
    fmt.Println("len:", len(s)) // 3

    // 向切片中添加一个元素
    s = append(s, "d")
    // 向切片中添加两个元素
    s = append(s, "e", "f")
    // 打印切片的所有元素
    fmt.Println(s) // [a b c d e f]

    // 创建一个新的切片c,其长度与s相同
    c := make([]string, len(s))
    // 将切片s的内容复制到切片c中
    copy(c, s)
    // 打印切片c的所有元素
    fmt.Println(c) // [a b c d e f]

    // 打印切片s从第三个元素到第五个元素的所有元素
    fmt.Println(s[2:5]) // [c d e]
    // 打印切片s从第一个元素到第五个元素的所有元素
    fmt.Println(s[:5]) // [a b c d e]
    // 打印切片s从第三个元素到最后一个元素的所有元素
    fmt.Println(s[2:]) // [c d e f]

    // 创建一个新的字符串切片good,并初始化它
    good := []string{"g", "o", "o", "d"}
    // 打印切片good的所有元素
    fmt.Println(good) // [g o o d]

map

go中的map类似java的hashmap,存储k-v的结构

// 创建一个空的map,键为字符串string类型,值为整数int类型
    m := make(map[string]int)
    // 向map中添加一个键值对
    m["one"] = 1
    // 向map中添加一个键值对
    m["two"] = 2
    // 打印map
    fmt.Println(m)           // map[one:1 two:2]
    // 打印map的长度
    fmt.Println(len(m))      // 2
    // 打印map中键为"one"的值
    fmt.Println(m["one"])    // 1
    // 打印map中键为"unknow"的值,因为该键不存在,所以返回默认值0
    fmt.Println(m["unknow"]) // 0

    // 使用ok-idiom检查map中键为"unknow"的值是否存在
    r, ok := m["unknow"]
    // 打印返回值和是否存在的标志
    fmt.Println(r, ok) // 0 false

    // 删除map中键为"one"的键值对
    delete(m, "one")

    // 创建一个新的map,并初始化它
    m2 := map[string]int{"one": 1, "two": 2}
    // 使用var关键字声明一个新的map,并初始化它
    var m3 = map[string]int{"one": 1, "two": 2}
    // 打印两个新map
    fmt.Println(m2, m3)

map和slice都需要用到make关键字

range方法

有关切片的range方法

nums := []int{2, 3, 4}
    sum := 0
    //i为序号,num为slice元素
    for i, num := range nums {
        sum += num
        if num == 2 {
            fmt.Println("index:", i, "num:", num) // index: 0 num: 2
        }
    }
    fmt.Println(sum) // 9

有关map的range方法

 m := map[string]string{"a": "A", "b": "B"}
 //k为key,v为value元素
    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
    }

func方法

//func 函数名(形参...) (返回值...){
//	函数体
//}  
func add(a int, b int) int {
    return a + b
}
  
func add2(a, b int) int {
    return a + b
}  
//go可以有多个返回值,ok以及err是非常常用的返回值
func exists(m map[string]string, k string) (v string, ok bool) {
    v, ok = m[k]
    return v, ok
}

返回值error类型的err是方法多返回值的一个广泛应用,类似其他语言的异常处理机制

point指针

类似c++的引用传递和值传递,但是要注意,go里面只有值传递(类似),即使是结构体也只有传递指针才能修改结构体

import "fmt"
//n不会变化
func add2(n int) {
    n += 2
}
//n会变化
func add2ptr(n *int) {
    *n += 2
}
  
func main() {
	//可以通过new一个指针,初始化时为空nil
	A := new(int)

    n := 5
    add2(n)
    fmt.Println(n) // 5
    add2ptr(&n)
    fmt.Println(n) // 7
}

结构体

结构体类似c++ java中的对象,go不是面向对象的语言

import "fmt"
  
type user struct {
    name     string
    password string
}
  
func main() {
    a := user{name: "wang", password: "1024"}
    b := user{"wang", "1024"}
    c := user{name: "wang"}
    c.password = "1024"
    var d user
    d.name = "wang"
    d.password = "1024"  
    fmt.Println(a, b, c, d)                 // {wang 1024} {wang 1024} {wang 1024} {wang 1024}
    fmt.Println(checkPassword(a, "haha"))   // false
    fmt.Println(checkPassword2(&a, "haha")) // false
}
  
func checkPassword(u user, password string) bool {
    return u.password == password
}
  //注意这里需要传递user指针才能对user结构体进行修改
func checkPassword2(u *user, password string) bool {
    return u.password == password
}

结构体方法

import "fmt"

type user struct {
    name     string
    password string
}
  //第一种(u user)
func (u user) checkPassword(password string) bool {
    return u.password == password
}
  //第二种(u *user)用于修改结构体
func (u *user) resetPassword(password string) {
    u.password = password
}
  
func main() {
    a := user{name: "wang", password: "1024"}
    a.resetPassword("2048")
    fmt.Println(a.checkPassword("2048")) // true
}

error异常

go的异常处理机制相比java和c++要简单的多,nil一般表示空,即无异常

import (
    "errors"
    "fmt"
)
  
type user struct {
    name     string
    password string
}

func findUser(users []user, name string) (v *user, err error) {
	//结构体切片users
    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)
    }
}

string的一些操作方法

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中文字符串的长度

格式化打印fmf流

	import "fmt"

	type point struct {	
	    x, y int	
	}

	s := "hello"
    n := 123
    p := point{1, 2}
    fmt.Println(s, n) // hello 123 联合打印
    fmt.Println(p)    // {1 2} 打印结构体
    //  这里\n替代了Println的回车
    fmt.Printf("s=%v\n", s)  // s=hello 打印值,等价于不带参数s=%v\n,以默认的方式打印变量的值
    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  %.2f 保留两位小数

json的使用

Go开发人员经常需要处理JSON内容。例如,我们经常要读取JSON文件来填充Go对象,并从现有的Go对象中写入JSON文件。像其他现代编程语言一样,Go提供了一个标准库模块来处理JSON结构。

Go提供了encoding/json包,通过标准库的编码命名空间处理JSON内容。encoding/json包提供了API函数,用于从Go对象生成JSON文档--以及从JSON文档中填充Go对象。此外,它还允许你定制JSON到Go和Go到JSON的翻译过程。

将Go对象编码为JSON格式被称为marshaling。我们可以使用Marshal 函数来将 Go 对象转换为 JSON。Marshal 函数的语法如下。将一个go结构体转化为byte数组。

func Marshal(v interface{}) ([]byte, error)

使用map构造json

package main
import (
    "fmt"
    "encoding/json"
)
func main() {
    fileCount := map[string]int{
        "cpp": 10,
        "js": 8,
        "go": 10,
    }
    bytes, _ := json.Marshal(fileCount)
    fmt.Println(string(bytes))
}

使用结构体构造json:

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"]}

输出格式化的json:json.MarshalIndent(a, "", "\t")


    buf, err = json.MarshalIndent(a, "", "\t")
    if err != nil {
        panic(err)
    }
    fmt.Println(string(buf))

json的解码:json.Unmarshal(buf, &b) 注意这里要传入结构体的引用才能返回json的go结构体

    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时间的使用

go提供了time包处理时间数据

time.Time类型表示时间。我们可以通过time.Now()函数获取当前的时间对象,然后获取时间对象的年月日时分秒等信息。

时间类型有一个自带的方法Format进行格式化,需要注意的是Go语言中格式化时间模板不是常见的Y-m-d H:M:S而是使用Go的诞生时间2006年1月2号15点04分。

t3, err := time.Parse("2006-01-02 15:04:05", "2022-03-27 01:25:36"):使用指定的格式字符串"2006-01-02 15:04:05"来解析字符串"2022-03-27 01:25:36",并将结果赋值给变量t3。如果解析失败,err会被赋值为非nil值。

fmt.Println(now.Unix()):打印当前时间的Unix时间戳(从1970年1月1日00:00:00 UTC到当前时间的秒数)。

示例代码如下:

import (
    "fmt"
    "time"
)
  
func main() {
    now := time.Now()
    fmt.Println(now) // 2022-03-27 18:04:59.433297 +0800 CST m=+0.000087933
    //设置时区为UTC
    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
}

string与数字的转化

f, _ := strconv.ParseFloat("1.234", 64) 将字符串转化为float,指定以64位存储

n, _ := strconv.ParseInt("111", 10, 64) 指定以10进制转化为int

strconv.Atoi 自动转化,如果不符合规范则返回错误信息

import (
    "fmt"
    "strconv"
)  

func main() {
    f, _ := strconv.ParseFloat("1.234", 64)
    fmt.Println(f) // 1.234  
    n, _ := strconv.ParseInt("111", 10, 64)
    fmt.Println(n) // 111  
    n, _ = strconv.ParseInt("0x1000", 0, 64)
    fmt.Println(n) // 4096  
    n2, _ := strconv.Atoi("123")
    fmt.Println(n2) // 123 
    n2, err := strconv.Atoi("AAA")
    fmt.Println(n2, err) // 0 strconv.Atoi: parsing "AAA": invalid syntax
}

环境相关

import (
    "fmt"
    "os"
    "os/exec"
)
  
func main() {
    // go run example/20-env/main.go a b c d
    fmt.Println(os.Args)           // [/var/folders/8p/n34xxfnx38dg8bv_x8l62t_m0000gn/T/go-build3406981276/b001/exe/main a b c d]
    fmt.Println(os.Getenv("PATH")) // /usr/local/go/bin...
    //设置环境变量
    fmt.Println(os.Setenv("AA", "BB"))

这是使用exec.Command()执行在linux下的grep命令,后面附带grep的参数,CombinedOutput()返回命令运行的结果(以字节数组存储)

在文件 file.txt 中查找字符串 "hello",并打印匹配的行:grep hello file.txt

参考 Linux grep 命令 | 菜鸟教程

    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
}