break
case
chan
const
continue
default
defer
else
fallthrough
for
func
go
goto
if
import
interface
map
package
range
return
select
struct
switch
type
var
package main
import "fmt"
func main() {
p := 1
q := 2
if p != q && p <= q {
fmt.Println("True") // True
}
if p != q || p <= q {
fmt.Println("True") // True
}
if !(p == q) {
fmt.Println("True") // True
}
}
package main
import "fmt"
func main() {
p := 456
q := 793
fmt.Printf("计算结果是: p & q = %d", p & q) // 计算结果是: p & q = 264
fmt.Printf("\n计算结果是: p | q = %d", p | q) // 计算结果是: p | q = 985
fmt.Printf("\n计算结果是: p ^ q = %d", p ^ q) // 计算结果是: p ^ q = 721
fmt.Printf("\n计算结果是: p << q = %d", p << q) // 计算结果是: p << q = 0
fmt.Printf("\n计算结果是: p >> q = %d", p >> q) // 计算结果是: p >> q = 0
fmt.Printf("\n计算结果是: p &^ q = %d", p &^ q) // 计算结果是: p &^ q = 192
}
package main
import "fmt"
func main() {
p := 1
q := 2
// “=”(简单赋值)
p = q
fmt.Println(p) // 2
// “+=”(加法赋值)
p += q
fmt.Println(p) // 4, 由于上面运算已经赋值,所以是 p=2+q
//“-=”(减法赋值)
p -= q
fmt.Println(p) // 2,由于上面运算已经赋值,所以是 p=4-q
// “*=”(乘法赋值)
p *= q
fmt.Println(p) // 4,由于上面运算已经赋值,所以是 p=2*q
// “/=”(除法赋值)
p /= q
fmt.Println(p) // 2,由于上面运算已经赋值,所以是 p=4/2
// “%=”(求模赋值)
p %= q
fmt.Println(p) // 2,由于上面运算已经赋值,所以是 p=4/2
}
package main
import "fmt"
func main() {
a := 23
b := &a
fmt.Println(*b) // 23
*b = 78
fmt.Println(a) // 78
}
package main
import "fmt"
func main() {
/*
// 显示类型转换
var a int = 985
var b uint = uint(a)
var c int64 = int64(a)
var d float64 = float64(a)
fmt.Printf("转换类型: %T",b,c,d) // 转换类型: uint%!(EXTRA int64=985, float64=985)
*/
/*
// 计算平均值
var a int = 446
var b int = 23
var c float32
c = float32(a) / float32(b)
fmt.Printf("平均值 = %f",c) // 平均值 = 19.391304
*/
}
package main
import "fmt"
func main() {
var a int = 100
// if 语句
if(condition) {
//condition为真,执行
}
// if...else 语句
if (condition) {
// if条件为true,执行此代码块
} else {
// if条件为false,执行此代码块
}
// 嵌套if 语句
if (condition1) {
// 当条件1为真时执行
if (condition2) {
// 当条件2为真时执行
}
}
// if...else...if 语句
if(condition_1) {
//condition_1为true,执行这里的代码块
} else if(condition_2) {
//condition_2为true,执行这里的代码块
}else {
//没有条件为true时,执行这里代码块
}
}
for initialization; condition; post{
// 语句....
}
package main
import "fmt"
func main() {
// initialization 是 i := 0 , condition 是 i < 4 ; post 是 i++
// 意思: 定义变量i=0,从0开始,直到 i < 4 为真,每次循环之后 i+1
for i :=0; i < 4; i++ {
fmt.Println(i)
}
}
// 输出:
0
1
2
3
package main
import "fmt"
func main() {
// 无限循环
for {
fmt.Printf("nhooo\n")
}
}
package main
import "fmt"
func main() {
//while循环
//for循环执行到
//i <3条件为真
i:= 0
for i < 3 {
i += 2
}
fmt.Println(i)
}
package main
import "fmt"
func main() {
// 定义一个数组
_var := bytestring{"a","b","c"}
// index和j是分配迭代值的变量。它们也称为迭代变量。
// 第二个变量,即j是可选的。
// 范围表达式在循环开始之前被评估一次。
// index和j存储 _var 的值
// index存储单个字符串和的索引号
// j存储给定数组的单个字符串
for index,j := range _var{
fmt.Println(index, j)
}
}
// 输出
0 a
1 b
2 c
package main
import "fmt"
func main() {
for index, j := range "abcd" {
fmt.Println(index, j ,string(j))
// 0 97 a
// 1 98 b
// 2 99 c
// 3 100 d
}
for index, j := range "abcd" {
fmt.Printf("%U 的索引值为 %d\n", j, index,string(j))
// %!(EXTRA string=a)U+0062 的索引值为 1
// %!(EXTRA string=b)U+0063 的索引值为 2
// %!(EXTRA string=c)U+0064 的索引值为 3
// %!(EXTRA string=d)
}
}
package main
import "fmt"
func main() {
res := map[int]string{
111: "a",
222: "b",
333: "c",
}
for k, v := range res {
fmt.Println(k, v)
}
}
// 输出
111 a
222 b
333 c
package main
import "fmt"
func main() {
// 使用 channel
chnl := make(chan int)
go func() {
chnl <- 100
chnl <- 1000
chnl <- 10000
chnl <- 100000
close(chnl)
}()
for i := range chnl {
fmt.Println(i)
}
}
switch optstatement; optexpression{
case expression1: Statement..
case expression2: Statement..
...
default: Statement..
}
package main
import "fmt"
// 同时使用两种语句, 如可选语句, day:=4 和表达式 如:day
func main() {
switch day := 2; day{
case 1:
fmt.Println(1)
case 2:
fmt.Println(2) // 输出2
case 3:
fmt.Println(3)
default:
fmt.Println("I don't know")
}
}
package main
import "fmt"
func main() {
var value int = 2
switch {
case value == 1:
fmt.Println(1)
case value == 2:
fmt.Println(2)
case value == 3:
fmt.Println(3)
default:
fmt.Println("I don't know")
}
}
package main
import "fmt"
func main() {
var value string = "e"
//没有默认语句的switch语句,case语句中的多个值
switch value {
case "a":
fmt.Println("aaa")
case "b", "c":
fmt.Println("bbb")
case "d", "e", "f":
fmt.Println("ccc")
}
}
package main
import (
"fmt"
)
func outType(v interface{}) {
switch v.(type) {
case int:
fmt.Println(v, "is int")
case string:
fmt.Println(v, "is string")
case bool:
fmt.Println(v, "is bool")
}
}
func main() {
outType(1024) // 1024 is int
outType("pig") // pig is string
outType(true) // true is bool
}
select{
case SendOrReceive1: // 语句
case SendOrReceive2: // 语句
case SendOrReceive3: // 语句
.......
default: // Statement
}
package main
import "fmt"
func main() {
// 创建通道
c := make(chan int)
select {
case <-c:
default:
fmt.Println("default")
}
}
func function_name(Parameter_list)(Return_type){
// function body.....
}
package main
import "fmt"
// 此函数需要传两个 int 类型的值, 返回的值也是 int 类型
func abc(length, width int) int {
res := length + width
return res
}
func main() {
fmt.Println(abc(10,10)) // 调用函数
}
package main
import "fmt"
func myfunc(a [6]int, size int) int { // 接受两个参数,第一个参数6位int类型,第二个参数int类型, 返回int类型
var k, val, r int
for k = 0; k < size; k++ {
val += a[k]
}
r = val / size
return r
}
func main() {
//创建数组
var arr = [6]int{1,2,3,4,5,6}
// 初始化数组,并将数组作为参数传递
var res int = myfunc(arr, 6)
fmt.Println(res)
}
package main
import "fmt"
func main() {
// 定义一个数组,数组长度最大是8, 数组索引下标从0开始
arr := [8]string{"a","b","c","d","e","f","g"}
fmt.Println("数组:",arr) // 数组: [a b c d e f g ]
// 如何定义切片
// 1、使用var关键字,创建切片
// var my_slice_1 = []string{"nhooos", "for", "nhooos"}
// 2、创建切片,使用简写声明
// my_slice_2 := []int{12, 45, 67, 56, 43, 34, 45}
// 切片数组
myslice := arr[1:3] // 切片下标1开始,3结束,不包括3,也就是长度2
fmt.Println("切片:",myslice) // 切片: [b c]
fmt.Println("切片长度:", len(myslice)) // 切片长度:2 (3-1,两个数值)
fmt.Println("切片容量:",cap(myslice)) // 切片容量: 7 (最多存储)
fmt.Println(arr[0:]) // [a b c d e f g ]
fmt.Println(arr[:0]) // []
fmt.Println(arr[:3]) // [a b c]
fmt.Println(arr[:]) // [a b c d e f g ]
}
// 在 s 中查找 sep 的第一次出现,返回第一次出现的索引
func Index(s, sep string) int
// 在 s 中查找字节 c 的第一次出现,返回第一次出现的索引
func IndexByte(s string, c byte) int
// chars 中任何一个 Unicode 代码点在 s 中首次出现的位置
func IndexAny(s, chars string) int
// 查找字符 c 在 s 中第一次出现的位置,其中 c 满足 f(c) 返回 true
func IndexFunc(s string, f func(rune) bool) int
// Unicode 代码点 r 在 s 中第一次出现的位置
func IndexRune(s string, r rune) int
// 有三个对应的查找最后一次出现的位置
func LastIndex(s, sep string) int
func LastIndexByte(s string, c byte) int
func LastIndexAny(s, chars string) int
func LastIndexFunc(s string, f func(rune) bool) int
package main
import (
"fmt"
"strings"
"unicode"
)
func main() {
mapping := func(r rune) rune {
switch {
case r >= 'A' && r <= 'Z': // 大写字母转小写
return r + 32
case r >= 'a' && r <= 'z': // 小写字母不处理
return r
case unicode.Is(unicode.Han, r): // 汉字换行
return '\n'
}
return -1 // 过滤所有非字母、汉字的字符
}
fmt.Println(strings.Map(mapping, "Hello你#¥%……\n('World\n,好Hello^(&(*界gopher..."))
}
//
hello
world
hello
gopher
// 用 new 替换 s 中的 old,一共替换 n 个。
// 如果 n < 0,则不限制替换次数,即全部替换
func Replace(s, old, new string, n int) string //-> old 是 s 当中需要替换的字符
// 该函数内部直接调用了函数 Replace(s, old, new , -1)
func ReplaceAll(s, old, new string) string
package main
import (
"fmt"
)
type _Class struct {
name string
gender string
age int
}
func main() {
// 声明 struct 类型变量
var student _Class
fmt.Println(student) // { 0} , int 类型,默认为0
// 声明初始化结构
_st1 := _Class{"tom","boy", 18} // 方法一
_st2 := _Class{name:"tom", gender:"boy", age:18} // 方法二
_st3 := _Class{name:"tom"} // 方法三
fmt.Println(_st1) // {tom boy 18}
fmt.Println(_st2) // {tom boy 18}
fmt.Println(_st3) // {tom 0}
// 访问定义的结构文字
fmt.Println(_st1.name) // tom
fmt.Println(_st1.gender) // boy
fmt.Println(_st1.age) // 18
// 修改结构值
_st1.name = "google"
fmt.Println(_st1) // {google boy 18}
// 定义变量,并获取指向结构体的指针,既内存地址
_get := &_Class{"a","b",1}
fmt.Println((*_get).name) // a
fmt.Println(_get.name) // a
}
// 使用 reflect 下的 DeeplyEqual 方法
package main
import (
"fmt"
"reflect"
)
type _Class struct {
name string
gender string
age int
}
func main() {
_st1 := _Class{"a","女",18}
_st2 := _Class{"a","女",18}
_st3 := _Class{"a","女",19}
fmt.Println(reflect.DeepEqual(_st1, _st2)) // true
fmt.Println(reflect.DeepEqual(_st1, _st3)) // false
}
type struct_name_1 struct{
// Fields
}
type struct_name_2 struct{
variable_name struct_name_1
}
package main
import (
"fmt"
)
type User struct {
name string
gender string
age int
}
// 嵌套结构
type Group struct {
group User
}
func main() {
_g := Group{
group: User{name:"tom", gender: "girl", age: 18}, // 另起一行必须要加上,号
}
fmt.Println(_g) // {{tom girl 18}}
fmt.Println(_g.group.name) // tom, 访问结构属性
}
package main
import (
"fmt"
)
func main() {
// 创建和初始化一次性匿名结构
Student := struct {
name string
gender string
age int
}{
name: "张三",
gender: "女",
age: 18,
}
fmt.Println(Student) // {张三 女 18}
_Student
}
package main
import "fmt"
//创建一个结构匿名字段
type student struct {
int
string
float64
}
// Main function
func main() {
// 将值分配给匿名,学生结构的字段
value := student{123, "Bud", 8900.23}
fmt.Println("入学人数 : ", value.int) // 入学人数 : 123
fmt.Println("学生姓名 : ", value.string) // 学生姓名 : Bud
fmt.Println("套餐价格 : ", value.float64) // 套餐价格 : 8900.23
}
// 不允许创建两个或多个相同类型的字段
type student struct{
int
int
}
package main
import "fmt"
type Group struct {
group string
}
type User struct {
uname string
Group
}
func main() {
var _u User
_u.uname = "小明"
_u.group = "技术部"
fmt.Println(_u) // {小明 {技术部}}
}
//使用匿名函数作为Go结构中的一个字段
package main
import "fmt"
//创建结构
type Author struct {
name string
language string
Tarticles int
Particles int
Pending func(int, int) int
}
func main() {
//初始化结构字段
result := Author{
name: "Sonia",
language: "Java",
Tarticles: 340,
Particles: 259,
Pending: func(Ta int, Pa int) int {
return Ta - Pa
},
}
fmt.Println("作者姓名: ", result.name)
fmt.Println("语言: ", result.language)
fmt.Println("文章总数: ", result.Tarticles)
fmt.Println("发表文章总数: ", result.Particles)
fmt.Println("待处理文章: ", result.Pending(result.Tarticles, result.Particles))
// 作者姓名: Sonia
// 语言: Java
// 文章总数: 340
// 发表文章总数: 259
// 待处理文章: 81
}
//使用匿名函数作为Go结构中的一个字段
package main
import "fmt"
func main() {
b := 255
var a *int = &b
fmt.Println(a) // 变量的指针地址 0xc00018c000
fmt.Println(b) // 变量值
}
//使用匿名函数作为Go结构中的一个字段
package main
import "fmt"
func main() {
b := 255
a := &b // 引用
fmt.Println(a) // 打印指针地址
fmt.Println(*a) // 解引用
}
//使用匿名函数作为Go结构中的一个字段
package main
import "fmt"
func change(val *int) {
*val = 55
}
func main() {
a := 59
b := &a // 把 b 的值指向 a 的指针地址
change(b) // 传递指针给函数,并修改指针地址
fmt.Println(a)
}
package main
import (
"fmt"
)
type Student struct {
name string
age int
}
/* 使用值接收器 */
func (e Student) ModifyName(newName string) {
e.name = newName
}
/* 使用指针接收器 */
func (e *Student) ModifyAge(newAge int) {
e.age = newAge
}
func main() {
e := Student{name: "tom", age: 20,}
e.ModifyName("jack aaaa") // 调用值接收器
fmt.Println(e.name) // tom,发现前后都是一样,值没有改变
e.ModifyAge(50)
fmt.Println(e.age) // 50, 发现值已经改变,变成50
}
package main
import (
"fmt"
)
type address struct {
city string
state string
}
func (e address) fullAddress() {
fmt.Println(e.city , e.state)
}
// 匿名结构体
type person struct {
firstName string
lastName string
address
}
func main() {
p := person{
firstName: "张",
lastName: "三",
address: address{
city: "BeiJing",
state: "JinShuiQu",
},
}
p.fullAddress() // BeiJing JinShuiQu
}
package main
import (
"fmt"
)
type rectangle struct {
length int
width int
}
func area(r rectangle) {
fmt.Printf("Area Function result: %d\n", (r.length * r.width))
}
func (r rectangle) area() {
fmt.Printf("Area Method result: %d\n", (r.length * r.width))
}
func main() {
r := rectangle{
length: 10,
width: 5,
}
area(r) // Area Function result: 50, 等同如下
r.area() // Area Method result: 50, 等同如上
p := &r
/*
compilation error, cannot use p (type *rectangle) as type rectangle
in argument to area
*/
//area(p)
p.area()//通过指针调用值接收器
}
package main
import (
"fmt"
)
type rectangle struct {
length int
width int
}
// 定义了一个接受指针参数的函数 perimeter
func perimeter(r *rectangle) {
fmt.Println("perimeter function output:", 2*(r.length+r.width))
}
// 定义了一个有一个指针接收器的方法
func (r *rectangle) perimeter() {
fmt.Println("perimeter method output:", 2*(r.length+r.width))
}
func main() {
r := rectangle{
length: 10,
width: 5,
}
p := &r //pointer to r
perimeter(p) // perimeter function output: 30
p.perimeter() // perimeter method output: 30
/*
cannot use r (type rectangle) as type *rectangle in argument to perimeter
*/
//perimeter(r)
r.perimeter()//使用值来调用指针接收器 perimeter method output: 30
}
package main
import "fmt"
// 为内置类型 int 创建一个类型别名,然后创建一个以该类型别名为接收器的方法
// 为 int 创建了一个类型别名 myInt。我们定义了一个以 myInt 为接收器的的方法 add。
type myInt int
func (a myInt) add(b myInt) myInt {
return a + b
}
func main() {
num1 := myInt(5)
num2 := myInt(10)
sum := num1.add(num2)
fmt.Println("Sum is", sum)
}
type interface_name interface{
//方法签名
}
package main
import "fmt"
// 定义接口
type MyApi interface {
// 定义接口下的方法,返回 rune 类型切片
Response() []rune
}
// 声明类型
type MyString string
// 接收器接受类型 MyString,并添加 Response() []rune 方法
func (ms MyString) Response() []rune {
// 方便操作,重新赋值返回值
var _data []rune
// 循环遍历类型 MyString, 也就是 ms 传值字符串
for _, i := range ms {
// 单引号表示字符,双引号表示字符串
if i == 'a' || i == 'e' {
_data = append(_data, i)
}
}
return _data
}
func main() {
name := MyString("Sam Anderson")
var api MyApi
// name 是 MyString 类型,api 类型是 Myapi
// 把 name 赋值给 api, api.Response() 调用 MyString 类型 Response()方法
api = name
fmt.Printf("%c", api.Response()) // [a e]
}
package main
import (
"fmt"
)
// 创建接口, 薪资计算器
type SalaryCalculator interface {
CalculateSalary() int
}
// 永久雇员工资结构体
type Permanent struct {
empId int
basicpay int
pf int
}
// 合同员工工资结构体
type Contract struct {
empId int
basicpay int
}
// 永久雇员的工资是基本工资和公积金的总和
func (p Permanent) CalculateSalary() int {
return p.basicpay + p.pf
}
// 合同工的工资是单独的基本工资
func (c Contract) CalculateSalary() int {
return c.basicpay
}
/*
作用说明:总费用是通过遍历SalaryCalculator切片并求和来计算的雇员个人的工资
方法说明:该方法接收一个 SalaryCalculator 接口的切片([]SalaryCalculator)作为参数
*/
func totalExpense(s []SalaryCalculator) {
// 设置初始总费用为:0
expense := 0
for _, v := range s {
expense = expense + v.CalculateSalary()
}
fmt.Printf("公司每月工资总费用 $%d", expense)
}
func main() {
pemp1 := Permanent{1, 5000, 20} // 第一个永久雇员的工资
pemp2 := Permanent{2, 6000, 30} // 第二个永久雇员的工资
cemp1 := Contract{3, 3000} // 合同工的工资
employees := []SalaryCalculator{pemp1, pemp2, cemp1}
totalExpense(employees) // 执行上面的方法
}
package main
import "fmt"
// 定义接口, Test 接口只有一个方法 Tester()
type Test interface {
Tester()
}
// 定义变量 MyFloat 为 float64
type MyFloat float64
// 定义接收器, MyFloat 类型实现了该接口
func (m MyFloat) Tester() {
fmt.Println(m)
}
func main() {
var t Test // 赋值 t 为接口
f := MyFloat(98.1) // 赋值 f 的变量值
t = f // 把 f (MyFloat) 类型的值赋值给 t ,t 的类型变成 MyFloat
t.Tester() // 调用接收器方法, 输出: 98.1
}
package main
import "fmt"
// describe(i interface{}) 函数接收空接口作为参数,因此,可以给这个函数传递任何类型
func describe(i interface{}) {
fmt.Printf("Type = %T, value = %v\n", i, i)
}
func main() {
s := "Hello World"
describe(s) // Type = string, value = Hello World
i := 55
describe(i) // Type = int, value = 55
// 匿名结构体
strt := struct {
name string
}{
name: "Hungry",
}
describe(strt) // Type = struct { name string }, value = {Hungry}
}
package main
import "fmt"
// 如果 i 的具体类型是 T,那么 v 赋值为 i 的底层值,而 ok 赋值为 true。
// 如果 i 的具体类型不是 T,那么 ok 赋值为 false,v 赋值为 T 类型的零值,此时程序不会报错。
// v, ok := i.(T)
func assert(i interface{}) {
v, ok := i.(int)
fmt.Println(v, ok)
}
func main() {
var s interface{} = 56
assert(s) // 56 true
var i interface{} = "Steven Paul"
assert(i) // 0 false
}
package main
import "fmt"
// switch i.(type) 表示一个类型选择。每个 case 语句都把 i 的具体类型和一个指定类型进行了比较。如果 case 匹配成功,会打印出相应的语句
func FindType(i interface{}) {
switch i.(type) {
case string:
fmt.Printf("String %s\n", i.(string)) // String aaa
case int:
fmt.Printf("Int %d\n", i.(int)) // Int 111
default:
fmt.Printf("Unknow type\n") // Unknow type
}
}
func main() {
FindType("aaa")
FindType(111)
FindType(111.11)
}
package main
import "fmt"
// 定义一个接口
type Describer interface {
Db()
}
// 定义结构体
type Person struct {
name string
age int
}
// 接收器
func (p Person) Db() {
fmt.Printf("%s is %d years old", p.name, p.age)
}
// 定义一个方法
func findType(i interface{}) {
switch v := i.(type) {
case Describer:
v.Db()
default:
fmt.Printf("Unknow type\n")
}
}
func main() {
findType("aaaa") // Unknow type
// 结构体 Person 实现了 Describer 接口
p := Person{
name: "girl",
age: 18,
}
findType(p) // girl is 18 years old
}
package main
import "fmt"
// 定义一个接口
type Describer interface {
Db()
}
// 定义一个结构体
type Person struct {
name string
age int
}
// 定义一个值接收器实现接口
func (p Person) Db() {
fmt.Printf("%s is %d years old\n", p.name, p.age)
}
type Address struct {
state string
country string
}
// 定义一个指针接收器实现接口
func (a *Address) Db() {
fmt.Printf("Statee %s Country %s", a.state, a.country)
}
func main() {
var d1 Describer // 赋值接口变量
p1 := Person{"tom", 29}
d1 = p1 // 赋值值给接口
d1.Db() // 调用接口方法: tom is 29 years old
p2 := Person{"Harry", 18}
d1 = &p2 // 赋值指针给接口
d1.Db() // 调用接口方法: Harry is 18 years old
/*
使用值接受者声明的方法,既可以用值来调用,也能用指针调用
*/
var d2 Describer
a := Address{"China","ShangHai"}
fmt.Println(&a) // &{China ShangHai} ,可以看出 &{China ShangHai}
d2 = &a
d2.Db() // 调用接口方法: Statee China Country ShangHai
/*
对于使用指针接受者的方法,用一个指针或者一个可取得地址的值来调用都是合法的。但接口中存储的具体值(Concrete Value)并不能取到地址,
*/
}
package main
import (
"fmt"
)
// 薪资计算器接口
type SalaryCalculator interface {
DisplaySalary()
}
// 离开计算器接口
type LeaveCalculator interface {
CalculateLeavesLeft() int
}
type Employee struct {
firstName string
lastName string
basicPay int
pf int
totalLeaves int
leavesTaken int
}
func (e Employee) DisplaySalary() {
fmt.Printf("%s %s has salary $%d", e.firstName, e.lastName, (e.basicPay + e.pf))
}
func (e Employee) CalculateLeavesLeft() int {
return e.totalLeaves - e.leavesTaken
}
func main() {
e := Employee {
firstName: "Naveen",
lastName: "Ramanathan",
basicPay: 5000,
pf: 200,
totalLeaves: 30,
leavesTaken: 5,
}
var s SalaryCalculator = e
s.DisplaySalary() // Naveen Ramanathan has salary $5200
var l LeaveCalculator = e
fmt.Println("\nLeaves left =", l.CalculateLeavesLeft()) // Leaves left = 25
}
// 声明了两个接口:SalaryCalculator 和 LeaveCalculator。
// 定义了结构体 Employee, 实现了 SalaryCalculator 接口的 DisplaySalary 方法, 又实现了LeaveCalculator 接口里的 CalculateLeavesLeft 方法
// 于是 Employee 就实现了 SalaryCalculator 和 LeaveCalculator 两个接口。
package main
import "fmt"
type Describer interface {
Describe()
}
func main() {
var d1 Describer
if d1 == nil {
fmt.Printf("d1 is nil and has type %T value %v\n", d1, d1)
// d1 is nil and has type <nil> value <nil>
}
}
package main
import (
"fmt"
)
type Stu struct{}
func (St *Stu) Show() {
fmt.Println("aaaaa")
}
type People interface {
Show()
}
func main() {
var p People = &Stu{} // 传递结构体指针
p.Show() // aaaaa
}
package main
import (
"fmt"
)
type Stu struct{}
func (St Stu) Show() {
fmt.Println("aaaaa")
}
type People interface {
Show()
}
func main() {
var p People = Stu{} // 值类型
p.Show() // aaaaa
}
package main
import (
"fmt"
)
type Stu struct{}
func (St *Stu) Show() {
fmt.Println("aaaaa")
}
type People interface {
Show()
}
// 实现接口
func Line() People {
var stu *Stu
return stu
}
func main() {
p := Line()
p.Show()
}
package main
import (
"fmt"
"time"
)
func hello() {
fmt.Println("Helo world")
}
func main() {
go hello()
// time.Sleep(1 * time.Second) , 如果想输出 hello 函数方法,使用休眠,以便等待其他协程执行完毕
fmt.Println("main") // main
}
// 调用了 go hello() 之后,程序控制没有等待 hello 协程结束,立即返回到了代码下一行,打印 main function。接着由于没有其他可执行的代码,Go 主协程终止,于是 hello 协程就没有机会运行了。
package main
import (
"fmt"
"time"
)
func numbers() {
for i := 0; i <= 5;i ++ {
time.Sleep(250 * time.Millisecond)
fmt.Printf("%d",i)
}
}
func alphabets() {
for i := 'a'; i <= 'e'; i++ {
time.Sleep(400 * time.Millisecond)
fmt.Printf("%c ", i)
}
}
func main() {
go numbers()
go alphabets()
time.Sleep(3000 * time.Millisecond)
fmt.Println("main terminated")
}
// 0a 12b 3c 45d e main terminated
package main
import (
"fmt"
)
func main() {
var a chan int // 定义信道 a, 类型 int,默认零值
if a == nil {
a := make(chan int) // 用 make 来定义信道
fmt.Printf("Type of a is %T", a) // Type of a is chan int
}
}
package main
import (
"fmt"
)
func producer(chnl chan int) {
for i := 0; i < 10; i++ {
chnl <- i
}
close(chnl)
}
func main() {
ch := make(chan int)
go producer(ch)
for {
v, ok := <- ch
if ok == false {
break
}
fmt.Println("Received ", v, ok)
}
}
Received 0 true
Received 1 true
Received 2 true
Received 3 true
Received 4 true
Received 5 true
Received 6 true
Received 7 true
Received 8 true
Received 9 true
package main
import (
"fmt"
)
func producer(chnl chan int) {
for i := 0; i < 10; i++ {
chnl <- i
}
close(chnl)
}
func main() {
ch := make(chan int)
go producer(ch)
// for range 循环从信道 ch 接收数据,直到该信道关闭。一旦关闭了 ch,循环会自动结束。该程序会输出:
for v := range ch {
fmt.Println("Received ",v)
}
}
Received 0
Received 1
Received 2
Received 3
Received 4
Received 5
Received 6
Received 7
Received 8
Received 9
package main
import (
"fmt"
"time"
)
func write(ch chan int) {
for i := 0; i < 6; i++ {
ch <- i
fmt.Println("Successfully wrote", i, "to ch")
}
close(ch)
}
func main() {
// 缓冲值是 2
ch := make(chan int, 2)
go write(ch)
// <- ch
time.Sleep(1 * time.Second)
for v := range ch {
fmt.Println("read value", v,"from ch")
time.Sleep(1 * time.Second)
}
}
Successfully wrote 0 to ch
Successfully wrote 1 to ch
read value 0 from ch
Successfully wrote 2 to ch
read value 1 from ch
Successfully wrote 3 to ch
read value 2 from ch
Successfully wrote 4 to ch
read value 3 from ch
Successfully wrote 5 to ch
read value 4 from ch
read value 5 from ch
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan send]:
main.main()
/tmp/sandbox274756028/main.go:11 +0x100
package main
import (
"fmt"
)
func main() {
ch := make(chan string, 3)
ch <- "naveen"
ch <- "paul"
fmt.Println("capacity is", cap(ch)) // 信道容量 capacity is 3
fmt.Println("length is", len(ch)) // 信道长度 length is 2
fmt.Println("read value", <-ch) // 打印内容 read value naveen
fmt.Println("new length is", len(ch)) // 使用过后的长度 new length is 1
}
package main
import (
"fmt"
"sync"
"time"
)
func process(i int, wg *sync.WaitGroup) {
fmt.Println("started Goroutine ", i)
time.Sleep(2 * time.Second)
fmt.Printf("Goroutine %d ended\n", i)
wg.Done() // 减少计数器,调用 WaitGroup 的 Done() 方法
}
func main() {
no := 3
var wg sync.WaitGroup // 创建 WaitGroup 类型变量,初始值为 0
for i := 0; i < no; i++ {
wg.Add(1) // 调用 WaitGroup 的 Add 并传递一个 int 时.,WaitGroup 的计数器会加上 Add 的传参
go process(i, &wg)
}
wg.Wait() // Wait() 方法会阻塞调用它的 Go 协程,直到计数器变为 0 后才会停止阻塞
fmt.Println("All go routines finished executing")
}
// 由于 Go 协程的执行顺序不一定
started Goroutine 2
started Goroutine 1
started Goroutine 0
Goroutine 0 ended
Goroutine 1 ended
Goroutine 2 ended
All go routines finished executing
package main
import (
"fmt"
"sync"
"time"
"math/rand"
)
// 第一步: 创建结构体,表示作业和结果
type Job struct {
id int
randomno int // 用于计算其每位数之和
}
type Result struct {
job Job // 表示所对应的作业
sumofdigits int // 表示计算的结果(每位数字之和)
}
// 第二步:创建用于接受作业和写入结果的缓冲信道
var jobs = make(chan Job, 10)
var results = make(chan Result, 10)
// digits 函数的任务实际上就是计算整数的每一位之和,最后返回该结果
func digits(number int) int {
// 默认结果未 0
sum := 0
// 赋值变量
no := number
for no != 0 {
digits := no % 10
sum += digits
no /= 10
}
// 为了模拟出 digits 在计算过程中花费了一段时间,我们在函数内添加了两秒的休眠时间
time.Sleep(1 * time.Second)
return sum
}
// 然后,我们写一个创建工作协程的函数
/*
创建一个工作者 worker, 读取 jobs 信道的数据,根据当前的 job 和 digits 的返回值,
创建了一个 Result 结构体变量,然后将结果写入 results 缓冲信道。
worker 函数接收一个 WaitGroup 类型的 wg 作为参数,当所有的 jobs 完成时候,调用 Done() 方法
*/
func worker(wg *sync.WaitGroup) {
for job := range jobs {
output := Result{job, digits(job.randomno)}
results <- output
}
wg.Done()
}
// creatWorkerPool 函数创建了一个 Go 协程的工作池
/*
函数的参数是需要创建的工作协程的数量
在创建 Go 协程之前,它调用了 wg.Add(1)方法,于是 WaitGroup 计数器递增,
接下来,我们创建工作协程,并向 worker 函数传递 wg 地址。
创建了需要的工作协程后,函数调用了 wg.Wait(),等待所有的 Go 协程执行完毕。
所有协程完成执行之后,函数会关闭 results 信道。
因为所有协程都已经执行完毕,于是不再需要向 results 信道写入数据
*/
func createWorkerPool(noOfWorkers int) {
var wg sync.WaitGroup
for i := 0; i < noOfWorkers; i++ {
wg.Add(1)
go worker(&wg)
}
wg.Wait()
close(results)
}
// 现在我们已经有了工作池,继续编写一个函数,把作业分配给工作者
/*
allocate 函数接收所需创建的作业数量作为输入参数,生成了最大值为 9 的伪随机数,并使用该随机数创建了 Job 结构体变量。
这个函数把 for 循环的计数器 i 作为 id,最后把创建的结构体变量写入 jobs 信道。当写入所有的 job 时,它关闭了 jobs 信道。
*/
func allocate(noOfJobs int) {
for i := 0; i < noOfJobs ; i++ {
randomno := rand.Intn(9)
job := Job{i, randomno}
jobs <- job
}
close(jobs)
}
// 创建一个读取 results 信道和打印输出的函数。
/*
result 函数读取 results 信道,并打印出 job 的 id、输入的随机数、该随机数的每位数之和。
result 函数也接受 done 信道作为参数,当打印所有结果时,done 会被写入 true。
*/
func result(done chan bool) {
for result := range results {
fmt.Printf("Job id %d, input random no %d , sum of digits %d\n", result.job.id, result.job.randomno, result.sumofdigits)
}
done <- true
}
func main() {
startTime := time.Now()
noOfJobs := 10
go allocate(noOfJobs)
done := make(chan bool)
go result(done)
noOfWorkers := 5
createWorkerPool(noOfWorkers)
<-done
endTime := time.Now()
diff := endTime.Sub(startTime)
fmt.Println("total time taken ", diff.Seconds(), "seconds")
}
Job id 4, input random no 4 , sum of digits 4
Job id 1, input random no 6 , sum of digits 6
Job id 0, input random no 5 , sum of digits 5
Job id 2, input random no 2 , sum of digits 2
Job id 3, input random no 2 , sum of digits 2
Job id 5, input random no 6 , sum of digits 6
Job id 7, input random no 8 , sum of digits 8
Job id 6, input random no 7 , sum of digits 7
Job id 8, input random no 4 , sum of digits 4
Job id 9, input random no 6 , sum of digits 6
total time taken 2.000395302 seconds
package main
import (
"fmt"
"time"
)
func process(ch chan string) {
time.Sleep(10500 * time.Millisecond)
ch <- "process successfull"
}
func main() {
ch := make(chan string)
go process(ch)
for {
time.Sleep(1000 * time.Millisecond)
select {
case v := <- ch:
fmt.Println("received value:", v)
return
default:
fmt.Println("No have value")
}
}
}
/*
并发地调用了 process 协程之后,主协程启动了一个无限循环。
这个无限循环在每一次迭代开始时,都会先休眠 1000 毫秒(1 秒),然后执行一个 select 操作。
在最开始的 10500 毫秒中,由于 process 协程在 10500 毫秒后才会向 ch 信道写入数据,因此 select 语句的第一个 case(即 case v := <-ch:)并未就绪。
所以在这期间,程序会执行默认情况,该程序会打印 10 次 no value received。
在 10.5 秒之后,process 协程会在第 10 行向 ch 写入 process successful。
现在,就可以执行 select 语句的第一个 case 了,程序会打印 received value: process successful,然后程序终止。该程序会输出:
*/
package main
func main() {
ch := make(chan string)
select {
case <-ch:
}
}
// 创建了一个信道 ch。我们在 select 内部(第 6 行),试图读取信道 ch。由于没有 Go 协程向该信道写入数据,因此 select 语句会一直阻塞,导致死锁。该程序会触发运行时 panic,报错信息如下:
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan receive]:
main.main()
/tmp/sandbox416567824/main.go:6 +0x80
package main
import "fmt"
func main() {
ch := make(chan string)
select {
case <-ch:
default:
fmt.Println("default case executed")
}
}
package main
import "fmt"
func main() {
var ch chan string
select {
case v := <-ch:
fmt.Println("received value", v)
default:
fmt.Println("default case executed")
}
}
/*
ch 等于 nil,而我们试图在 select 中读取 ch(第 8 行)。如果没有默认情况,select 会一直阻塞,导致死锁。由于我们在 select 内部加入了默认情况,程序会执行它
*/
mutex.Lock()
x = x + 1
mutex.Unlock()
// 如果有一个 Go 协程已经持有了锁(Lock),当其他协程试图获得该锁时,这些协程会被阻塞,直到 Mutex 解除锁定为止
package main
import (
"fmt"
"sync"
)
var x = 0
func increment(wg *sync.WaitGroup, m *sync.Mutex) {
m.Lock()
x = x + 1
m.Unlock()
wg.Done()
}
/*
我们修改了 increment 函数,将增加 x 的代码(x = x + 1)放置在 m.Lock() 和 m.Unlock()之间。现在这段代码不存在竞态条件了,因为任何时刻都只允许一个协程执行这段代码。
*/
func main() {
var w sync.WaitGroup
var m sync.Mutex // 定义加锁
for i := 0; i < 1000; i++ {
w.Add(1)
go increment(&w, &m)
}
w.Wait()
fmt.Println("Final value of x", x) // Final value of x 1000
}
package main
import (
"fmt"
"sync"
)
var x = 0
func increment(wg *sync.WaitGroup,ch chan bool) {
ch <- true
x = x + 1
<- ch
wg.Done()
}
func main() {
var w sync.WaitGroup
ch := make(chan bool, 1)
for i := 0; i < 10; i++{
w.Add(1)
go increment(&w,ch)
}
w.Wait()
fmt.Println("Finshed value of x", x) // Finshed value of x 10
}
opp/
├── employee
│ └── employee.go
└── main.go
package employee
import (
"fmt"
)
type employee struct {
firstName string
lastName string
totalLeaves int
leavesTaken int
}
/*
Go 不支持类,但结构体能够很好地取代类,而以 New(parameters) 签名的方法可以替代构造器。
提供了一个可引用的 New 函数,该函数接收必要的参数,返回一个新创建的 employee 结构体变量。
*/
func New(firstName string, lastName string, totalLeave int, leavesTaken int) employee {
e := employee {firstName, lastName, totalLeave, leavesTaken}
return e
}
func (e employee) LeavesRemaining() {
fmt.Printf("%s %s has %d leaves remaining", e.firstName, e.lastName, (e.totalLeaves - e.leavesTaken))
}
package main
import "oop/employee"
func main() {
e := employee.New("Sam", "Adolf", 30, 20)
e.LeavesRemaining() // Sam Adolf has 10 leaves remaining
}
package main
import (
"fmt"
)
/*
1、创建 author 结构体, author 字段有 firename、lastname、bio
2、添加了 fullName() 方法,其中 author 作为接受者类型,该方法返回作者的全名
*/
type author struct {
firstName string
lastName string
bio string
}
func (a author) fullName() string {
return fmt.Sprintf("%s %s", a.firstName, a.lastName)
}
/*
1、post 结构体的字段有 title、content, 嵌套匿名字段 author
2、post 可以访问 author 结构体的所有字段和方法
3、post 结构体添加了 details() 方法,用于打印标题、内容和作者的全名与简介
*/
type post struct {
title string
content string
author // 嵌套匿名字段 author
}
func (p post) details() {
fmt.Println("Title: ", p.title)
fmt.Println("Content: ", p.content)
fmt.Println("Author: ", p.fullName())
fmt.Println("Bio: ", p.bio)
}
/*
结构体切片的嵌套,
使用博客帖子的切片来创建一个网站
*/
type website struct {
posts []post // 结构体不能嵌套一个匿名切片,需要指定一个字段名来嵌套
}
func (w website) contents() {
fmt.Println("Contents of Website\n")
for _, v := range w.posts {
v.details()
fmt.Println()
}
}
func main() {
author1 := author{"张", "三", "Golang"}
post1 := post{
"Inheritance in Go",
"Go supports composition instead of inheritance",
author1,
}
post2 := post{
"Struct instead of Classes in Go",
"Go does not support classes but methods can be added to structs",
author1,
}
post3 := post{
"Concurrency",
"Go is a concurrent language and not a parallel one",
author1,
}
w := website{
posts: []post{post1,post2, post3},
}
w.contents()
}
Contents of Website
Title: Inheritance in Go
Content: Go supports composition instead of inheritance
Author: 张 三
Bio: Golang
Title: Struct instead of Classes in Go
Content: Go does not support classes but methods can be added to structs
Author: 张 三
Bio: Golang
Title: Concurrency
Content: Go is a concurrent language and not a parallel one
Author: 张 三
Bio: Golang
package main
import "fmt"
// 定义一个接口, 接口里有两个方法
type Inome interface {
calculate() int // 计算并返回项目的收入
source() string // 返回项目名称
}
// 项目类型一
type FixedBilling struct {
projectName string // 项目名称
biddedAmount int // 该项目投标的金额
}
// 项目类型二
type TimeAndMaterial struct {
projectName string // 项目名称
noOfHours int
hourlyRate int
}
// 下一步我们给这些结构体类型定义方法,计算并返回实际收入和项目名称。
// 由于 FixedBilling 和 TimeAndMaterial 两个结构体都定义了 Income 接口的两个方法:calculate() 和 source(),
// 因此这两个结构体都实现了 Income 接口。
func (fb FixedBilling) calculate() int {
return fb.biddedAmount // 返回FixedBilling实际收入
}
func (fb FixedBilling) source() string {
return fb.projectName // 返回FixedBilling项目名称。
}
func (tm TimeAndMaterial) calculate() int {
return tm.noOfHours * tm.hourlyRate // 返回 TimeAndMaterial 实际收入,收入等于 noOfHours 和 hourlyRate 的乘积
}
func (tm TimeAndMaterial) source() string {
return tm.projectName // 返回 TimeAndMaterial 项目名称。
}
/*
声明一个 calculateNetIncome 函数,用来计算并打印总收入。
接收一个 Income 接口类型的切片作为参数。该函数会遍历这个接口切片,并依个调用 calculate() 方法,计算出总收入。该函数同样也会通过调用 source() 显示收入来源。根据 Income 接口的具体类型,程序会调用不同的 calculate() 和 source() 方法。于是,我们在 calculateNetIncome 函数中就实现了多态。
*/
func calculateNetIncome(ic []Inome) {
var netincome int = 0
for _, i := range ic {
fmt.Printf("Income From %s = $%d\n", i.source(), i.calculate())
netincome += i.calculate()
}
fmt.Printf("Net income of organisation = $%d", netincome)
}
/*
main 函数中,我们创建了三个项目,有两个是 FixedBilling 类型,一个是 TimeAndMaterial 类型。接着我们创建了一个 Income 类型的切片,存放了这三个项目。由于这三个项目都实现了 Interface 接口,因此可以把这三个项目放入 Income 切片。最后我们将该切片作为参数,调用了 calculateNetIncome 函数,显示了项目不同的收益和收入来源。
如果在该组织以后增加了新的收入来源,calculateNetIncome 无需修改一行代码,就可以正确地计算总收入了。:smile:
*/
func main() {
project1 := FixedBilling{projectName: "Project 1", biddedAmount: 5000}
project2 := FixedBilling{projectName: "Project 2", biddedAmount: 10000}
project3 := TimeAndMaterial{projectName: "Project 3", noOfHours: 160, hourlyRate: 25}
incomeStreams := []Inome{project1, project2, project3} // 定义接口传值切片
calculateNetIncome(incomeStreams)
}
Income From Project 1 = $5000
Income From Project 2 = $10000
Income From Project 3 = $4000
Net income of organisation = $19000
Income From Project 1 = $5000
Income From Project 2 = $10000
Income From Project 3 = $4000
Income From Banner Ad = $1000
Income From Popup Ad = $3750
Net income of organisation = $23750
package main
import (
"fmt"
"os"
)
/*
在处理错误时,通常都是将返回的错误与 nil 比较
nil 值表示了没有错误发生,而非 nil 值表示出现了错误
*/
func main() {
f, err := os.Open("/test.txt")
if err != nil {
fmt.Println(err) // open /test.txt: no such file or directory
return
}
fmt.Println(f.Name())
}
type error interface {
Error() string
}
package main
import (
"fmt"
"os"
)
func main() {
f, err := os.Open("/test.txt")
// 使用了类型断言(Type Assertion)来获取 error 接口的底层值
if err, ok := err.(*os.PathError); ok {
fmt.Println("File at path", err.Path, "failed to open")
return
}
fmt.Println(f.Name(), "opened successfully")
}
package main
import (
"fmt"
"net"
)
func main() {
addr, err := net.LookupHost("golangbot123.com")
if err, ok := err.(*net.DNSError); ok {
if err.Timeout() {
fmt.Println("operation timed out")
} else if err.Temporary() {
fmt.Println("temporary error")
} else {
fmt.Println("generic error: ", err)
}
return
}
fmt.Println(addr)
}
package main
import (
"errors"
"fmt"
"math"
)
/*
定义方法,接收一个 float64 类型参数,返回 float64 和 error
New 函数自定义返回的错误信息
*/
func circleArea(radius float64) (float64, error) {
if radius < 0 {
return 0, errors.New("radius is less than zero")
}
return math.Pi * radius * radius, nil
}
func main() {
radius := -20.0
area, err := circleArea(radius)
// 检查错误是否等于 nil。如果不是 nil,我们会打印出错误并返回,否则我们会打印出圆的面积
if err != nil {
fmt.Println(err)
return
}
fmt.Printf("Area of circle %0.2f", area)
}
package main
import (
"fmt"
"math"
)
func circleArea(radius float64) (float64, error) {
if radius < 0 {
return 0, fmt.Errorf("Area calculation failed, radius %0.2f is less than zero", radius)
}
return math.Pi * radius * radius, nil
}
func main() {
radius := -20.0
area, err := circleArea(radius)
if err != nil {
fmt.Println(err)
return
}
fmt.Printf("Area of circle %0.2f", area)
}
package main
import (
"fmt"
"math"
)
type areaError struct {
err string
radius float64
}
func (e *areaError) Error() string {
return fmt.Sprintf("radius %0.2f: %s", e.radius, e.err)
}
func circleArea(radius float64) (float64, error) {
if radius < 0 {
return 0, &areaError{"radius is negative", radius}
}
return math.Pi * radius * radius, nil
}
func main() {
radius := -20.0
area, err := circleArea(radius)
if err != nil {
if err, ok := err.(*areaError); ok {
fmt.Printf("Radius %0.2f is less than zero", err.radius)
return
}
fmt.Println(err)
return
}
fmt.Printf("Area of rectangle1 %0.2f", area)
}
// 第一步就是创建一个表示错误的结构体。
// 有了错误类型,我们来实现 error 接口,并给该错误类型添加两个方法,使它提供了更多的错误信息
package main
import "fmt"
type areaError struct {
err string //error description
length float64 //length which caused the error
width float64 //width which caused the error
}
// Error() string 方法中返回了关于错误的描述
func (e *areaError) Error() string {
return e.err
}
// 当 length 小于零时,lengthNegative() bool 方法返回 true
func (e *areaError) lengthNegative() bool {
return e.length < 0
}
// 当 width 小于零时,widthNegative() bool 方法返回 true
func (e *areaError) widthNegative() bool {
return e.width < 0
}
// rectArea 函数检查了长或宽是否小于零,如果小于零,rectArea 会返回一个错误信息,否则 rectArea 会返回矩形的面积和一个值为 nil 的错误。
func rectArea(length, width float64) (float64, error) {
err := ""
if length < 0 {
err += "length is less than zero"
}
if width < 0 {
if err == "" {
err = "width is less than zero"
} else {
err += ", width is less than zero"
}
}
if err != "" {
return 0, &areaError{err, length, width}
}
return length * width, nil
}
/*
我们检查了错误是否为 nil。如果错误值不是 nil,我们会在下一行断言 *areaError 类型。
然后,我们使用 lengthNegative() 和 widthNegative() 方法,检查错误的原因是长度小于零还是宽度小于零。
这样我们就使用了错误结构体类型的方法,来提供更多的错误信息。
如果没有错误发生,就会打印矩形的面积。
*/
func main() {
length, width := -5.0, -9.0
area, err := rectArea(length, width)
if err != nil {
if err, ok := err.(*areaError); ok {
if err.lengthNegative() {
fmt.Printf("error: length %0.2f is less than zero\n", err.length)
}
if err.widthNegative() {
fmt.Printf("error: width %0.2f is less than zero\n", err.width)
}
return
}
fmt.Println(err)
return
}
fmt.Println("area of rect", area)
}
error: length -5.00 is less than zero
error: width -9.00 is less than zero
package main
import (
"fmt"
)
func fullName(firstName *string, lastName *string) {
if firstName == nil {
panic("runtime error: first name cannot be nil")
}
if lastName == nil {
panic("runtime error: last name cannot be nil")
}
fmt.Printf("%s %s\n", *firstName, *lastName)
fmt.Println("returned normally from fullName")
}
func main() {
firstName := "Elon"
fullName(&firstName, nil)
fmt.Println("returned normally from main")
}
// 当出现了 panic 时,程序就会终止运行,打印出传入 panic 的参数
panic: runtime error: last name cannot be nil
// 接着打印出堆栈跟踪
goroutine 1 [running]:
main.fullName(0x1040c128, 0x0)
/tmp/sandbox135038844/main.go:12 +0x120
main.main()
/tmp/sandbox135038844/main.go:20 +0x80
package main
import (
"fmt"
)
func fullName(firstName *string, lastName *string) {
defer fmt.Println("deferred call in fullName")
if firstName == nil {
panic("runtime error: first name cannot be nil")
}
if lastName == nil {
panic("runtime error: last name cannot be nil")
}
fmt.Printf("%s %s\n", *firstName, *lastName)
fmt.Println("returned normally from fullName")
}
func main() {
defer fmt.Println("deferred call in main")
firstName := "Elon"
fullName(&firstName, nil)
fmt.Println("returned normally from main")
}
This program prints,
deferred call in fullName
deferred call in main
panic: runtime error: last name cannot be nil
goroutine 1 [running]:
main.fullName(0x1042bf90, 0x0)
/tmp/sandbox060731990/main.go:13 +0x280
main.main()
/tmp/sandbox060731990/main.go:22 +0xc0
package main
import (
"fmt"
)
// recoverName() 函数调用了 recover(),返回了调用 panic 的传参
func recoverName() {
if r := recover(); r!= nil {
fmt.Println("recovered from ", r)
}
}
func fullName(firstName *string, lastName *string) {
// 当 fullName 发生 panic 时,会调用延迟函数 recoverName(),
// 它使用了 recover() 来停止 panic 续发事件。
defer recoverName()
if firstName == nil {
panic("runtime error: first name cannot be nil")
}
if lastName == nil {
panic("runtime error: last name cannot be nil")
}
fmt.Printf("%s %s\n", *firstName, *lastName)
fmt.Println("returned normally from fullName")
}
func main() {
defer fmt.Println("deferred call in main")
firstName := "Elon"
fullName(&firstName, nil)
fmt.Println("returned normally from main")
}
recovered from runtime error: last name cannot be nil
returned normally from main
deferred call in main
package main
import (
"fmt"
"time"
)
func recovery() {
if r := recover(); r != nil {
fmt.Println("recovered:", r)
}
}
func a() {
defer recovery()
fmt.Println("Inside A")
go b() // 不在同一个协程
time.Sleep(1 * time.Second)
}
func b() {
fmt.Println("Inside B")
panic("oh! B panicked")
}
func main() {
a()
fmt.Println("normally returned from main")
}
Inside A
Inside B
panic: oh! B panicked
goroutine 5 [running]:
main.b()
/tmp/sandbox388039916/main.go:23 +0x80
created by main.a
/tmp/sandbox388039916/main.go:17 +0xc0
import (
"fmt"
"runtime/debug"
)
func r() {
if r := recover(); r != nil {
fmt.Println("Recovered", r)
debug.PrintStack()
}
}
func a() {
defer r()
n := []int{5, 7, 4}
fmt.Println(n[3])
fmt.Println("normally returned from a")
}
func main() {
a()
fmt.Println("normally returned from main")
}
// 首先已经恢复了 panic,打印出 Recovered runtime error: index out of range。此外,我们也打印出了堆栈跟踪。在恢复了 panic 之后,还打印出 normally returned from main。
Recovered runtime error: index out of range
goroutine 1 [running]:
runtime/debug.Stack(0x1042beb8, 0x2, 0x2, 0x1c)
/usr/local/go/src/runtime/debug/stack.go:24 +0xc0
runtime/debug.PrintStack()
/usr/local/go/src/runtime/debug/stack.go:16 +0x20
main.r()
/tmp/sandbox949178097/main.go:11 +0xe0
panic(0xf0a80, 0x17cd50)
/usr/local/go/src/runtime/panic.go:491 +0x2c0
main.a()
/tmp/sandbox949178097/main.go:18 +0x80
main.main()
/tmp/sandbox949178097/main.go:23 +0x20
normally returned from main
package main
import "fmt"
func main() {
a := func() {
fmt.Println("Hello wolrd")
}
a()
fmt.Printf("%T", a)
}
Hello wolrd
func()
package main
import (
"fmt"
)
func main() {
func() {
fmt.Println("hello world first class function")
}()
}
package main
import "fmt"
// 创建一个新的函数类型 add, 接收两个整型类型,并返回一个整型
type add func(a int, b int) int
func main() {
var a add = func(a int, b int) int {
return a + b
}
s := a(5, 6)
fmt.Println("Sum", s) // Sum 11
}
package main
import "fmt"
// 函数 simple 接收一个函数参数(该函数接收两个 int 参数,返回一个 a 整型)
func simple(a func(a, b int) int) {
fmt.Println(a(60,7))
}
func main() {
// 创建了一个匿名函数 f,其签名符合 simple 函数的参数
f := func(a, b int) int {
return a + b
}
simple(f) // 67
}
package main
import (
"fmt"
)
// simple 函数返回了一个函数,并接受两个 int 参数,返回一个 int。
func simple() func(a, b int) int {
f := func(a, b int) int {
return a + b
}
return f
}
func main() {
/*
调用了 simple 函数。我们把 simple 的返回值赋值给了 s
调用了 s,并向它传递了两个 int 参数
*/
s := simple()
fmt.Println(s(60, 7)) // 67
}
package main
import "fmt"
func main() {
a := 5
// 访问了变量 a,而 a 存在于函数体的外部。因此这个匿名函数就是闭包。
func() {
fmt.Println("a=",a) // a= 5
}()
}
package main
import (
"fmt"
)
// 函数 appendStr 返回了一个闭包
func appendStr() func(string) string {
t := "Hello"
c := func(b string) string {
t = t + " " + b
return t
}
return c
}
func main() {
a := appendStr()
b := appendStr()
fmt.Println(a("World")) // Hello World
fmt.Println(b("Everyone")) // Hello Everyone
fmt.Println(a("Gopher")) // Hello World Gopher
fmt.Println(b("!")) // Hello Everyone !
}
package main
import (
"fmt"
)
type student struct {
firstName string
lastName string
grade string
country string
}
/*
filter 的第二个参数是一个函数
这个函数接收 student 参数,返回一个 bool 值
*/
func filter(s []student, f func(student) bool) []student {
var r []student
for _, v := range s {
if f(v) == true {
r = append(r, v)
}
}
return r
}
func main() {
s1 := student{
firstName: "Naveen",
lastName: "Ramanathan",
grade: "A",
country: "India",
}
s2 := student{
firstName: "Samuel",
lastName: "Johnson",
grade: "B",
country: "USA",
}
s := []student{s1, s2}
// 这个函数作为参数传递给了 filter 函数
f := filter(s, func(s student) bool {
if s.grade == "B" {
return true
}
return false
})
fmt.Println(f)
}
package main
import (
"fmt"
)
func iMap(s []int, f func(int) int) []int {
var r []int
for _, v := range s {
r = append(r, f(v))
}
return r
}
func main() {
a := []int{5, 6, 7, 8, 9}
r := iMap(a, func(n int) int {
return n * 5
})
fmt.Println(r) // [25 30 35 40 45]
}
// 通用查询生成器,可以适用于任何结构体类型
package main
import (
"fmt"
"reflect"
)
type order struct {
ordId int
customerId int
}
// createQuery 函数接收 interface{} 作为参数
// 程序打印了接口的具体类型和具体值。
func createQuery(q interface{}) {
t := reflect.TypeOf(q) // reflect.TypeOf 接收了参数 interface{},返回了reflect.Type
v := reflect.ValueOf(q) // 返回了 reflect.Value
fmt.Println("Type ", t) // Type main.order
fmt.Println("Value ", v) // Value {456 56}
}
func main() {
o := order{
ordId: 456,
customerId: 56,
}
createQuery(o)
}
package main
import (
"fmt"
"reflect"
)
type order struct {
ordId int
customerId int
}
func createQuery(q interface{}) {
t := reflect.TypeOf(q) // 实际类型main.order
k := t.Kind() // 该类型的特定类别(在这里是 struct)。
fmt.Println("Type ", t) // Type main.order
fmt.Println("Kind ", k) // Kind struct
}
func main() {
o := order{
ordId: 456,
customerId: 56,
}
createQuery(o)
}
package main
import (
"fmt"
"reflect"
)
type order struct {
ordId int
customerId int
}
func createQuery(q interface{}) {
/*
1、判断类型是否是结构体
2、NumField 方法只能在结构体上使用
*/
if reflect.ValueOf(q).Kind() == reflect.Struct {
v := reflect.ValueOf(q)
fmt.Println("Number of fields", v.NumField())
for i := 0; i < v.NumField(); i++ {
fmt.Printf("Field:%d type:%T value:%v\n", i, v.Field(i), v.Field(i))
}
}
}
func main() {
o := order{
ordId: 456,
customerId: 56,
}
createQuery(o)
}
Number of fields 2
Field:0 type:reflect.Value value:456
Field:1 type:reflect.Value value:56
package main
import (
"fmt"
"reflect"
)
func main() {
a := 56
x := reflect.ValueOf(a).Int()
fmt.Printf("type:%T value:%v\n", x, x) // type:int64 value:56
b := "Naveen"
y := reflect.ValueOf(b).String()
fmt.Printf("type:%T value:%v\n", y, y) // type:string value:Naveen
}
package main
import (
"fmt"
"reflect"
)
type order struct {
ordId int
customerId int
}
type employee struct {
name string
id int
address string
salary int
country string
}
func createQuery(q interface{}) {
if reflect.ValueOf(q).Kind() == reflect.Struct {
t := reflect.TypeOf(q).Name()
query := fmt.Sprintf("insert into %s values(", t)
v := reflect.ValueOf(q)
for i := 0; i < v.NumField(); i++ {
switch v.Field(i).Kind() {
case reflect.Int:
if i == 0 {
query = fmt.Sprintf("%s%d", query, v.Field(i).Int())
} else {
query = fmt.Sprintf("%s, %d", query, v.Field(i).Int())
}
case reflect.String:
if i == 0 {
query = fmt.Sprintf("%s\"%s\"", query, v.Field(i).String())
} else {
query = fmt.Sprintf("%s, \"%s\"", query, v.Field(i).String())
}
default:
fmt.Println("Unsupported type")
return
}
}
query = fmt.Sprintf("%s)", query)
fmt.Println(query)
return
}
fmt.Println("unsupported type")
}
func main() {
o := order{
ordId: 456,
customerId: 56,
}
createQuery(o)
e := employee{
name: "Naveen",
id: 565,
address: "Coimbatore",
salary: 90000,
country: "India",
}
createQuery(e)
i := 90
createQuery(i)
}