1.1 进阶语法——函数
package main
import "fmt"
func add(a, 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
}
func main() {
fmt.Println(add(2, 10))
fmt.Println(exists(map[string]string{"a": "A"}, "a"))
}
1.2 进阶语法——指针
- 和C艹一样,如果想通过形参修改实参,只能通过指针操作更改地址的内容
package main
import "fmt"
func add(n int) {
n += 2
}
func add2ptr(n *int) {
*n += 2
}
func main() {
n := 5
add(n)
fmt.Println(n)
add2ptr(&n)
fmt.Println(n)
}
1.3 进阶语法——结构体
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
}
1.3 进阶语法——结构体方法
package main
import "fmt"
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
}
func main() {
a := user{name: "wang", password: "1024"}
a.resetPassword("2048")
fmt.Println(a.checkPassword("2048")) // true
}
- 把u user从形参列移动到func关键字后面,就变成了类成员函数
1.3 进阶语法——错误处理
package main
import (
"errors"
"fmt"
)
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")
}
func main() {
u, err := findUser([]user{{"wang", "123"}, {"li", "321"}}, "li")
if err != nil {
fmt.Println(err)
return
}
fmt.Println(u.name)
if u, err := findUser([]user{{"wang", "123"}, {"li", "321"}}, "lijie"); err != nil {
fmt.Println(err)
return
} else {
fmt.Println(u.name)
}
}
- GO语言的异常检测可以在函数返回值中进行指定,可以很容易地知道哪一块的错误
- 在findUser函数中,形参是增加了指针的user,是因为如果发生异常,返回值需要返回nil,结构体对象是值类型,所以需要增加指针。
- 在这段代码中,最后的if语句和其他语言不太一样,更像for循环的语法一样,其中有个封号“;”。这是Go语言的一个特性,允许在条件部分声明并赋值变量,然后在条件判断之后使用这些变量。
1.4 进阶语法——字符串
package main
import (
"fmt"
"strings"
)
func main() {
a := "hello"
fmt.Println(strings.Contains(a, "ll")) // 字符串是否被包含
fmt.Println(strings.Count(a, "l")) // 查找指定字符串的数目
fmt.Println(strings.HasPrefix(a, "hell")) // 字符串是否以某个字符串打头
fmt.Println(strings.Index(a, "ll")) // 查找字符串的位置索引
fmt.Println(strings.Join([]string{"he", "llo"}, "+")) // 拼接列表
fmt.Println(strings.Repeat(a, 3)) // 重复多个字符串
fmt.Println(strings.Replace(a, "e", "E", -1)) // 替换字符,-1表示替换所有的指定字符
fmt.Println(strings.Split("a-2-3-6", "-")) // 根据指定符号将字符串分割为列表
fmt.Println(strings.ToUpper(a)) // 字符串转大写
fmt.Println(strings.ToLower(a)) // 字符串转小写
fmt.Println(len((a))) // 输出字符串长度
}
1.4 进阶语法——字符串格式化
package main
import "fmt"
type point struct {
x, y int
}
func main() {
s := "hello"
n := 123
p := point{1, 2}
fmt.Println(s, n) // hello 123
fmt.Println(p) // {1 2} 点数据类型
fmt.Printf("s=%v\n", s) // s=hello
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
}
- go语言可以用%v格式化所有数据,不像c和py需要区分,采用“%+v”和“&#v”会格式化输出更详细的内容
1.5 进阶语法——JSON处理
package main
import (
"encoding/json"
"fmt"
)
// 属性名首字母需要大写
type userInfo struct {
Name string
Age int `json:"age"`
Hobby []string
}
func main() {
u := userInfo{Name: "LIHUA", Age: 18, Hobby: []string{"eat", "sleep", "play"}}
buf, err := json.Marshal(u)
if err != nil {
panic(err)
}
fmt.Println(buf)
fmt.Println(string(buf))
buf, err = json.MarshalIndent(u, "", "\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"}}
}
- GO语言JSON转换可以直接在结构体中定义字段,然后利用json.Marshal将结构体转为JSON16进制的列表流,转为string后即转为了JSON字段,这个思路我很是喜欢。
- 要注意,在结构体中定义属性的时候,首字母需要大写,否则转为JSON时,该属性值会消失。
- 如果非要修改json的key,可以在定义结构体的时候,增加类似java的@JsonField的字符,简单好用。
1.6 进阶语法——时间处理
package main
import (
"fmt"
"time"
)
func main() {
now := time.Now()
fmt.Println(now)
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)
fmt.Println(t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), t.Second())
fmt.Println(t.Format("2006-01-02 15:04:05"))
diff := t2.Sub(t)
fmt.Println(diff)
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)
fmt.Println(now.Unix())
}
- t.Format()方法内可以列举一个时间,然后t就可以转为该格式(批量操作很适用)
- t.now()方法可以制造一个时间戳,一般可以作为防止重复命名的标记
1.6 进阶语法——数字解析
package main
import (
"fmt"
"strconv"
)
func main() {
f, _ := strconv.ParseFloat("3.14159", 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
n2, err := strconv.Atoi("AAA")
fmt.Println(n2, err)
}
- strconv的包,可以理解为自
- Atoi 函数用于将字符串转换为 int 类型,Itoa 函数则用于将 int 类型转换为字符串类型。
1.6 进阶语法——进程信息
package main
import (
"fmt"
"os"
"os/exec"
)
func main() {
fmt.Println(os.Args)
fmt.Println(os.Getenv("PATH"))
buf, err := exec.Command("grep", "127.0.0.1", "etc/hosts").CombinedOutput()
if err != nil {
panic(err)
}
fmt.Print(string(buf))
}
1.7 goto有益论
在60年代末和70年代初,关于GOTO语句的用法的争论比较激烈。主张从高级程序语言中去掉GOTO语句的人认为,GOTO语句是对程序结构影响最大的一种有害的语句,他们的主要理由是:GOTO语句使程序的静态结构和动态结构不一致,从而使程序难以理解,难以查错。去掉GOTO语句后,可直接从程序结构上反映程序运行的过程。这样,不仅使程序结构清晰,便于理解,便于查错,而且也有利于程序的正确性证明。
- 我惊奇地发现,在go语言中居然有和C艹一样的goto语句,goto语句在专家看来会增加程序结构,增加代码阅读的难度,但是对于做题党来说:谁说这goto有害鸭?这goto可太棒啦!平时写算法题和一些功能脚本来说,goto尊嘟是省了太多事了。例如下面这个例子中,可以体现出goto的强大,可以随时跳转到程序的任何部位,包括已经执行过的程序的位置。
package main
import (
"fmt"
"time"
)
func main() {
num:=10
var input int
gotoLabel:
fmt.Scanf("%d", &input)
if input == 1 {
fmt.Println("input is 1")
for i:=0;i<num;i++{
//循环输入一组数字,判断是否是斐波那契数列,如果不是,则提示输入不合法,重新输入
}
if 结果不满足数列{
fmt.Println("输入不合法,请重新输入")
time.Sleep(2*time.Second)
goto gotoLabel
}
} else if input == 2 {
//循环输入一组数字,判断是否是等差数列,如果不是,则提示输入不合法,重新输入
//……………………
}
}