1、程序结构程序员
Go程序结构和C系程序(C/C++/JAVA等)一致,基本语句被组织成函数用于隔离和复用,函数组成源文件和包。Go程序存储在一个或多个.go文件中,每一个文件都已pakage开头,表面当前文件属于哪一个包;package语句后面是import语句,用于包含其余包以便于使用其余包中的元素;以后是包级别的类型、变量、常量、函数声明,声明不用区分先后顺序。编程
例:json
pakage main
import “fmt”
var name = “tony” func main(){ //函数、控制语句的前半大括号必须和函数名在同一行 fmt.Printf(“name = %s”,name) }
注意:变量声明区别于C的是类型后知,例如var name string;数组
特色:对比C,go有以下常见特色:多线程
1)、变量声明还能够经过返回值完成,例如name := getname(),称之为短声明;并发
2)、函数返回值能够有多个,例如ret1,ret2 = getret(),ret1和ret2将得到getret函数返回的两个参数;同时赋值表达式也能够多重赋值,如x,y=10,20 ;app
3)、赋值多了一种“:=”,这种用法用于定义一个类型是返回值类型的变量,同时该变量的值为返回值。是一种方便程序员的特性;编程语言
4)、新类型声明用type关键字;例如 type mytype string,那么mytype能够等价于string;函数
5)、包初始化时从包级别变量开始,这些变量按照声明顺序初始化,对于多个文件的包,初始化顺序是传给编译器的文件顺序,每一个包,甚至每一个文件均可以定义一个init函数,在里边能够自定义初始化一些内容,这个函数会在初始化阶段自动调用,且这个函数不是给用户调用的。优化
2、数据类型
go的数据类型包括基础类型、聚合类型、引用类型、接口类型四大类。
基础类型包括数字、字符串和布尔型;聚合类型有数组和结构体;引用类型包括slice、指针、map、函数、通道;接口类型即“接口”类型。
1)、基础类型使用上参考C系语言,差异不大,不过go对这些基础类型作了各类优化,好比内置复数类型、提供常量生成器、方便操做字符串等。
2)、数组和结构体长度都是固定的,slice和map的长度是能够动态增加的;
①、slice表示一个拥有相同元素的可变长序列,一般写做[]T ;slice有三个属性,指针、长度、容量,在长度变长的过程当中,容量会适时的增长以适应元素增长;len和cap用来返回slice的长度和容量;
②、map,即键值对类型,这种类型在平常开发者很经常使用,因此go内置了;map的类型是map[K]v ;map要求k必须是相同类型,V是相同类型,但K和V的类型能够不一样;而且要求K的值必须是能够经过==操做符来进行比较的数据类型,目的是能够检索某一个K是否已经存在。空map表示为map[k]v{} 。
③、结构体相似于C系语言的结构体;
④、go标准库支持操做json、xml等经常使用格式标记语言。
3、函数
go函数声明以下格式:
func name(para-list) (ret-list){ body }
常规操做相似于C系语言,因此再也不多加描述。
特性:延迟函数调用
用defer关键字后跟函数调用,这种格式的函数调用将会在当前函数执行流程结束后执行;不论是正常return仍是程序产生异常都会在最终调用defer语句;defer语句能够在须要的地方屡次调用,defer语句常常适用于成对操做中,如文件打开关闭,这时不管文件操做成功与否最后确定是要关闭文件的,因此这一特性是颇有用的。
resp.err := http.Get(url) if err != nil{ return err } defer resp.Body.Close()
4、方法
方法在本质上等同于函数,但它是对于面向对象编程而言的;go是一种支持大多数面向对象编程特性的编程语言,因此也存在继承、复用等。
方法声明和普通函数相比函数前面多了个参数,以下:
func (p class) name(para-list) (ret-list){ body }
多出的这个类参数意图是把当前函数绑定到这个参数对应的类型上。和C系语言不一样的是这个参数显示指定了特定类型实例p,而不是用隐性的this、self、that等;这样的好处是由用户本身选择当前方法的接收者p 。
以上的p也能够是指针类型,这样能够避免参数复制。
合法的方法调用仅如下三种状况:
//如下三种状况的 前置条件 func (p Point) Distance(q Point) float64 { body } func (p *Point) ScaleBy (q Point) float64 { body } var pptr *Point
1)、实参接收者和形参接收者类型相同,即同是T或*T
Point{1,2}.Distance(q) //Point
pptr.ScaleBy(q) //*Point
2)、实参接收者是T而形参接收者是*T,编译器会隐式获取地址;
p. ScaleBy(q) //
3)、实参接收者是*T而形参接收者是T,编译器会隐式转换。
pptr.Distance(q)
Notice: nil是个合法接收者
5、封装
go只有一种方式控制命名的可见性:定义的时候首字母大写的标识符是能够从包中导出的,小写的标识符只能在包中使用。
6、接口
接口类型是对其余类型行为的归纳和抽象。接口类型是一种抽象类型,它提供的仅仅是一些方法。举个例子:
type ControllerInterface interface { Init(ct *context.Context, controllerName, actionName string, app interface{}) Get() Post() Delete() Put() Head() Patch() Options() }
一个接口类型定义了一组方法,若是一个具体类型要实现这个接口,那么他必须实现接口类型中提供的全部方法。
若是一个类型实现了一个接口所要求的的全部方法,那么这个类型实现了这个接口;接口的赋值规则很简单,仅当一个表达式实现了一个接口时这个表达式才能赋值给该接口。
package io type Reader interface{ Read() } type ReadWriter interface{ Read() Write() } type Writer interface{ Write() }
依据以上前置条件如下赋值状况为:
var w io.Writer
w =os.Stdout //能够 *osFile 有write方法
w = time.Secound //不能够 未实现write方法
因此,接口能够当作普通变量看待,申请变量时它是nil,仅当赋值特定实现它要求的方法的类型后它将得到这个类型的具体方法,以后用这个变量完成特定的操做。
类型断言:
形如X.(T)的操做称之为类型断言,其中X是一个接口类型表达式,T是一个类型;类型断言会检查做为操做数的动态类型是否知足指定的断言类型;做用结果分为两种可能:
1)、T是一个具体类型,从它的操做数中把具体类型的值提取出来;
var w io.Writer
w = os.Stdout
f := w.(*os.File) // f = os.Stuout
2)、 T是一个接口类型,从一个接口类型向另外一个更宽松的接口类型转化(方法增多)
var w io.Writer
w = os.Stdout
rw := w.(io.ReadWriter) // 成功,rw将会变成包含Read和Write的接口
7、并发编程
go支持两种类型的并发编程风格,goroutine+channel风格(CSP)和共享内存多线程风格,go编程中第一种比较常见,由于使用很简单方便。
go里每个并发执行的活动称为goroutine;在函数调用或者表达式前加关键字go便可达成建立新的goroutine去执行表达式任务的目的;因此比起传统的多线程编程要简单得多。
固然程序执行的时候建立不少goroutine达成并发执行的目的了,但这些goroutine之间若是不能有效沟通那程序的功能将很大程度上受限,因此咱们须要这些goroutine之间通讯的机制,此处引入channel(通道)