今天在看fabric源码的时候发现go的一些语法不是很懂,就看了一遍他的语法规则,然后总结一下,我就写一写相比其他语言,像Java多出的特点
go 是Google的一门开源编程语言,全称叫golang,2007年末由Robert Griesemer, Rob Pike, Ken Thompson主持开发,后来还加入了Ian Lance Taylor, Russ Cox等人,并最终于2009年11月开源,在2012年早些时候发布了Go 1稳定版本。go语言我觉得非常的好用来做现在的区块链,因为区块链没有像做其他那样许多小细节要通过运算符的控制,做一个很漂亮的界面,只要实现一些大的板块和逻辑实现,非常的简洁,还有就是第三方包很好使用,还加入其他一些元素来增加他的使用,不多说,完整的整理一遍那些属于go的特色
我现在用的是window10 ,环境配置非常简单,直接就不用配置了,只要到官网去下载
安装包下载地址为:https://golang.org/dl/。
如果打不开可以使用这个地址:https://golang.google.cn/dl/
(在下载列表中可以找到该文件,如go1.4.2.windows-amd64.msi)的安装包来安装,下载安装就可以了,path环境变量直接就不用配置了,再次说明,不用去看了,安好看看能不能在控制台输出hello Word,可以就说明安装好了go语言
Go 语言的基础组成有以下几个部分:
- 包声明 :package package_name
- 引入包 :import { "全路径"github.com/hyperledger/fabric/bccsp"相对路径都可以啦" fmt"""}
- 函数 :func 函数名(参数,,) 函数返回值数据类型,,{ 语句块 }
- 变量 : var 变量名 变量数据类型
- 语句 & 表达式
- 注释 : // 单行注释 /* */多行注释
如:package main import "fmt" func main() { /* 这是我的第一个简单的程序 */ fmt.Println("Hello, World!") }
我就用最简洁的方式说一下go的基础语法吧
每一行是一条语句,多条语句用;分开,只有一条就不用了
每打完一个符号、标识符、关键字后敲一下空格,这样看起来可读性比较好
语言是从右开始读的,这样会和国外的比较接近一点,也不会感觉老是怪怪的,吧结果放前面,像修饰符,数据类型放后
标识符我叫名字不知你理不理解,标识符是用来标识值的地址的,命名规范一样,字母、数字、下划线,开头不可以是数字
下面列举了 Go 代码中会使用到的 25 个关键字或保留字:
break | default | func | interface | select |
case | defer | go | map | struct |
chan | else | goto | package | switch |
const | fallthrough | if | range | type |
continue | for | import | return | var |
除了以上介绍的这些关键字,Go 语言还有 36 个预定义标识符:
append | bool | byte | cap | close | complex | complex64 | complex128 | uint16 |
copy | false | float32 | float64 | imag | int | int8 | int16 | uint32 |
int32 | int64 | iota | len | make | new | nil | panic | uint64 |
println | real | recover | string | true | uint | uint8 | uintptr |
数据类型就是告诉计算机一个变量要存哪,要多少的内存,不同的数据类型占用的内存空间不同
基本数据类型:
int/uint 8、16、32、68 float/complex 32 、64 string 、 byte 、uintptr (存放指针)、 rune (类似uint32ying)
引用类型:
指针类型(Pointer) 数组类型 结构化类型(struct) Channel 类型 函数类型 切片类型 接口类型(interface)Map 类型
变量声明
第一种,指定变量类型,声明后若不赋值,使用默认值。
var v_name v_type //可以使用逗号来隔开,同是定义多个数据类型相同的变量
第二种,根据值自行判定变量类型。
v_name = value //编译器根据值自行判断类型
第三种,省略var, 注意 :=左侧的变量不应该是已经声明过的,否则会导致编译错误。
v_name := value //这种定义变量的方法只可以在函数里面来定义,不可以用在全局变量时使用这种形式的定义
在运行时不会被改变的量
常量的定义格式:
const identifier [type] = value
在go的常量中有个特殊的常量是可以改变常量的值的参数 iota ,使用iota参数常量会曾1,如
package main
import "fmt"
func main() {
const (
a = iota //0
b //1
c //2
d = "ha" //独立值,iota += 1
e //"ha" iota += 1
f = 100 //iota +=1
g //100 iota +=1
h = iota //7,恢复计数
i //8
)
fmt.Println(a,b,c,d,e,f,g,h,i)
}
运行的结果是:
0 1 2 ha ha 100 100 7 8
- 算术运算符 :+ 、-、*、/、%、++、--
- 关系运算符 :>、<、>=、<=、==、!=、
- 逻辑运算符 :&&、||、!
- 位运算符 : &、|、^
- 赋值运算符 : +=、-= 、*=、/=、%=、》=、《=、&=、!=、^=
- 其他运算符 :
下表列出了Go语言的其他运算符。
运算符 描述 实例 & 返回变量存储地址 &a; 将给出变量的实际地址。 * 指针变量。 *a; 是一个指针变量
Go 语言提供了以下几种条件判断语句:
语句 | 描述 |
---|---|
if 语句 | if 语句 由一个布尔表达式后紧跟一个或多个语句组成。 |
if...else 语句 | if 语句 后可以使用可选的 else 语句, else 语句中的表达式在布尔表达式为 false 时执行。 |
if 嵌套语句 | 你可以在 if 或 else if 语句中嵌入一个或多个 if 或 else if 语句。 |
switch 语句 | switch 语句用于基于不同条件执行不同动作。 |
select 语句 | select 语句类似于 switch 语句,但是select会随机执行一个可运行的case。如果没有case可运行,它将阻塞,直到有case可运行。 |
for 循环,和基本的循环是一样的,处置-条件-循环体-增量-条件-循环体
可以不用这这种,条件就有一个就可以了,如条件就一个true就构成了无限循环了,嵌套循环也是可以的啦
对于三种条件循环控制语句 ;
break: 用于跳出当前循环,执行循环之后的语句
continue: 用于跳出循环继续判断,不在执行continue之后的循环体
goto: 跳转语句,直接跳到制定的标识符去从哪里又重新开始执行,我记得在c++里面也是有这条语句的,但是尽量少用,会破坏程序的结构,不知道为什么go又要使用这个,有待深入
Go 语言函数定义格式如下:
func function_name( [parameter list] ) [return_types] {//多个变量和返回值时使用括号括起来
函数体
}
这里的参数叫做形参,在调用函数的时候有两种方法,值传递和引用传递,值传递给的是具体的值,传参之后不改变实参的值,引用传递传递的是值的地址,传递之后实参的值改变
函数除了正常的返回值之外,go多了一个闭包,闭包函数的意思就是没有按照定义函数的方法去定义一个函数,而上在另外一个函数中来作为函数的返回值,返回的是一个函数,这个函数就是我么的闭包函数,内联在一个函数里面
作用域就是我们定义的标识符标识的变量、常量、函数在程序中的作用范围
全局变量:在当前和当前之后的包中可以使用
局部变量:只在当前函数范围内可以使用
Go 语言数组声明需要指定元素类型及元素个数,语法格式如下:
var variable_name [SIZE] variable_type
可以定义二维、三维数组,和Java里面一样,可以使用数组下标来访问数据,下标从0开始,定义数组的时候要指明数字的长度
数组一旦定义之后就是固定的了,没法改变,但是万一要是我们想要改变数组的长度呢
在go里面提供了分片机制来实现动态数组的功能:具体的看后面
一个指针变量指向了一个值的内存地址。
类似于变量和常量,在使用指针前你需要声明指针。指针声明格式如下:
var var_name *var-type
这里的指针可以是空指针,用nil 来表示和null一样,空指针说明虽然定义了但是没有使用它
切片之前就有提到,在数组哪里,就是对数组长度固定的一种扩充,可以改变数组的长度,例如可以在一个长度固定的数组里面加上一个或多个元素,使用内置append() 函数就可以向指定位置添加元素了,也可以访问多个连续数组里面的内容,如使用数组名[lower-bound:upper-bound]来访问数组的内容,下面看一下定义切片的语法:
你可以声明一个未指定大小的数组来定义切片:
var identifier []type
切片不需要说明长度。
或使用make()函数来创建切片:
var slice1 []type = make([]type, len)
也可以简写为
slice1 := make([]type, len)
go中的range用来将集合中的元素依次取出来复值或其他的,用在for循环中,对集合数组(array)、切片(slice)、通道(channel)或集合(map)的元素,还可以数组和切片中还可以返回集合中值对应的索引值
nums := []int{2, 3, 4}
sum := 0
for _, num := range nums {
sum += num
}
fmt.Println("sum:", sum)
//在数组上使用range将传入index和值两个变量。上面那个例子我们不需要使用该元素的序号,所以我们使用空白符"_"省略了。有时侯我们确实需要知道它的索引。
map是一个键值集合key-value,key唯一,value可以重复,一个key对应唯一一个value,通过map-name[key]就可以查询到相应的值,map的定义格式为:
可以使用内建函数 make 也可以使用 map 关键字来定义 Map:
/* 声明变量,默认 map 是 nil */
var map_variable map[key_data_type]value_data_type
/* 使用 make 函数 */
map_variable := make(map[key_data_type]value_data_type)
递归函数就是,在一个函数里面在调用相同的函数,来达到不同的目的,最好的例子就是计算阶乘就是一个递归函数调用最好的例子
将另外一种数据类型转换成我们想要的数据类型,转换格式为
type_name(变量)
我们使用结构体将不同类型的数据放在一起,比如,我们定义了一个书的结构体,我们想要书的作者是字符型的,价格是数字型的,书名是字符型的,
type Books struct {//使用type关键字
title string
author string
subjec string
book_id int
}
//给结构体赋值
Books{"Go 语言", "www.runoob.com", "Go 语言教程", 6495407}
接口只是定义了一套方法,但是没有具体的实现,需要实现接口才能具体的实现某种方法,接口的定义方法如下:
/* 定义接口 */
type interface_name interface {
method_name1 [return_type]
method_name2 [return_type]
method_name3 [return_type]
...
method_namen [return_type]
}
/* 实现接口方法 */
func (struct_name_variable struct_name) method_name1() [return_type] {
/* 方法实现 */
go已经将错误处理的方法定义成接口了,使用就实现就好了,错误处理尤其在test是使用的较多
test.go....
一般我们使用一门语言来实现具体的运用,都是用相应的编辑器,也叫IDE,编辑go使用
LiteIDE 是一款开源、跨平台的轻量级 Go 语言集成开发环境(IDE)。
支持的 操作系统
- Windows x86 (32-bit or 64-bit)
- Linux x86 (32-bit or 64-bit)
下载地址 :http://sourceforge.net/projects/liteide/files/
源码地址 :https://github.com/visualfc/liteide
当然如果你之前使用Java习惯了eclipse的画也可以在里面下载插件来编辑咯,具体怎么使用百度就欧克了
好吧,就到这吧,占时,等我看几天fabric看看可不可以讲清楚,我也可以加深理解的记忆