Go 语言基础语法 | 青训营笔记

93 阅读4分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 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转成 jsonstruct 中的成员变量都需要与 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++语法的角度来看,需要额外注意的有几点:

  1. switch语句,每一个case后面还可以放置条件表达式,有些情况下比if-else更加灵活;
  2. 尽量的多使用slice,而不是数组,因为我认为slice是不定长数组,会更加灵活;
  3. 需要遍历slice时,可以考虑使用for和range组合,会很方便;
  4. 函数可以有两个返回值,第二个返回值一般用err表示。

除了以上提到的这些,剩下的内容,需要多写写代码进行熟悉,和C++内的相关用法类似。

引用参考