go的语法
概述
有接触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程序,但是调调库啥的是没问题。
我们需要去读更多优秀的开源项目,汲取营养。
后续我会说明一些好用的库,也会阅读一些项目的源码
go的语法的更多相关文章
- 我的MYSQL学习心得(一) 简单语法
我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(四) 数据类型 我的MYSQL学习心得(五) 运 ...
- Swift与C#的基础语法比较
背景: 这两天不小心看了一下Swift的基础语法,感觉既然看了,还是写一下笔记,留个痕迹~ 总体而言,感觉Swift是一种前后端多种语言混合的产物~~~ 做为一名.NET阵营人士,少少多多总喜欢通过对 ...
- 探索C#之6.0语法糖剖析
阅读目录: 自动属性默认初始化 自动只读属性默认初始化 表达式为主体的函数 表达式为主体的属性(赋值) 静态类导入 Null条件运算符 字符串格式化 索引初始化 异常过滤器when catch和fin ...
- [C#] 回眸 C# 的前世今生 - 见证 C# 6.0 的新语法特性
回眸 C# 的前世今生 - 见证 C# 6.0 的新语法特性 序 目前最新的版本是 C# 7.0,VS 的最新版本为 Visual Studio 2017 RC,两者都尚未进入正式阶段.C# 6.0 ...
- Velocity初探小结--velocity使用语法详解
做java开发的朋友一般对JSP是比较熟悉的,大部分人第一次学习开发View层都是使用JSP来进行页面渲染的,我们都知道JSP是可以嵌入java代码的,在远古时代,java程序员甚至在一个jsp页面上 ...
- node.js学习(二)--Node.js控制台(REPL)&&Node.js的基础和语法
1.1.2 Node.js控制台(REPL) Node.js也有自己的虚拟的运行环境:REPL. 我们可以使用它来执行任何的Node.js或者javascript代码.还可以引入模块和使用文件系统. ...
- C#语法糖大汇总
首先需要声明的是"语法糖"这个词绝非贬义词,它可以给我带来方便,是一种便捷的写法,编译器会帮我们做转换:而且可以提高开发编码的效率,在性能上也不会带来损失.这让java开发人员羡慕 ...
- 值得注意的ibatis动态sql语法格式
一.Ibatis常用动态sql语法,简单粗暴用一例子 <select id="iBatisSelectList" parameterClass="java.util ...
- Flex 布局教程:语法篇
作者: 阮一峰 网页布局(layout)是CSS的一个重点应用. 布局的传统解决方案,基于盒状模型,依赖 display属性 + position属性 + float属性.它对于那些特殊布局非常不方便 ...
- postgresql 基本语法
postgresql数据库创建/修改/删除等写入类代码语法总结: 1,创建库 2,创建/删除表 2.1 创建表 create table myTableName 2.2 如果表不存在则创建表 crea ...
随机推荐
- idea 炫酷插件
1.插件的安装 打开setting文件选择Plugins选项 Ctrl + Alt + S File -> Setting 分别是安装JetBrains插件,第三方插件,本地已下载的插件包.详情 ...
- php 跨域问题 解决办法
php 跨域问题的解决主要有两步: 本人使用的是 windows下的 phpstudy的集成环境 1.修改服务器配置文件 在 apache 的配置文件 D:\phpStudy\Apache\con ...
- Linux 下的 Docker 安装与使用
一.安装与配置 1.安装依赖包 sudo yum install -y yum-utils device-mapper-persistent-data lvm2 2.设置阿里云镜像源 sudo yum ...
- PHP入门——基本巩固
----------一.变量 ----------二.运算 ----------三.控制结构 ----------四.函数 ----------六.字符串 ----------七.数组 ------- ...
- C# Func与Action
Func与Action是C#的内置委托,在使用委托时,可不必再定义. (1)Func:有返回类型的委托. Func类型的委托,肯定有一个返回类型,如果Func只有一个参数,那么它就是代表没有参数但是有 ...
- DataTable行列转换
#region DataTable行列转换 /// <summary> /// DataTable行列转换 /// </summary> /// <param name= ...
- 这就涉及到ABAQUS历史输出中各能量变量的意义
ABAQUS中,对于很多动态问题,尤其像高速冲击模拟中,对结果评价很重要的一点就是要保证模型能量守恒,这就涉及到ABAQUS历史输出中各能量变量的意义,下面最各简单整理: ALLAE:人工伪应变能,六 ...
- PHP通过身份证号码获取性别、出生日期、年龄等信息
$sex = substr($idcard, (strlen($idcard)==18 ? -2 : -1), 1) % 2 ? '1' : '2'; //18位身份证取性别,倒数第二位奇数是男,偶数 ...
- sql语句(已在Oracle中测试,之后有添加内容放在评论中)
1增 1.1[创建一张表] create table 表名(列名 类型); 例: ),性别 ),出生日期 date); ),sex ),出生日期 date); 1.2[插入单行]insert [int ...
- Virtualbox下克隆CentOS 网络配置
Virtualbox下克隆虚拟机非常容易,也使得我们在平常搭建测试环境方便了许多.不过克隆以后的虚机并不能够直接联网,这是由于网卡的MAC地址引起的.在"控制->复制"弹出的 ...