永远的Hello World
Hello world
1 | package main |
第一行代码 package main 定义了包名。你必须在源文件中非注释的第一行指明这个文件属于哪个包,如:package main。package main表示一个可独立执行的程序,每个 Go 应用程序都包含一个名为 main 的包。
main 函数是每一个可执行程序所必须包含的,一般来说都是在启动后第一个执行的函数(如果有 init() 函数则会先执行该函数)。
当标识符(包括常量、变量、类型、函数名、结构字段等等)以一个大写字母开头,如:Group1,那么使用这种形式的标识符的对象就可以被外部包的代码所使用(客户端程序需要先导入这个包),这被称为导出(像面向对象语言中的 public);标识符如果以小写字母开头,则对包外是不可见的,但是他们在整个包的内部是可见并且可用的
结构
Go使用package来组织,只要package名称为main的包可以包含main函数,一个可执行程序有且仅有一个main包。
1 | import "fmt" |
可以将导入的包起别名
1 | import fmt2 "fmt" |
省略调用,在调用其他包的方法的时候,不需要再先写其他的包名
1 | import . "fmt" |
其他一些用法
1 | package main |
Go语言中,使用大小写来决定该常量、变量、类型、接口、结构或函数是否可以被外部包所调用。函数名首字母小写即为 private ,函数名首字母大写即为 public 。
数据类型
- 布尔类型
1 | var flag bool=true; |
- 数字类型
整形:uint/int/byte
浮点型: float32/float64
复数型:complex
- 字符串
字符串中的字节使用UTF8编码标识Unicode文本。
Unicoder有2个字节形式、4个字节形式
UTF8是变长编码,英文1个字节,汉字3个字节,生僻的为4-6字节
- 派生类型
例如指针、数组、结构化、Channel、函数、切片、接口、Map
下面是一些变量赋值代码:
1 | /*全局变量声明*/ |
值类型:
所有像int、float、bool和string这些基本类型都属于值类型,使用这些类型的变量直接指向存在内存中的值,使用等号赋值的时候,实际上是在内存中将数值进行了拷贝。可以使用&i
获取变量i的内存地址
引用类型:
一个引用类型的变量r1存储的是r1值值所有的内存地址,或者内存地址中第一个字所在的位置,这个地址被称之为指针。
对于局部变量,仅仅声明不赋值不使用,以及仅仅声明赋值不进行使用都是不行的,会报错。局部变量必须使用。
声明的几种方法:var + type
,var
,:=
空白标识符_也用与抛弃值,,因为他是一个只读类型的变量。
数组
1 | var number = [6] int{1,2,3,5} |
常量
常量是一个简单值的标识符,在程序运行时,不会被修改的量。使用const进行标识
常量还可以用作枚举:
1 | const ( |
常量可以用len(), cap(), unsafe.Sizeof()函数计算表达式的值。其中unsafe.Sizeof
表示占用的内存字节数;例如a=12;fmt.Println(unsafe.Sizrof(a))
输出的就是8,因为a的类型为int8;对于一个字符串,unsafe.Sizeof
一直都是16字节,因为他是一个结构,其中8个字节指向了存储的空间,8个字节保存了这个字符串的长度。
iota
iota,特殊常量,可以认为是一个可以被编译器修改的常量。
在每一个const关键字出现时,被重置为0,然后再下一个const出现之前,每出现一次iota,其所代表的数字会自动增加1。
1 | const ( |
一些运算符
位运算运算符:
& 按位与,!按位或,^按位异或,<<左移运算(高位丢弃,低位补0),>>右移运算
channel
Channel是Go中的一个核心类型,你可以把它看成一个管道,通过它并发核心单元就可以发送或者接收数据进行通讯
channel包含三种形式定义,分别是双向管道,以及两个单向(单发送和单接受)
1 | chan T // 可以接收和发送类型为 T 的数据 |
条件语句
if语句,if else,wiitch,select
1 | if a<20{ |
循环语句
for循环的几种形式:
1 | /*和C语言的for循环一样*/ |
goto 语句可以无条件地转移到过程中指定的行。
1 | LOOP: for a < 20{ |
示例:打印小于100的素数
1 | func main() { |
函数
1 | func function_name( [parameter list] ) [return_types] {} |
实例:
1 | func max(num1,num2 int) int{ |
重写打印素数
1 | /*检查数值是否为素数*/ |
指针
1 | var a int= 20 /* 声明实际变量 */ |
指针数组:
数组中的每个元素都是指针:
1 | a := []int{10,100,200} |
指针作为参数
1 | func swap(x *int, y *int) { |
结构体
type对结构体进行命名
1 | type Books struct { |
使用指向结构体的指针,访问结构体内部元素
1 | var struct_pointer *Books |
切片
Go 数组的长度不可改变,在特定场景中这样的集合就不太适用,Go中提供了一种灵活,功能强悍的内置类型切片(“动态数组”),与数组相比切片的长度是不固定的,可以追加元素,在追加时可能使切片的容量增大。
1 | s :=[] int {1,2,3 } /*不设置数组长度,此时分片的初始len=cap=3*/ |
copy函数与append函数
1 | var numbers []int |
Range方法
1 | func main() { |
map
Map 是一种无序的键值对的集合。Map 最重要的一点是通过 key 来快速检索数据,key 类似于索引,指向数据的值。
Map 是一种集合,所以我们可以像迭代数组和切片那样迭代它。不过,Map 是无序的,我们无法决定它的返回顺序,这是因为 Map 是使用 hash 表来实现的。
1 | var countryCapitalMap map[string]string |
语言类型转换
1 | func main() { |
接口
1 | type Phone interface { |
在上面的例子中,我们定义了一个接口Phone,接口里面有一个方法call()。然后我们在main函数里面定义了一个Phone类型变量,并分别为之赋值为NokiaPhone和IPhone。然后调用call()方法
错误处理
Go 语言通过内置的错误接口提供了非常简单的错误处理机制。
error类型是一个接口类型,这是它的定义:
1 | type error interface { |
我们需要在相应的地方实现这个接口方法。
函数通常在最后的返回值中返回错误信息。使用errors.New 可返回一个错误信息
1 | func Sqrt(f float64) (float64, error) { |