01 Go语言基础语法 | 青训营

96 阅读7分钟

语言特性

  • 高性能、高并发
  • 语法简单,学习曲线平缓
  • 有丰富的标准库
  • 有完善的工具链
  • 支持静态链接
  • 支持快速编译
  • 跨平台支持
  • 支持垃圾回收

以下是一个基于Go语言的http服务器实例:

package main  
  
import "net/http"  
  
func main() {  
	http.Handle("/", http.FileServer(http.Dir(".")))  
	http.ListenAndServe(":8080", nil)  
}

基本结构

  • 包声明:package main
  • 引入包:import "fmt"
  • 函数:func main
  • 变量:var i int
  • 语句&表达式:fmt.Println(i)
  • 注释:/*这是一个简单的程序*/

语法

行分隔符

Go程序中,每一行代表一个语句的结束,类似Python;如果要将多个语句写在同一行,则两条语句之间需要用分号隔开。

e.g:

fmt.Println("HHW")
fmt.Println("runoob")

注释

// 单行注释
/*
 Author by 菜鸟教程
 我是多行注释
 */

标识符

禁止的标识符类型:

  • 数字开头
  • Go语言的关键字
  • 不能携带运算符

字符串

连接

通过+实现。

e.g:

package main
import "fmt"
func main() {
    fmt.Println("Google" + "Runoob")
}

输出结果:

GoogleRunoob

格式化

Go语言使用fmt.Printffmt.Sprintf格式化字符串并赋值给新串。

  • Sprintf 根据格式化参数生成格式化的字符串并返回该字符串。
  • Printf 根据格式化参数生成格式化的字符串并写入标准输出。

Sprintf实例:

package main

import (
    "fmt"
)

func main() {
   // %d 表示整型数字,%s 表示字符串
    var stockcode=123
    var enddate="2020-12-31"
    var url="Code=%d&endDate=%s"
    var target_url=fmt.Sprintf(url,stockcode,enddate)
    fmt.Println(target_url)
}

输出结果:

Code=123&endDate=2020-12-31

Printf实例:

package main

import (
    "fmt"
)

func main() {
   // %d 表示整型数字,%s 表示字符串
    var stockcode=123
    var enddate="2020-12-31"
    var url="Code=%d&endDate=%s"
    fmt.Printf(url,stockcode,enddate)
}

输出结果:

Code=123&endDate=2020-12-31

操作

具体的操作如下实例所示:

func main{
	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  
	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  
	b:="你好"  
	fmt.Println(len(b))//6 每个中文字符被记录为3个字符
}

解析字符串

使用"strconv"包进行解析。

关键字

Go语言常用的25个关键字/保留字如下:

breakdefaultfuncinterfaceselect
casedefergomapstruct
chanelsegotopackageswitch
constfallthroughifrangetype
continueforimportreturnvar

Go语言的36个预定义标识符如下:

appendboolbytecapclosecomplex
complex64complex128uint16copyfalsefloat32
float64imagintint8int16uint32
int32int64iotalenmakenew
nilpanicuint64printprintlnreal
recoverstringtrueuintuint8uintptr

关于空格的使用

Go 语言中变量的声明必须使用空格隔开。

变量

常量

Go语言中的常量const没有固定的类型,可以自动根据上下文来确定类型。

数组

Go语言中的数组是具有编号且长度固定的元素序列。创建方式:var 数组名 [数组大小] 数据类型

由于其长度固定,在日常使用中我们用的更多的是切片。

切片 (slice)

本质是可变长度的数组,可以随时更改其长度。

创建方式:切片名 := make([]数据类型, 初始长度)

可以使用append语句来追加元素。追加方式:原来的切片名 = append(原来的切片名, 新加的数据)

有类似于python的切片提取功能,用法示例:fmt.Println(数组名[要切片的范围])

可以使用copy语句实现数组的复制,用法:

s:=make([]string,3)
c:=make([]string,len(s))
copy(c,s)

逻辑语句

if else

Go语言中的if else语句格式如下:

package main

import "fmt"

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

注意: Go语言中if语句后面是不带括号的。

循环语句

Go语言中仅有for循环

以下是一个for循环的实例:

package main

import "fmt"

func main(){

	i:=1
	for{
		fmt.Println("loop")//不加break就是死循环
		break
	}

	for j:=7;j<9;j++{
		fmt.Println(j)
	}

	for n:=0;n<5;n++{
		if n%2==0 {
			continue
		}
		fmt.Println(n)
	}

	for i<=3{
		fmt.Println(i)
		i=i+1
	}
}

输出结果如下:

loop
7
8
1
3
1
2
3

分支语句

switch语句

Go语言中的switch语句有如下特点:

  • 大体上和C++类似
  • switch后面的语句不需要加括号
  • 每个case不需要添加break语句,执行完一个case会直接跳出分支语句
  • switch后可以使用任意的变量类型

以下是一个switch语句实例:

package main

import (
	"fmt"
	"time"
)

func main(){

	a:=2
	switch a{
	case 1:
		fmt.Println("one")
	case 2:
		fmt.Println("two")
	case 3:
		fmt.Println("three")
	default:
		fmt.Println("other")
	}

	t:=time.Now()
	switch {//switch后面可以不加判断,直接在case语句中进行判断
	case t.Hour()<12://可以直接在case后面加判断语句
		fmt.Println("It's before noon")
	default:
		fmt.Println("It's afternoon")
	}//整个的功能可以用于替换if else语句
}

map结构

实际使用过程中可能(?)是最频繁的数据结构。其他语言可能称之为哈希字典。私以为是建立了两个数据之间的联系。

以下是一个map的实例:

func main(){
	m:=make(map[string]int)//string是key的类型,int是value的类型
	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["two"])//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}//也可以用var语句,两者功能一致
	fmt.Println(m2,m3)//map[one:1 two:2] map[one:1 two:2]
}

range语句

可以用来快速遍历map结构。采用range后会返回两个值,第一个是索引,第二个是对应位置的值

以下是一个range的实例:

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语言的函数数据类型是后置的,函数原生支持返回多个值。一般情况下会返回两个结果:真正的结果 + 错误信息

指针

Go语言指针的操作相比C++非常有限,主要用途就是对常用的参数进行修改。

设定数据类型和参与运算时需要在数据类型前加上*,在输出结果时需要在变量名前加上&

结构体

相当于是将几个变量打包成一个变量组。

以下是一个结构体实例:

type user struct {
    name     string
    password string
}

func checkPassword(u user, password string) bool {
    return u.password == password
}

func checkPassword2(u *user, password string) bool {
    return u.password == password
}

func (u *user) resetPassword(password string){//类似于Java中的类成员函数
	u.password = password
}

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

	a.resetPassword("2048")//此处调用了结构体方法
}

错误处理

Go语言相比Java的异常处理,能够清晰的知道是哪个函数发出了错误信息。

通过在函数的返回值中添加一个error变量,从而获取到实际的错误信息。

JSON处理

对于一个已有的结构体,如果其变量名首字母均为大写,即可使用json.Marshal进行序列化操作,序列化后会变成一个buf数组。若要输出字符,需要使用string(buf)进行强制类型转换。也可以使用json.Unmarshal实现反序列化到一个空变量中。

时间的处理

最常用的是time.Now()获取当前时间,也可以使用time.Date(YYYY, MM, DD, HH, MM, SS, +x, time.timeReigon)来构造一个具有时区的时间。

获取时间段:time2.Sub(time1)语句。输出一个时间段,得到其时分秒值。

利用time.Format("2006-01-02 15:04:05")来格式化一个时间字符串;同样地,可以用time.Parse("2006-01-02 15:04:05", "2022-03-27 01:25:29")语句来解析一个时间字符串。

可以利用now.Unix()来获取一个时间戳。