GoLang学习 Golang的优势 极简单的部署方式 静态类型语言 语言层面的并发 强大的标准库 简单易学 第一个go程序 变量 函数 defer slice切片 map 面向对象特征 结构体struct class封装 继承 多态 万能数据类型 反射
Golang的优势
极简单的部署方式
静态类型语言
语言层面的并发
强大的标准库
runtime系统调度机制 高效的GC垃圾回收 丰富的标准库
简单易学
25个关键字 C语言简洁基因,内嵌C语法支持 面向对象特征(继承、多态、封装) 跨平台
第一个go程序
嗨嗨嗨,依旧是经典的hello world 注意:在go里面,函数的{一定是和函数名在同一行的,否则会编译错误
package mainimport "fmt" func main ( ) { fmt. Printf ( "hello world" )
}
变量
变量的声明
一共有四种变量的声明方式: 声明一个变量,默认的值是0 声明一个变量并初始化 在初始化的时候可以省去数据类型,通过值自动匹配当前的变量的数据类型 省去var关键字 — 只能用在函数内部,不能用来声明全局变量
package mainimport "fmt" func main ( ) { var a int fmt. Printf ( "a=%d\n" , a) var b int = 10 fmt. Printf ( "b=%d\n" , b) var c = 100 fmt. Printf ( "c=%d,%T\n" , c, c) e := 100 fmt. Println ( e) fmt. Printf ( "e=%d,%T\n" , e, e) var x1, x2 int = 100 , 200 fmt. Printf ( "x1=%d,x2=%d\n" , x1, x2) var ( y1 int = 1000 y2 int = 2000 ) fmt. Printf ( "y1=%d,y2=%d\n" , y1, y2)
}
常量
使用const进行声明,具有只读属性 可以在const()中添加一个关键字iota,每行的iota都会累加1,第一行的iota的默认值是0 iota只能配合const()一起使用,iota只有在const进行累加效果
package mainimport "fmt"
const ( Up = iota DownLeftRight
) func main ( ) { const length int = 100 fmt. Println ( "length=" , length) fmt. Println ( "Up=" , Up) fmt. Println ( "Down=" , Down) fmt. Println ( "Left=" , Left) fmt. Println ( "Right=" , Right)
}
函数
多返回值
可以分为两种,返回值是匿名 的和返回值是具名 的 有形参名称的(具名)他们的作用域是这个函数体内部
package mainimport "fmt"
func getSumAndSub ( a int , b int ) ( int , int ) { sum := a + bsub := a - breturn sum, sub
}
func getSumAndSub2 ( a int , b int ) ( sum int , sub int ) { sum = a + bsub = a - breturn
} func main ( ) { res1, res2 := getSumAndSub ( 10 , 5 ) fmt. Println ( "res1=" , res1) fmt. Println ( "res2=" , res2) res3, res4 := getSumAndSub2 ( 10 , 5 ) fmt. Println ( "res3=" , res3) fmt. Println ( "res4=" , res4)
}
init函数与import导包
import导包: import _ "fmt":给fmt包起一个别名,匿名,无法使用当前包的方法,但是会执行当前的包内部的init方法import bb "fmt":给fmt包起一个别名—bb,bb.Println()可以直接调用import . "fmt":将当前的fmt包中的全部方法,导入到当前本包的作用域中,fmt包中的全部方法可以直接使用API来调用,不需要fmt.API来调用 目录结构如图 lib1
package lib1import "fmt" func Lib1Test ( ) { fmt. Println ( "lib1Test ..." )
} func init ( ) { fmt. Println ( "lib1 init ..." )
}
package lib2import "fmt" func Lib2Test ( ) { fmt. Println ( "lib2Test ..." )
} func init ( ) { fmt. Println ( "lib2 init ..." )
}
package mainimport ( "5-init/lib1" "5-init/lib2" "fmt"
) func main ( ) { fmt. Println ( "main ..." ) lib1. Lib1Test ( ) lib2. Lib2Test ( )
}
运行结果如图
defer
在 Go 语言里,defer 就像一个“延迟执行的小秘书”:它把任务(函数或语句)压进栈里,等当前函数即将返回前 才按后进先出 的顺序统一执行,无论函数是正常结束还是 panic 崩溃都要先处理完这些“遗愿”。因此它最常用来做资源清理(关闭文件、解锁互斥量、释放锁等),保证成对操作 绝不遗漏,代码也更简洁直观。
package mainimport "fmt" func main ( ) { defer fmt. Println ( "main end" ) fmt. Println ( "main start" ) fmt. Println ( "main middle" )
}
defer和return谁先谁后
return之后的语句先执行,defer之后的语句后执行
slice切片
创建的数组为动态数组 并且函数中传递的参数也为引用传递 ,而且不同元素长度的动态数组他们的形参是一致的
package mainimport "fmt" func printArray ( array [ ] int ) { for _ , value := range array { fmt. Println ( "value=" , value) } array[ 0 ] = 1000
} func main ( ) { myArray := [ ] int { 1 , 2 , 3 , 4 } printArray ( myArray) fmt. Println ( "-------" ) for i := 0 ; i < len ( myArray) ; i++ { fmt. Println ( myArray[ i] ) }
}
声明方式
slice1 := []int{1,2,3}:声明slice1是一个切片,并且初始化,默认值是1,2,3,长度len是3var slice1 []int + slice1 = make([]int,3):声明slice1是一个切片,但是并没有给slice分配空间var slice1 []int = make([]int,3):声明slice1是一个切片,同时给slice分配空间,3个空间,初始化值为0
使用方式
切片容量的追加
len和cap:切片的长度和容量不同,长度表示左指针至右指针之间的距离,容量表示左指针至底层数组末尾的距离切片的扩容机制:append的时候,如果长度增加后超过了容量,则将容量增加2倍
package mainimport "fmt" func main ( ) { var numbers = make ( [ ] int , 3 , 5 ) fmt. Println ( len ( numbers) , cap ( numbers) , numbers) numbers = append ( numbers, 2 ) fmt. Println ( len ( numbers) , cap ( numbers) , numbers) numbers = append ( numbers, 3 ) fmt. Println ( len ( numbers) , cap ( numbers) , numbers) numbers = append ( numbers, 4 ) fmt. Println ( len ( numbers) , cap ( numbers) , numbers) }
输出结果
切片的拷贝
map
三种声明方式
var myMap1 map [ string ] string if myMap1 == nil { fmt. Println ( "myMap1是一个空map" ) } myMap1 = make ( map [ string ] string , 10 ) myMap1[ "one" ] = "java" myMap1[ "two" ] = "c++" myMap1[ "three" ] = "python" fmt. Println ( myMap1)
myMap2 := make ( map [ int ] string ) myMap2[ 1 ] = "java" myMap2[ 2 ] = "js" myMap2[ 3 ] = "go" fmt. Println ( myMap2)
myMap3 := map [ string ] string { "one" : "php" , "two" : "c++" , "three" : "python" , } fmt. Println ( myMap3)
使用方式
package mainimport "fmt" func main ( ) { studentMap := make ( map [ int ] string ) studentMap[ 1 ] = "熊大" studentMap[ 2 ] = "熊二" studentMap[ 3 ] = "光头强" for key, value := range studentMap { fmt. Println ( key, value) } delete ( studentMap, 3 ) studentMap[ 2 ] = "吉吉" fmt. Println ( "------------" ) for key, value := range studentMap { fmt. Println ( key, value) }
}
输出结果
面向对象特征
结构体struct
package mainimport "fmt"
type myint int
type Book struct { title string auth string price int
} func main ( ) { var a myint = 10 fmt. Printf ( "a=%d,%T\n" , a, a) var b1 Bookb1. auth = "miraculous" b1. price = 99 b1. title = "go_learn" fmt. Println ( b1)
}
class封装
类名、属性名、方法名首字母大写表示对外(其他包)可以访问,否则只能够在本包内访问
package mainimport "fmt"
type Student struct { name string age int
}
func ( this * Student) Show ( ) { fmt. Println ( this. age, this. name)
} func ( this * Student) GetName ( ) { fmt. Println ( this. name)
} func ( this * Student) SetName ( newName string ) { this. name = newName
} func main ( ) { s1 := Student{ name: "熊大" , age: 10 } s1. Show ( ) s1. SetName ( "光头强" ) s1. Show ( ) }
输出结果
继承
package mainimport "fmt" type Human struct { name string age int
} func ( this * Human) Walk ( ) { fmt. Println ( "Human Walk ..." )
} func ( this * Human) Eat ( ) { fmt. Println ( "Human Eat ..." )
}
type SuperMan struct { Human level int
}
func ( this * SuperMan) Eat ( ) { fmt. Println ( "SuperMan Eat ..." )
}
func ( this * SuperMan) Fly ( ) { fmt. Println ( "SuperMan fly ..." )
} func main ( ) { h1 := Human{ "zhangsan" , 18 } fmt. Println ( h1) h1. Eat ( ) h1. Walk ( ) var sh1 SuperMansh1. name = "熊大" sh1. age = 10 sh1. level = 100 sh1. Eat ( ) sh1. Walk ( ) sh1. Fly ( )
}
运行结果
多态
多态就是“同一接口,不同实现 ”:代码里只写一次调用,运行时才根据对象的实际类型决定具体干什么,就像同一颗遥控器按钮,遥控电视就换台,遥控音响就切歌,调用者无需关心细节,只管发出指令。 特点: 有一个父类(有接口) 有子类(实现了父类的全部接口方法) 父类类型的变量(指针)指向(引用)子类的具体数据变量 示例代码
package mainimport "fmt"
type AnimalIF interface { Sleep ( ) GetColor ( ) string GetType ( ) string
}
type Cat struct { color string
} type Dog struct { color string
} func ( this * Cat) Sleep ( ) { fmt. Println ( "Cat is sleeping" )
} func ( this * Cat) GetColor ( ) string { return this. color
} func ( this * Cat) GetType ( ) string { return "Cat"
} func ( this * Dog) Sleep ( ) { fmt. Println ( "Dog is sleeping" )
} func ( this * Dog) GetColor ( ) string { return this. color
} func ( this * Dog) GetType ( ) string { return "Dog"
}
func showAnimal ( animal AnimalIF) { animal. Sleep ( ) fmt. Println ( "color=" , animal. GetColor ( ) ) fmt. Println ( "kind=" , animal. GetType ( ) )
} func main ( ) { cat := Cat{ "Green" } dog := Dog{ "Yellow" } showAnimal ( & cat) showAnimal ( & dog)
}
运行效果
万能数据类型
interface{}是万能数据类型那么interface{}应该如何区分此时引用的底层数据类型是什么?----- 类型断言
反射
反射(Reflection)是一种语言级元编程机制,允许运行中的程序以自描述方式查询、访问并修改自身结构 ——包括类型信息、字段、方法、接口、标签等——而无需在编译期显式知晓这些成员的名称与签名;凭借该能力,程序可在执行期动态实例化任意类型、调用任意函数、读写私有状态,实现依赖注入、序列化、动态代理、框架级配置解析等高阶功能。