0.基本语法结构
package main
import "fmt"
func main(){
fmt.Println("Hello World")
}
- 声明包
- 保留了大括号,但去掉了分号
- 和python有点像,但没有强制锁进
- 首字母大写表示public,小写表示private
- 和类c语言相似,都是从main函数开始执行
1、 变量
变量的声明和初始化
go语言的变量声明需要使用var
一下,或者使用海象运算符
var x int =1 //长声明
var y,z int =1024,2048 //多重声明
p:=3 //海象运算符,短声明
//如果没有初始化,用默认值代替
const Pi=3.14 //常量,变量不可更改。声明常量需要关键字const,禁止使用海象运算符
变量类型
go是强类型语言,对于数值类型的定义域和符号分的很清,除了所有语言都有的数字类型、字符串、数组外,还有一些go独有的派生类型。
整数类型:int,int8,int32,int64,带符号和不带符号
浮点类型:Float32—单精度浮点值,Float64—双精度浮点值
布尔类型:true,false
字符串类型:string
数组类型:array
指针类型:pointer
管道类型:chan
接口类型:interface
常量
const PI =3.1415926
2 、运算符
//算术运算符
x,y :=1,2
res:=x+y //加法
res:=x-y //减法
res:=x/y //除法,取整
res:=x%y //模,取余数
res+=x //赋值运算符,类似的*=,%=
//关系运算符
res:=x==y
res:=x!=y
res:=x>y
res:=x0&&y>=0 //与门
res:=x>0||y>0 //或门
res:=!(x>y)//非门
3、 逻辑结构
判断
//判断语句
x:=1
if x>0{
//... ...
}else{
//... ...
}
循环
//for循环
for x:=1;x<10;x++{
//...
}
// 省略初始化和迭代loop
x:=1
for x<10{
//...
x++
}
switch
//switch,注意go中没有break语句,遇到第一个匹配的case就会跳出判断,不会穿透
x:=1
switch x{
case 1:
//...
case 2:
//...
case 3:
//...
default:
//...
}
4、函数
函数结构
关键字、函数名、函数体、输入参数,返回值
//基本结构,关键字、函数名、函数体、形参、返回值
func FunName(v int) string{
return st
}
//多个参数的输入和输出
func FunName(v1 int ,v2 int)(int,string){
return 2,"2"
}
可变参数
// 例子:求n个整数的和
func sum(x ...int) (s int) {
//可变参数
for _, v := range x {
s += v
}
return
}
// 也可以直接把切片扔进去作为可变参数
arr=[3]int{1,2,3}
sum(arr...) //类似于解包的操作
闭包于匿名函数
闭包给了在内部函数捕获外部函数参数的权利,匿名函数是闭包的实现方式之一,字面意思上的没有名字,直接调用的函数。
// 函数的闭包
func test14(a int, b int) int {
func() {
fmt.Println(a, b)
}()
return a + b
}
5、指针
指针,即一个值的内存地址。在go中,&
表示取地址,*
表示取值。
指针声明
var p1 *int
var p2 *string
// go中指针必须带类型
6、结构体
定义数据使用,类似于其他面向对象语言中的class
type Contact struct{
Age int
Name string
}
结构体与指针
x:=&Contact{"ronron",12}
x.name="xiaojiji"
7、方法
结构体除了声明了属性外,还能定义方法,方法即带接收器的函数。
type Contact struct{
Name string
Age int
}
// 方法,结构体接收器
func (c Constact) addAge1(){
c.Age+=1
}
// 方法,结构体指针接收器
func (c *Contact) addAge2(){
c.Age+=1
}
与普通函数相比,方法多了一个接收器,这个接收器可以是结构体,也可以是结构体指针。如果是结构体,那么传递的是结构体副本,修改不会影响原有的对象。如果是结构体指针,那么会影响原有的对象。
8、数组 Array
var a [3]int //定义一个长度为3的空数组
var a [3]int{1,2,3} //定义一个长度为3的数组并初始化
//数组的操作
// 索引
a[1]
数组一旦定义就无法修改大小,不方便使用,所以常用切片 slice代替
//切片定义方式一,直接从数组中切下来
a :=[5]int{1,2,3,4,5}
b:=a[1,3]
//切片定义方式二 ,使用make方法
c:=make([]int,5,10) //注意初始化长度为5,元素默认为0
//切片的遍历,和python真的相似
for i := 0; i < len(a); i++ {
fmt.Println(a[i])
}
for _, v := range a {
fmt.Println(v)
}
切片
go语言中的数组一旦定义就不能再改变长度,不大好用。切片是数组的高一级别的抽象,可以理解为动态数组。
// 定义一个字符串的切片,初始长度为10,容量为20
s:=make([]string 10,20)
// 切片的索引,与python相似
s[1:3]
//
9、字典Map
//直接定义和初始化map
m := map[string]int{
"a": 1,
"b": 2,
}
// 使用make进行初始化
m :=make(map[string]int)
// 添加元素
m["c"]=1024
//获取value
value,ok:=m["c"]
value,ok:=m["d"]
if ok{
}else{
}
//遍历map
for k, v := range m {
fmt.Println(k, v)
}
//删除dict元素
delete(m,"a")
10、并发
并发是go语言提供的核心语法,相比其他语言多线程的方式,使用简单,效率更高,管理便捷。
go例程中最核心的概念是goroutine和chan
goroutine
// 任务1
func A(){
//do some thing a
}
//任务2
func B(){
// do some thing b
}
//关键字go 直接使用例程,类似于其他语言中开辟一个新的线程
func main(){
go A() //处理任务A
go B() //处理任务B
}
channel
Channel用于多个goroutine 之间进行通信,<-
符合指示数据的流动方向
// 创建一个channel
ch:=make(chan int)
// 向chan中发射数据
ch <- 1
// 从chan中接受一个数据
value := <-chan
// 不用变量接收也可以
<- chan
11 错误处理
go中没有exception的概念,取而代之的是error,error在go中是一个接口
type error interface {
Error() string //只要实现了这个方法,就算error
}
go中把‘异常’当中一个值来处理,所以并没有try catch的语法,而是通过判断error是否为nill来进行异常处理。
// 内部error的处理
func ErrorTest(a, b int) (int, error) {
if b == 0 {
return 0, errors.New("b can not be zero")
}
return a / b, nil
}
// 调用
v,error:=ErrorTest(1,0)
if error !=nill{
// 处理有错误的情况
return
}
//...正常的处理
Panic和recove
panic用于手动抛出致命异常,直接宕机,程序线程停止。
recover 获取宕机时的信息,配合defer关键字,让程序在宕机后能继续从断点处开始运行。