这是我参与「第五届青训营 」伴学笔记创作活动的第 1 天
基础语法
变量
初始化时可以不用指定类型,但如果只是生命则需要指定类型在变量的后面,常见的变量类型包括 int, float64, float32, bool, string 。声明变量格式:var name type,初始化变量格式:var name = value ,初始化则不需要添加类型。
var name string
name := "xiaoming"
常量
定义时可以不用添加类型,系统会自动判别类型。
const num = 2389479
for 循环
与C++中的for循环类似(区别在于Go中的for循环不加括号),三个参数任意一个都可省略不写。
for i := 0; i < 20; i ++ {
...
break
continue
}s
if 语句
与C++中的if语句类似(区别在于Go中的if语句不加括号)。
if condition {
...
} else if condition {
...
} else {
...
}
switch 语句
感觉比C++中的switch更加强大。第一个区别是Go中的每个case后不需要添加break语句。第二个是case后面可以放置条件表达式,而对于C++来说只能放置整形或者字符型的数据。
switch tmp {
case 1:
...
case 2, 3:
...
default:
...
}
tmp := 2
switch {
case tmp < 2:
...
case tmp > 2:
...
default:
...
}
数组
定义数组格式 var name [length]type ,初始化数组格式 name := [length]type{value1, ...} ,用 len() 可以获取数组长度,数组使用方式跟C++一样。
var names [5]string
var names:= [2]string{"xiaoming", "xiaohei"}
fmt.Println(len(names))
slice 切片
个人觉得可以理解成不定长数组,定义切片格式 name := make([]type, length) name := [] type{value, ...} ,可以使用append()添加一到多个元素,格式为 name = append(name, value, ...)。
names := make([]sting, 2)
names := []string{"xiaoming", "xiaohei"}
names = append(names, "xiaowang")
map 哈希表
跟C++的标准模板库里的map用法类似,定义:name := make(map[type1][type2]),初始化:name := map[type1]type2{key:value, ...} ,添加一个键值对:m[key] = value,删除一个键值对:delete(m, key) 。value, ok := name[key] 获取key所对应的value,如果key不存在则ok为false,否则为true。
name := make(map[string]int)
name := map[string]int{"xiaohei": 11, "xiaownag": 43}
name["xiaohah"] = 243
value, ok = name["xiaohah"]
delete(name, "xiaohah")
range
一般用在for循环中,配合使用有点类似于python常用的for循环。
nums := []int{1, 2, 3, 4}
for key, value := range nums {
...
}
// 键值对也是同样的方式
函数
可以简单理解成与c++的区别是Go可以返回多个值,在Go中传参时同样可以使用指针的形式。
func name(a *type, ...) (name returnType, ...) {
...
}
结构体
// 定义
type User struct {
name string
pwd string
}
//结构体方法,同样可以使用指针的方式
func (user *User)checkPwd(pwd string) bool {
...
}
// 赋值
a := User{name:"wang", pwd: "1024"}
b := User("wang", "1023")
error
一般是函数的第二个返回参数,第二个返回参数不为 nil 则表示有error。
func findUser(users []User, name string) (value *user, err error) {
for _, u := range users {
if u.name == name {
return &u, nil
}
}
return nil, errors.New("Not found")
}
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
// 与Python中的split()类似
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
fmt 常用的方法
// 输出一个或多个内容并换行
fmt.Println(s, ...)
// 格式化输出,%v可以识别任意的变量类型,%f针对浮点数类型
fmt.Printf("%v %.2f", a, b)
JSON 相关
需要注意的是,无论是 json 转成struct还是struct转成 json ,struct 中的成员变量都需要与 json 中的一一对应,如果结构过于复杂,可以借助一些工具实现。
// 成员变量需要首字符大写,如需要转成json后大写,需要在后面加上 `json:"age"`
type userInfo struct {
Name string
Age int `json:"age"`
Hobby []string
}
func main() {
a := userInfo{Name: "wang", Age: 18, Hobby: []string{"Golang", "TypeScript"}}
// 结构体转json
buf, err := json.Marshal(a)
fmt.Println(string(buf)) // {"Name":"wang","age":18,"Hobby":["Golang","TypeScript"]}
//格式化输出
buf, err = json.MarshalIndent(a, "", "\t")
fmt.Println(string(buf))
var b userInfo
// json转结构体
err = json.Unmarshal(buf, &b)
fmt.Printf("%#v\n", b) // main.userInfo{Name:"wang", Age:18, Hobby:[]string{"Golang", "TypeScript"}}
}
时间
// 获取当前时间
now := time.Now()
// 生成时间
t := time.Date(2022, 3, 27, 1, 25, 36, 0, time.UTC)
// 从时间变量单独获取年月日等
fmt.Println(t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute())
// 获取时间差
diff := now.sub(t)
// 获取时间戳
now.Unix()
字符串转数字
// 字符串转浮点数,64为字节大小,可以不用变
strconv.ParseFloat(string, 64)
// 字符串转整数,base为进制,base为0可自动识别进制
strconv.ParseInt(string, base, 64)
// 字符串自动转为数字
strconv.Atoi(string)
OS
// 执行os命令,并获取输出流
buf, err := exec.Command("grep", "127.0.0.1", "/etc/hosts").CombinedOutput()
fmt.Println(string(buf)) // 127.0.0.1 localhost
个人总结
Go语言的很多语法跟C++语言和Python语言的语法类似,所以接受起来很快。我认为从C++语法的角度来看,需要额外注意的有几点:
- switch语句,每一个case后面还可以放置条件表达式,有些情况下比if-else更加灵活;
- 尽量的多使用slice,而不是数组,因为我认为slice是不定长数组,会更加灵活;
- 需要遍历slice时,可以考虑使用for和range组合,会很方便;
- 函数可以有两个返回值,第二个返回值一般用err表示。
除了以上提到的这些,剩下的内容,需要多写写代码进行熟悉,和C++内的相关用法类似。