go的语法

时间:2022-12-19 00:16:46

概述

有接触go语言,工作中用的比较少,偶尔做个小项目,最近看到的一个项目也从go迁移到java。

但是对go还是恋恋不忘,它语法比较简洁,库也比较多,编译速度快,等等优点,让我忘不了。

对go的语法做个简单的总结,内容主要来源官网的pdf,学习go语言

语法

安装和运行

安装go,上官网学学,我的系统是mac 直接brew安装

通过go build编译成二进制,然后直接运行,go提供了众多工具,说来惭愧用的比较少,build,test用的比较多吧

至于包管理以前用govender,现在有官方的mod

基础语法

支持各种类型:bool,int,float,double,complex,int32,byte,int64,string

注意go里面int和int32不是同一种类型,赋值需要转一次

go的变量定义比较奇怪,据说是方便编译器解析比如,定义一个变量

  var a int = 12或者是自动推导  a:=12

可以通过const xxx = aaa 定义常量

可以使用iota定义枚举,它会自增

也提供了丰富的string操作,这个是利器,其实程序员很大一部分工作都是在和字符串搏斗。

控制结构和python很像,又不同,没有while,都通过for提供能够,也支持goto和switch

switch里面不必要写break了,可以通过fallthrough进入下一个判断

语法的例子

var a int
var b bool
a = 1
b = true
fmt.Println(a, b) //多个变量赋值和丢弃
a,b = 2,true
a,_ = 12,false fmt.Println(const1, const2) //string
str1 := "hi world!"
csts := []rune(str1)
csts[0] = 'a'
str2 := string(csts)
fmt.Printf("str2=%s\n",str2) var comp complex64 = 5+5i;
fmt.Printf("val %v\n", comp) //var e error if a > 2{
fmt.Printf("> a=%d\n",a)
}else{
fmt.Printf("< a=%d\n",a)
} if err := os.Chmod("/data1/applogs",os.ModePerm); err != nil{ fmt.Println(err)
}else{
fmt.Println("chmod ok!")
} aFunc() for i:=0;i < 10;i++{
fmt.Print(i)
} //
list1 := []string{"a","b","c","d"}
for k,v := range list1{
fmt.Print(k,":",v)
}
var c byte = 'e'
switch {
case '0' <=c:
fmt.Println("aa")
fallthrough
case 'a' <= c:
fmt.Println("bb") }

    i :=
Here:
fmt.Print(i)
i++
if i < {
goto Here
}else{
return
}

go提供了几种基础类型 数组,slice列表 map字典 chan

除了chan用于管道通信,从效果上和其他语言没啥差别,语法有点不同,多用几次,熟练就好了

slice和map的例子

var arr1[]int
arr1[] =
fmt.Printf("%d",arr1[]) arr2 := []int{,,}
arr3 := [...]int{,,}
fmt.Println(arr2,arr3) arr4 := [][]int{{,},{,},{,}}
fmt.Println(arr4) //slice
slice1 := make([]int, )
fmt.Println(len(slice1),cap(slice1))
slice2 := arr2[:]
slice2[] =
fmt.Println(arr2)
slice2 = append(slice2,,,,,,)
fmt.Println(slice2)
slice3 := make([]int,)
n1:=copy(slice3,slice2)
fmt.Println(n1,slice3) //map
map1 := make(map[string]int)
map1["a0"] =
map1["a1"] =
map1["a2"] =
map1["a3"] =
fmt.Println(map1)
delete(map1,"a0")
fmt.Println(map1)

作用域的问题

  对于我这种新手来说go的作用域是最容易引起混乱的。因为参数可以随便传啊。一堆goroutine共享变量,很容易出错。

  注意全局变量和局部变量,也需注意 :=不仅仅是声明和创建,

函数

go的函数支持几个特别的特性,多个返回值,函数做参数,命名返回,变参,panic,recover

支持defer函数退出时执行,有点像try{}finally{}但是封装的更加方便,采用栈的方式去收集defer函数

panic 有点像java的exception ,没有捕获一层层往上抛出。结合defer和recover我们可以用来处理特殊情况

func testfunc(){
//打印
rec() //作用域
p()
fmt.Println(a1234)
//多值返回 //命名返回值
ret1,ret2 := p12()
fmt.Println(ret1, ret2) //延迟执行
readWrite()
//延迟的顺序
deferSeq() //变参
myFunc(,,,,)
//原样传递参数
myFunc2(,,,,)
//函数作为值
hello := func() {
fmt.Println("hello world")
}
hello()
//函数回调
aCallback(, func88)
//使用panic
bol := throwPanic(aPanic)
fmt.Println("bol:",bol) } func throwPanic(f func())(b bool){
defer func(){
if x:=recover(); x!= nil{
b = true
}
}()
f()
return false
} func aPanic(){
panic("throw a panic")
} func aCallback(y int, f func(int)){
f(y)
} func func88(i int) {
fmt.Printf("i=%d",i*i)
} func myFunc2(arg ...int){
myFunc(arg...)
} func myFunc(arg ...int) {
for _,n := range arg{
fmt.Printf("n=%d,",n)
}
} func deferSeq() {
for i:=; i < ;i++{
defer func(x int){
fmt.Printf("%d\t",x)
}(i)
}
} func readWrite() bool{
fp,err := os.Open("/data1/applogs/superfans/info-2019-01-02.log")
defer fp.Close()
if err != nil{
return false
} return true
} func p12()(a int,b int){
n :=
a =
b = n
return
} var a1234 int func p(){
a1234 :=
fmt.Println(a1234)
} func rec(i int){
if i == {
return
}
rec(i+)
fmt.Printf("%d ", i)
}

go里面没有private protected publice关键字,通过大小写去区分公用还是私有,

大写公用,小写属于包私有的

内存分配

make 只针对slice map chan,返回三种类型

new 任意类型,分配内存空间,返回指针

自定义类型

和c一样,使用struct作为自定义类型

go没有继承的概念,但是可以使用匿名字段

也支持方法,但是必须在函数名字前面加上类型,其实是把类型也作为参数传递给函数吧

go 有指针的概念,但是为了防止指针滥用,不支持指针的+和-

这是上面说明的例子

func testMoreFunc(){
//指针
var p *int
fmt.Printf("%v",p)
var i int
p = &i
fmt.Printf("%v",p)
*p =
fmt.Println("%v",i) //内存分配
//new 返回地址 make返回自建类型
psp := new (SynceBuffer)
var syncbufer SynceBuffer
fmt.Println("%v,%v",psp,&syncbufer)
//仅仅适用于 map,slice,channel
slice1:= make([]int, )
map1 := make(map[string]string)
chan1 := make(chan int,)
fmt.Println(len(slice1),len(map1),len(chan1)) //直接使用符合声明创建
syncbufer2 := &SynceBuffer{sync.Mutex{},bytes.Buffer{}}
fmt.Println("%v",syncbufer2) //自定义类型
testAge()
//结构体字段
aNull := struct{}{}
fmt.Printf("%v", aNull) //大写不可导出,小写可以导出
str1 := &Str1{name:"hehe"}
str1.T12 =
str1.showIt() //方法转换: 先找n, 再找&n
str11 := Str1{name:"hehe11"}
str11.showIt() //转换
convertStr() //迁入的方式实现组合 } func convertStr(){
//byte类型转换
mystr := "aba12"
byteslice := []byte(mystr)
runeSlice := []rune(mystr)
fmt.Printf("%v, %v",byteslice, runeSlice)
fmt.Printf("%v, %v",string(byteslice), string(runeSlice)) //自定义类型的转换
var t12 T12 = ;
var t13 int
t13 = int(t12) fmt.Printf("%v", t13) } type T12 int
type Str1 struct {
T12
name string
}
func (str1 *Str1) showIt(){
fmt.Printf("%v", str1)
} func testAge(){
a := new(NameAge)
a.name = "peter"
a.age =
fmt.Println("%v\n",a)
} type NameAge struct {
name string
age int
} type SynceBuffer struct{
lock sync.Mutex
buffer bytes.Buffer
}

接口

go的接口和python有点像,只要实现了某个方法你就可以实现转换

支持类型判断  xx.(type)

也支持反射reflect,提供两类方法,一类是获取字段的type,一类是获取字段的value

func testInterface(){
//测试接口
s1 := S1{}
//finter1(s1)//传递接口有问题,因为是*引用实现了接口
finter1(&s1);
//获取类型 .(type) //类型判断
gtype(&s1) //方法的定义只能是本地的 //接口名字,方法名+er //写代码时面向接口编程 //自省和反射
showTag(&Person{}) } func showTag(i interface{}){
t := reflect.TypeOf(i)
v := reflect.ValueOf(i)
fmt.Printf("%v,%v",t,v)
switch t.Kind() {
case reflect.Ptr:
tag := t.Elem().Field().Tag
fmt.Printf("tag:%s",tag)
default:
tag := t.Field().Tag
fmt.Printf("tag:%s",tag)
}
} type Person struct {
name string "namestr"
age int
} /*
func (i int) assf(){ }
*/ func gtype(som interface{})int{
return som.(I1).Get();
} func finter1(i1 I1){
switch t := i1.(type) {
case *S1:
fmt.Println("type is *s1")
default:
fmt.Println("%v",t)
}
fmt.Println(i1.Get())
i1.Put()
fmt.Println(i1.Get())
} type I1 interface {
Get()int
Put(int)
} type S1 struct {
i int
}
func(p *S1) Get() int {
return p.i;
}
func (p *S1)Put(v int){
p.i = v
}

通道

通道可以理解成管道,可以定义各种类型的通道,但是通道发送和接收必须成对出现,不然会报错

可以定义任意类型的通道

var a chan int ,  var b chan func(), var c chan struct{}

通道没有if判断,却可以使用select做选择

func tgoroutine(){
//torungoroutine()
torungoroutineChan()
} func torungoroutineChan(){
c := make(chan int,)
fmt.Println("i'm waitting") go readyNew("tom",,c)
go readyNew("tim",,c) i :=
L:for{
select{
case <-c:
i++
if i > {
break L
}
}
}
close(c) } func readyNew(w string, sec int, c chan int ){
time.Sleep(time.Duration(sec) * time.Second)
fmt.Println(w," is ready")
c <-
} func torungoroutine(){
go ready("tom",)
go ready("ted",)
fmt.Println("i'm waitting")
time.Sleep( * time.Second)
} func ready(w string, sec int){
time.Sleep(time.Duration(sec) * time.Second)
fmt.Println(w," is ready")
}

常用的包

参数获取,文件读取,命令行执行

func netFunc(){
r, err := http.Get("http://baidu.com")
if err != nil{
fmt.Printf("%v\n", err)
return
}else{
b, err := ioutil.ReadAll(r.Body)
r.Body.Close()
if err == nil{
fmt.Printf("%s", string(b))
}
}
} func cmdCommon(){ cmd := exec.Command("/bin/ls","-l")
buf,err := cmd.Output()
if err != nil{
fmt.Printf("err %v\n",err)
}else{
fmt.Printf("buf:%s\n",string(buf))
} } func flagParse(){
b := flag.Bool("b",false, "a bool")
port := flag.String("port","","set port")
flag.Usage =func(){
fmt.Fprintf(os.Stderr,"%s",os.Args[])
flag.PrintDefaults()
}
flag.Parse()
fmt.Printf("%v,%v",*b,*port)
} func dirOpt(){
//文件操作
fineName := "/data1test/"
if f,e := os.Stat(fineName);e != nil{
os.Mkdir(fineName,)
}else{
fmt.Printf("%v",f)
}
} func aBufOutput(){
buf := make([]byte, )
f,_ := os.Open("/data1test/info-2019-01-02.log")
defer f.Close()
r := bufio.NewReader(f)
w := bufio.NewWriter(os.Stdout)
defer w.Flush()
for{
n,_ := r.Read(buf)
if n == {
break
}
os.Stdout.Write(buf[:n])
} } func noBufOutput(){
buf := make([]byte, )
f,_ := os.Open("/data1test/info-2019-01-02.log")
defer f.Close()
for{
n,_ := f.Read(buf)
if n == {
break
}
os.Stdout.Write(buf[:n])
} }

总结

  go的语法告一段落,但是如果仅仅只了解这些还不足以写一个好的golang程序,但是调调库啥的是没问题。

  我们需要去读更多优秀的开源项目,汲取营养。

  后续我会说明一些好用的库,也会阅读一些项目的源码