- 作者:老汪软件技巧
- 发表时间: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 建立连接、发送数据。
总结
本次课程学习了 Go 语言的基础语法,包括如何运行 Go 项目、变量、循环、判断语句、数组、切片、函数、指针、结构体、错误、字符串等内容。同时,通过三个 Go 语言的实战案例,巩固练习了相关基础知识点。