• 作者:老汪软件技巧
  • 发表时间:2024-11-05 21:01
  • 浏览量:

var a = "initial"
g := a + "foo"

同时支持显示指定变量类型:

var b, c int = 1, 2

常量的声明,使用 const 关键字:

const s string = "constant"

基础语法 - if-else

Go 中 if-else 语句判断条件中无需 "()",但是 if-else 内容模块必须要用 "{}" 框选住。

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

基础语法 - 循环

Go 中只有 for 关键字,没有 while, do while ...,for 中的语句可以像 c++ for 一样分三段,也可以像 c++ while 一样,是一个判断语句。

package main
import "fmt"
func main() {
    i := 1
    for {
        fmt.Println("loop")
        break
    }
    for j := 7; j < 9; j++ {
        fmt.Println(j)
    }
    for i <= 3 {
        fmt.Println(i)
        i = i + 1
    }
}

基础语法 - switch

Go switch 中每个 case 默认 break,并且 switch 变量可以是任意类型,甚至是条件判断语句。这不同于 C++, Java ...

package main
import (
    "fmt"
    "time"
)
func main() {
    a := 2
    switch a {
    case 1:
        fmt.Println("one")
    case 2:
        fmt.Println("two")
    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")
    }
}

基础语法 - 数组

Go 数组同 C++, Java 一样,支持初始化、索引访问等方法,但是其长度是不可变的,所以在实际应用中很少使用数组。

package main
import "fmt"
func main() {
    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)
}

基础语法 - 切片

Go 通过关键字 make 创建切片,切片长度是可变的,通过关键字 append 追加元素。注意: append 追加元素之后必须重新赋值,这是因为当切片容量不足时,底层会重新创建一个新的数组,并返回。Go 切片也支持同 Python 一样的访问方式。

package main
import "fmt"
func main() {
    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 := make([]string, len(s))
    copy(c, s)
    fmt.Println(c) // [a b c d e f]
    fmt.Println(s[2:5]) // [c d e]
    fmt.Println(s[:5])  // [a b c d e]
    fmt.Println(s[2:])  // [c d e f]
    good := []string{"g", "o", "o", "d"}
    fmt.Println(good) // [g o o d]
}

基础语法 - map

Go 中 map 通过关键字 make 创建,需要指定 key value 的类型。同时,在获取 map 中元素时,会返回是否存在该 key 。在 Go 中, map 的 key 是无序存储的。

package main
import "fmt"
func main() {
    m := make(map[string]int)
    m["one"] = 1
    m["two"] = 2
    fmt.Println(m)           // map[one:1 two:2]
    fmt.Println(len(m))      // 2
    fmt.Println(m["one"])    // 1
    fmt.Println(m["unknow"]) // 0
    r, ok := m["unknow"]
    fmt.Println(r, ok) // 0 false
    delete(m, "one")
    m2 := map[string]int{"one": 1, "two": 2}
    var m3 = map[string]int{"one": 1, "two": 2}
    fmt.Println(m2, m3)
}

基础语法 - range

Go 支持通过关键字 range 来便捷访问容器,例如:数组,map , ...

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 中的函数支持返回多个变量,一般情况下都至少返回两个变量,一个表示函数处理结果,一个表示出现的异常。

func add(a int, b int) int {
    return a + b
}
func exists(m map[string]string, k string) (v string, ok bool) {
    v, ok = m[k]
    return v, ok
}

基础语法 - 指针

Go 同 C++ 一样,也支持指针操作。 "*", "&" 关键字分别表示取值、取址操作符。另外,同 C++ 一样,函数参数变量是拷贝,而不是像 Java, Python 一样的引用。

package main
import "fmt"
func add2(n int) {
    n += 2
}
func add2ptr(n *int) {
    *n += 2
}
func main() {
    n := 5
    add2(n)
    fmt.Println(n) // 5
    add2ptr(&n)
    fmt.Println(n) // 7
}

基础语法 - 结构体

Go 同 C++ 一样,可以定义结构体,并对其进行初始化、访问属性、修改属性、作为函数参数、使用指针 ...

package main
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
}
func checkPassword2(u *user, password string) bool {
    return u.password == password
}

基础语法 - 结构体函数

Go 中支持两种方式为结构体定义函数:不带指针、带指针。如果带指针,则可以对结构体内部进行修改。

type user struct {
    name     string
    password string
}
func (u user) checkPassword(password string) bool {
    return u.password == password
}
func (u *user) resetPassword(password string) {
    u.password = password
}

基础语法 - 错误处理

Go 中通过 error 类型表示错误,一般情况下,当一个函数抛出错误时,同时返回 nil, error 其中 nil 表示空值。

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

基础语法 - json处理

Go 支持结构体序列化,即转为json格式。只需要将结构体的所有属性第一个字母大写,如果在转化后想小写显示,只需要在属性后面加上 json:"age"。通过 Marshal, Unmarshal 方法进行序列化、反序列化。同时 MarshalIndent 方法支持格式化序列化结果。

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

实战案例 - 猜谜游戏

通过 math/rand 生成随机数。

maxNum := 100
secretNumber := rand.Intn(maxNum)
fmt.Println("The secret number is ", secretNumber)

但是这样每次运行生成的是相同的随机数,于是需要在程序开始时初始化随机种子。注意:在1.20版本之后, rand.Seed() 已被弃用,用 rand.NewSource() 代替。

maxNum := 100
rand.Seed(time.Now().UnixNano())
secretNumber := rand.Intn(maxNum)
fmt.Println("The secret number is ", secretNumber)

捕获用户输入,并将字符串转为 int 类型。

reader := bufio.NewReader(os.Stdin)
input, err := reader.ReadString('\n')
input = strings.Trim(input, "\r\n")
guess, err := strconv.Atoi(input)
fmt.Println("You guess is", guess)

将 guess 与 secretNumber 比较。

if guess > secretNumber {
    fmt.Println("Your guess is bigger than the secret number. Please try again")
} else if guess < secretNumber {
    fmt.Println("Your guess is smaller than the secret number. Please try again")
} else {
    fmt.Println("Correct, you Legend!")
}

最后添加上 for 循环,处理用户多次猜测。

实战案例 - 在线词典

创建客户端,以及请求信息,包括:将 json 字符串转为数据流,设置请求头。然后,发送请求,获取返回的 response 信息。

client := &http.Client{}
var data = strings.NewReader(`{"trans_type":"en2zh","source":"good"}`)
req, err := http.NewRequest("POST", "https://api.interpreter.caiyunai.com/v1/dict", data)
req.Header.Set("Connection", "keep-alive")
...
resp, err := client.Do(req)

将接收到的 response 数据流打印,然后,关闭数据流。 defer 关键字将在函数执行完毕后,从下至上依次执行。

defer resp.Body.Close()
bodyText, err := ioutil.ReadAll(resp.Body)
fmt.Printf("%s\n", bodyText)

为请求参数创建相应的结构体 DictRequest , 为返回响应参数创建结构体 DictResponse. Go 支持结构体嵌套。

type DictRequest struct {
    TransType string `json:"trans_type"`
    Source    string `json:"source"`
    UserID    string `json:"user_id"`
}
type DictResponse struct {
    Rc   int `json:"rc"`
    Wiki struct {
        KnownInLaguages int `json:"known_in_laguages"`
        Description     struct {
            Source string      `json:"source"`
            Target interface{} `json:"target"`
        } `json:"description"`
        ID   string `json:"id"`
        ...
    } `json:"wiki"`
    ...
}

通过 Marshal, Unmarshal 方法进行序列化、反序列化。

request := DictRequest{TransType: "en2zh", Source: "good"}
buf, err := json.Marshal(request)
...
bodyText, err := ioutil.ReadAll(resp.Body)
var dictResponse DictResponse
err = json.Unmarshal(bodyText, &dictResponse)

实战案例 - SOCKS5

SOCKS5 代理原理如下图所示,客户端先与 Socks5 服务端交互,然后通过 Socks5 服务端与目标主机 Host 建立连接、发送数据。

屏幕截图 2024-11-02 210448.png

总结

本次课程学习了 Go 语言的基础语法,包括如何运行 Go 项目、变量、循环、判断语句、数组、切片、函数、指针、结构体、错误、字符串等内容。同时,通过三个 Go 语言的实战案例,巩固练习了相关基础知识点。


上一条 查看详情 +没有了
下一条 查看详情 +没有了