1. 小案例:
package main 定义了包名
import "fmt" 告诉 Go 编译器这个程序需要使用 fmt 包
func main() { 程序开始执行的函数
/* 这是我的第一个简单的程序 */
fmt.Println("Hello, World!")} 字符串输出到控制台
go语言数据类型:
- 布尔型: var b bool = true。
- 数据类型: 整数型 int ; 浮点类型: float
- 字符串类型:String
(a) 指针类型(Pointer)
- (b) 数组类型
- (c) 结构化类型(struct)
- (d) Channel 类型
- (e) 函数类型
- (f) 切片类型
- (g) 接口类型(interface)
- (h) Map 类型
变量声明:
Var a int = 10 ;第一种
a :=10 ; 省略var, 注意 :=左侧的变量不应该是已经声明过的,否则会导致编译错误。
多变量声明:
//类型相同多个变量, 非全局变量var vname1, vname2, vname3 type
vname1, vname2, vname3 = v1, v2, v3
var vname1, vname2, vname3 = v1, v2, v3 //和python很像,不需要显示声明类型,自动推断
vname1, vname2, vname3 := v1, v2, v3 //出现在:=左侧的变量不应该是已经被声明过的,否则会导致编译错误
var (
vname1 v_type1
vname2 v_type2 )// 这种因式分解关键字的写法一般用于声明全局变量
注意事项:
如果在相同的代码块中,我们不可以再次对于相同名称的变量使用初始化声明,例如:a := 20 就是不被允许的,编译器会提示错误 no new variables on left side of :=,但是 a = 20 是可以的,因为这是给相同的变量赋予一个新的值。
你可以省略类型说明符 [type],因为编译器可以根据变量的值来推断其类型。
- 显式类型定义: const b string = "abc"
- 隐式类型定义: const b = "abc"
多个相同类型的声明:
const c_name1, c_name2 = value1, value2 //const关键字 修饰的数据类型是指常类型,常类型的变量或对象的值是不能被更新的
常量可以用len()字符串长度, cap()数组长度, unsafe.Sizeof()字节长度 函数计算表达式的值
iota,特殊常量,可以认为是一个可以被编译器修改的常量。
在每一个const关键字出现时,被重置为0,然后再下一个const出现之前,每出现一次iota,其所代表的数字会自动增加1。
iota 可以被用作枚举值:
const (
a = iota
b = iota
c = iota)
第一个 iota 等于 0,每当 iota 在新的一行被使用时,它的值都会自动加 1;所以 a=0, b=1, c=2 可以简写为如下形式:
例子1:const (
a = iota
b
c)
例子2:
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
)
算术运算符:
下表列出了所有Go语言的算术运算符。假定 A 值为 10,B 值为 20。
+ |
相加 |
A + B 输出结果 30 |
- |
相减 |
A - B 输出结果 -10 |
* |
相乘 |
A * B 输出结果 200 |
/ |
相除 |
B / A 输出结果 2 |
% |
求余 |
B % A 输出结果 0 |
++ |
自增 |
A++ 输出结果 11 |
-- |
自减 |
A-- 输出结果 9 |
关系运算符:
假定 A 值为 10,B 值为 20。
== |
检查两个值是否相等,如果相等返回 True 否则返回 False。 |
(A == B) 为 False |
!= |
检查两个值是否不相等,如果不相等返回 True 否则返回 False。 |
(A != B) 为 True |
> |
检查左边值是否大于右边值,如果是返回 True 否则返回 False。 |
(A > B) 为 False |
< |
检查左边值是否小于右边值,如果是返回 True 否则返回 False。 |
(A < B) 为 True |
>= |
检查左边值是否大于等于右边值,如果是返回 True 否则返回 False。 |
(A >= B) 为 False |
<= |
检查左边值是否小于等于右边值,如果是返回 True 否则返回 False。 |
|
逻辑运算符:
假定 A 值为 True,B 值为 False
&& |
逻辑 AND 运算符。 如果两边的操作数都是 True,则条件 True,否则为 False。 |
(A && B) 为 False |
|| |
逻辑 OR 运算符。 如果两边的操作数有一个 True,则条件 True,否则为 False。 |
(A || B) 为 True |
! |
逻辑 NOT 运算符。 如果条件为 True,则逻辑 NOT 条件 False,否则为 True。 |
!(A && B) 为 True |
赋值运算符
= |
简单的赋值运算符,将一个表达式的值赋给一个左值 |
C = A + B 将 A + B 表达式结果赋值给 C |
+= |
相加后再赋值 |
C += A 等于 C = C + A |
-= |
相减后再赋值 |
C -= A 等于 C = C - A |
*= |
相乘后再赋值 |
C *= A 等于 C = C * A |
/= |
相除后再赋值 |
C /= A 等于 C = C / A |
%= |
求余后再赋值 |
C %= A 等于 C = C % A |
<<= |
左移后赋值 |
C <<= 2 等于 C = C << 2 |
>>= |
右移后赋值 |
C >>= 2 等于 C = C >> 2 |
&= |
按位与后赋值 |
C &= 2 等于 C = C & 2 |
^= |
按位异或后赋值 |
C ^= 2 等于 C = C ^ 2 |
|= |
按位或后赋值 |
C |= 2 等于 C = C | 2 |
语言条件语句:
if 语句 由一个布尔表达式后紧跟一个或多个语句组成。 |
|
if 语句 后可以使用可选的 else 语句, else 语句中的表达式在布尔表达式为 false 时执行。 |
|
你可以在 if 或 else if 语句中嵌入一个或多个 if 或 else if 语句。 |
|
switch 语句用于基于不同条件执行不同动作。 |
|
select 语句类似于 switch 语句,但是select会随机执行一个可运行的case。如果没有case可运行,它将阻塞,直到有case可运行。 |
循环语句:
重复执行语句块 |
|
在 for 循环中嵌套一个或多个 for 循环 |
循环控制语句:
经常用于中断当前 for 循环或跳出 switch 语句 |
|
跳过当前循环的剩余语句,然后继续进行下一轮循环。 |
|
将控制转移到被标记的语句。 |
|
|
|
无限循环: 通过 for 循环语句中只设置一个条件表达式来执行无限循环
package main
import "fmt"
func main() {
for true {
fmt.Printf("这是无限循环。\n");
}}
函数定义:
func function_name( [parameter list] (参数类型)) [return_types(返回值类型)] {
函数体
}
实例:
package main
import "fmt"
func main() {
/* 定义局部变量 */
var a int = 100
var b int = 200
var ret int
/* 调用函数并返回最大值 */
ret = max(a, b)
fmt.Printf( "最大值是 : %d\n", ret )}
/* 函数返回两个数的最大值 */
func max(num1, num2 int) int {
/* 定义局部变量 */
var result int
if (num1 > num2) {
result = num1
} else {
result = num2
}
return result }
注意: 在函数内码不能改变用来调用所述函数的参数。考虑函数swap()的定义
Go 函数 局部变量 与 全局变量:
局部变量:
在函数体内声明的变量称之为局部变量,它们的作用域只在函数体内,参数和返回值变量也是局部变量。
package main
import "fmt"
func main() {
/* 声明局部变量 */
var a, b, c int
/* 初始化参数 */
a = 10
b = 20
c = a + b
fmt.Printf ("结果: a = %d, b = %d and c = %d\n", a, b, c)}
全局变量
在函数体外声明的变量称之为全局变量,全局变量可以在整个包甚至外部包(被导出后)使用。
全局变量可以在任何函数中使用,以下实例演示了如何使用全局变量:
package main
import "fmt"
/* 声明全局变量 */
var g int
func main() {
/* 声明局部变量 */
var a, b int
/* 初始化参数 */
a = 10
b = 20
g = a + b
fmt.Printf("结果: a = %d, b = %d and g = %d\n", a, b, g)}
注意: Go 语言程序中全局变量与局部变量名称可以相同,但是函数内的局部变量会被优先考虑
Go 语言数组:
声明数组:
var variable_name [SIZE] variable_type
例子:
package main
import "fmt"
func main() {
var n [10]int /* n 是一个长度为 10 的数组 */
var i,j int
/* 为数组 n 初始化元素 */
for i = 0; i < 10; i++ {
n[i] = i + 100 /* 设置元素为 i + 100 */
}
/* 输出每个数组元素的值 */
for j = 0; j < 10; j++ {
fmt.Printf("Element[%d] = %d\n", j, n[j] )
}}
Go语言结构体:
例:
package main
import "fmt"
type Books struct {
title string
author string
subject string
book_id int}
func main() {
var Book1 Books /* 声明 Book1 为 Books 类型 */
var Book2 Books /* 声明 Book2 为 Books 类型 */
/* book 1 描述 */
Book1.title = "Go 语言"
Book1.author = "www.runoob.com"
Book1.subject = "Go 语言教程"
Book1.book_id = 6495407
/* book 2 描述 */
Book2.title = "Python 教程"
Book2.author = "www.runoob.com"
Book2.subject = "Python 语言教程"
Book2.book_id = 6495700
/* 打印 Book1 信息 */
fmt.Printf( "Book 1 title : %s\n", Book1.title)
fmt.Printf( "Book 1 author : %s\n", Book1.author)
fmt.Printf( "Book 1 subject : %s\n", Book1.subject)
fmt.Printf( "Book 1 book_id : %d\n", Book1.book_id)
/* 打印 Book2 信息 */
fmt.Printf( "Book 2 title : %s\n", Book2.title)
fmt.Printf( "Book 2 author : %s\n", Book2.author)
fmt.Printf( "Book 2 subject : %s\n", Book2.subject)
fmt.Printf( "Book 2 book_id : %d\n", Book2.book_id)
//第二种 结构体作为函数参术
func printBook( book Books ) {
fmt.Printf( "Book title : %s\n", book.title);
fmt.Printf( "Book author : %s\n", book.author);
fmt.Printf( "Book subject : %s\n", book.subject);
fmt.Printf( "Book book_id : %d\n", book.book_id);
}
Go语言切片:
go语言切片是数组的对象.
Go 数组的长度不可改变,在特定场景中这样的集合就不太适用,Go中提供了一种灵活,功能强悍的内置类型切片("动态数组"),与数组相比切片的长度是不固定的,可以追加元素,在追加时可能使切片的容量增大。
定义切片: var identifier []type
切片不需要长度
或者使用make() 函数来创建切片
var slice1 []type = make([]type, len)
也可以简写为
slice1 := make([]type, len)
例: slice2 := make([]int32, 9)
slice3 := []int32{}
len() 和 cap() 函数
切片是可索引的,并且可以由 len() 方法获取长度。
切片提供了计算容量的方法 cap() 可以测量切片最长可以达到多少。
注意:切片的零值为 nil 。对于切片的零值, len 和 cap 都将返回0。
追加使用append()方法 复制使用copy()方法.
实际的是获取数组的某一部分,len切片<=cap切片<=len数组,切片由三部分组成:指向底层数组的指针、len、cap。
Go语言范围:
Go语言中 range 关键字用于for循环迭代数组(array) 切片(slice) 通道(channel) 或者集合(map)的元素, 在数组和切片中返回元素的索引值,在集合中返回key-value 对的key值.
实例:
package mainimport "fmt"
func main() {
//这是我们使用range去求一个slice的和。使用数组跟这个很类似
nums := []int{2, 3, 4}
sum := 0
for _, num := range nums {
sum += num
}
fmt.Println("sum:", sum)
//在数组上使用range将传入index和值两个变量。上面那个例子我们不需要使用该元素的序号,所以我们使用空白符"_"省略了。有时侯我们确实需要知道它的索引。
for i, num := range nums {
if num == 3 {
fmt.Println("index:", i)
}
}
//range也可以用在map的键值对上。
kvs := map[string]string{"a": "apple", "b": "banana"}
for k, v := range kvs {
fmt.Printf("%s -> %s\n", k, v)
}
//range也可以用来枚举Unicode字符串。第一个参数是字符的索引,第二个是字符(Unicode的值)本身。
for i, c := range "go" {
fmt.Println(i, c)
}}
结果:
sum: 9
index: 1
a -> apple
b -> banana0 1031 111
Go语言Map:
Map 是一种无序的键值对的集合。Map 最重要的一点是通过 key 来快速检索数据,key 类似于索引,指向数据的值。 Map 是一种集合,所以我们可以像迭代数组和切片那样迭代它。不过,Map 是无序的,我们无法决定它的返回顺序,这是因为 Map 是使用 hash 表来实现的。
实例:
package main
import "fmt"
func main() {
var countryCapitalMap map[string]string
/* 创建集合 */
countryCapitalMap = make(map[string]string)
/* map 插入 key-value 对,各个国家对应的首都 */
countryCapitalMap["France"] = "Paris"
countryCapitalMap["Italy"] = "Rome"
countryCapitalMap["Japan"] = "Tokyo"
countryCapitalMap["India"] = "New Delhi"
/* 使用 key 输出 map 值 */
for country := range countryCapitalMap {
fmt.Println("Capital of",country,"is",countryCapitalMap[country])
}
/* 查看元素在集合中是否存在 */
captial, ok := countryCapitalMap["United States"]
/* 如果 ok 是 true, 则存在,否则不存在 */
if(ok){
fmt.Println("Capital of United States is", captial)
}else {
fmt.Println("Capital of United States is not present")
}}
Delete 函数: 闪出集合元素 ,参数为map和对应的key
例子:
package main
import "fmt
func main() {
/* 创建 map */
countryCapitalMap := map[string] string {"France":"Paris","Italy":"Rome","Japan":"Tokyo","India":"New Delhi"}
fmt.Println("原始 map")
/* 打印 map */
for country := range countryCapitalMap {
fmt.Println("Capital of",country,"is",countryCapitalMap[country])
}
/* 删除元素 */
delete(countryCapitalMap,"France");
fmt.Println("Entry for France is deleted")
fmt.Println("删除元素后 map")
/* 打印 map */
for country := range countryCapitalMap {
fmt.Println("Capital of",country,"is",countryCapitalMap[country])
}}
Go语言递归调用函数:
递归就是运行过程中调用自己.
例子:
阶乘:
package main
import "fmt"
func Factorial(n uint64)(result uint64) {
if (n > 0) {
result = n * Factorial(n-1)//递归
return result
}
return 1}
func main() {
var i int = 15
fmt.Printf("%d 的阶乘是 %d\n", i, Factorial(uint64(i)))}
菲波那切数列(兔子数列):
package main
import "fmt"
func fibonacci(n int) int {
if n < 2 {
return n
}
return fibonacci(n-2) + fibonacci(n-1)}
func main() {
var i int
for i = 0; i < 10; i++ {
fmt.Printf("%d\t", fibonacci(i))
}}
结果:
0 1 1 2 3 5 8 13 21 34
Go语言类型转化:
例: 将整数型转化为浮点类型;
package main
import "fmt"
func main() {
var sum int = 17
var count int = 5
var mean float32
mean = float32(sum)/float32(count)
fmt.Printf("mean 的值为: %f\n",mean)}
输出结果: 3.400000
Go语言接口:
实现接口中的方法就是实现了 这个接口.
Go 语言提供了另外一种数据类型即接口,它把所有的具有共性的方法定义在一起,任何其他类型只要实现了这些方法就是实现了这个接口
实例:
/* 定义接口 */
type interface_name interface {
method_name1 [return_type]
method_name2 [return_type]
method_name3 [return_type]
...
method_namen [return_type]}
/* 定义结构体 */
type struct_name struct {
/* variables */}
/* 实现接口方法 */
func (struct_name_variable struct_name) method_name1() [return_type] {
/* 方法实现 */}...
func (struct_name_variable struct_name) method_namen() [return_type] {
/* 方法实现*/}
实例:
package main
import (
"fmt")
type Phone interface {
call()}
type NokiaPhone struct {}
func (nokiaPhone NokiaPhone) call() {
fmt.Println("I am Nokia, I can call you!")}
type IPhone struct {}
func (iPhone IPhone) call() {
fmt.Println("I am iPhone, I can call you!")}
func main() {
var phone Phone
phone = new(NokiaPhone)
phone.call()
phone = new(IPhone)
phone.call()
}
在上面的例子中,我们定义了一个接口Phone,接口里面有一个方法call()。然后我们在main函数里面定义了一个Phone类型变量,并分别为之赋值为NokiaPhone和IPhone。然后调用call()方法.
Go语言处理错误:
Go语言通过内置的错误接口提供非常简单的错误处理机制.
Error 类型是一个接口,定义:
type error interface {
Error() string
}
函数通常在最后的返回值中返回错误信息。使用errors.New 可返回一个错误信息:
func Sqrt(f float64) (float64, error) {
if f < 0 {
return 0, errors.New("math: square root of negative number")
}
// 实现}
实例:
package main
import (
"fmt")
// 定义一个 DivideError 结构
type DivideError struct {
dividee int
divider int}
// 实现 `error` 接口
func (de *DivideError) Error() string {
strFormat := `
Cannot proceed, the divider is zero.
dividee: %d
divider: 0
`
return fmt.Sprintf(strFormat, de.dividee)}
// 定义 `int` 类型除法运算的函数
func Divide(varDividee int, varDivider int) (result int, errorMsg string) {
if varDivider == 0 {
dData := DivideError{
dividee: varDividee,
divider: varDivider,
}
errorMsg = dData.Error()
return
} else {
return varDividee / varDivider, ""
}
}
func main() {
// 正常情况
if result, errorMsg := Divide(100, 10); errorMsg == "" {
fmt.Println("100/10 = ", result)
}
// 当被除数为零的时候会返回错误信息
if _, errorMsg := Divide(100, 0); errorMsg != "" {
fmt.Println("errorMsg is: ", errorMsg)
}
}