Golang语法特性总结

打印 上一主题 下一主题

主题 873|帖子 873|积分 2619

1.认识Golang代码特性

  1. package main //1.包含main函数的文件就是一个main包--当前程序的包名
  2. // import "fmt"
  3. // import "time"
  4. import(
  5.         "fmt"
  6.         "time"
  7. )//3.同时包含多个包 4.强制代码风格:函数的 { 一定和函数名在同一行,否则会出现语法错误
  8. //main函数
  9. func main() {
  10.         fmt.Println("hello Go!")
  11.         // fmt.Println("hello Go!"); 2.加不加分号都可以,建议不加分号
  12.         time.Sleep(1 * time.Second)
  13. }
复制代码
2.Golang变量声明的四种方式

  1. package main
  2. import (
  3.         "fmt"
  4. )
  5. func main() {
  6.         //方法一:声明一个变量,不初始化默认是0
  7.         var a int
  8.         fmt.Println("a =",a)
  9.         fmt.Printf("type of a = %T\n",a)
  10.         //方法二:声明一个变量,初始化
  11.         var b int = 100
  12.         fmt.Println("b =",b)
  13.         fmt.Printf("type of b = %T\n",b)
  14.         var bb string = "abcd"
  15.         fmt.Printf("bb = %s,type of bb = %T\n",bb,bb)
  16.         //方法三:在初始化时可以省去数据类型,通过值自动匹配当前的变量的数据类型
  17.         var c = 100
  18.         fmt.Println("c =",c)
  19.         fmt.Printf("type of c = %T\n",c)
  20.         var cc = "abcd"
  21.         fmt.Printf("cc = %s,type of cc = %T\n",cc,cc)
  22.         //方法四:(常用的方法)省去var的关键字,直接:=自动匹配;在声明的变量是全局变量时,方法四是不可用的会报错
  23.         e := 100
  24.         fmt.Println("e =",e)
  25.         fmt.Printf("type of e = %T\n",e)
  26.         ee := "abcd"
  27.         fmt.Printf("ee = %s,type of ee = %T\n",ee,ee)
  28.         eee := 3.14
  29.         fmt.Printf("eee = %s,type of eee = %T\n",eee,eee)
  30.         //声明多个变量
  31.         var xx,yy int = 100,200 //相同数据类型
  32.         fmt.Println("xx =",xx," yy =",yy)
  33.         var mm,nn = 100,"abcd" //不同数据类型
  34.         fmt.Println("mm =",mm," nn =",nn)
  35.         //多行的多变量声明
  36.         var (
  37.                 vv int = 100
  38.                 jj bool = true
  39.         )
  40.         fmt.Println("vv =",vv," jj =",jj)
  41. }
复制代码
3.常量与iota

  1. package main
  2. //const 来定义枚举类型
  3. const (
  4.         //可以在const()添加一个关键字 iota,每行的iota都会累加1,第一行的iota的默认值是0
  5.         BEIJING = iota //iota = 0
  6.         SHANGHAI           //iota = 1
  7.         SHENZHEN            //iota = 2
  8. )
  9. //iota只能出现在const的括号中
  10. const (
  11.         a,b = iota+1,iota+2// 0+1,0+2
  12.         c,d                                   // 1+1,1+2
  13.         e,f                                   // 2+1,2+2
  14.         g,h = iota*2,iota*3// 3*2,3*3
  15.         i,k                                   // 4*2,4*3
  16. )
  17. func main()
  18. {
  19.         //常量-具有只读属性
  20.         const length int = 10
  21.         fmt.Println("length = ",length)
  22.         length = 100 //报错-常量不可更改
  23. }
复制代码
4.Golang多返回值的三种写法 

  1. package main
  2. import "fmt"
  3. func fool(a string,b int) int {
  4.         fmt.Println("a = ",a)
  5.         fmt.Println("b = ",b)
  6.         c := 100
  7.         return c
  8. }
  9. //1.返回多个返回值-匿名
  10. func foo2(a string,b int) (int,int) {
  11.         fmt.Println("a = ",a)
  12.         fmt.Println("b = ",b)
  13.         return 666,777
  14. }
  15. //2.返回多个返回值-有形参名称
  16. func foo3(a string,b int) (r1 int,r2 int) {
  17.         fmt.Println("------------foo3-----------")
  18.         fmt.Println("a = ",a)
  19.         fmt.Println("b = ",b)
  20.         r1 = 1000
  21.         r2 = 2000
  22.         return r1,r2
  23.         //return;  方法3--也可以返回r1,r2
  24. }
  25. func main() {
  26.         c := fool("abc",555)
  27.         fmt.Println("c = ",c)
  28.         ret1,ret2 := foo2("bfr",666)
  29.         fmt.Println("ret1 = ",ret1,"ret2 = ",ret2)
  30.         ret3,ret4 := foo3("grx",777)
  31.         fmt.Println("ret3 = ",ret3,"ret4 = ",ret4)
  32. }
复制代码
5.init函数与import导包


递归式导包直到末了一个包没有依赖包->加载该包全局的常量变量->执行init函数
"主程序开始之前,加载一些配置文件、加载一些数据库的内容、根本环境变量的初始化"
  1. package main
  2. import(
  3.         "GolangStudy/Golang_5/lib1"
  4.         "GolangStudy/Golang_5/lib2"
  5. )
  6. func main(){
  7.         lib1.LibTest()
  8.         lib2.LibTest()
  9. }
复制代码
  1. package lib1
  2. import "fmt"
  3. //API接口
  4. func LibTest() {
  5.         fmt.Println("Lib1Test.....")
  6. }
  7. //init初始化函数
  8. func init() {
  9.         fmt.Println("Lib1init.....")
  10. }
复制代码
  1. package lib2
  2. import "fmt"
  3. //API接口--大写首字母表示对外开放该接口
  4. func LibTest() {
  5.         fmt.Println("Lib2Test.....")
  6. }
  7. //init初始化函数
  8. func init() {
  9.         fmt.Println("Lib2init.....")
  10. }
复制代码
运行结果: 

三种导包的方式:
  1. //三种导包的方式
  2. import(
  3.         _ "GolangStudy/Golang_5/lib1" //_表示匿名,可以在不使用该包但是可以调用它的init函数-无法使用当钱包的方法
  4.         //mylib "GolangStudy/Golang_5/lib2" //给包起别名mylib
  5.         . "GolangStudy/Golang_5/lib2" // . 表示将该包直接导入main包直接使用
  6. )
  7. func main(){
  8.         //lib1.LibTest()
  9.         //lib2.LibTest()
  10.         //mylib.LibTest()
  11.         LibTest()//同名方法容易导致歧义
  12. }
复制代码
6.Golang中指针的利用

  1. package main
  2. import "fmt"
  3. func swap(pa *int, pb *int) {
  4.         var tem int;
  5.         tem = *pa  
  6.         *pa = *pb
  7.         *pb = tem
  8. }
  9. func main() {
  10.         var a int = 10
  11.         var b int = 20
  12.         swap(&a,&b)
  13.         fmt.Println("a = ",a,"b = ",b)
  14.         var p *int
  15.         p = &a
  16.         fmt.Println("p = ",p)
  17.         var pp **int = &p
  18.         fmt.Println("pp = ",pp)
  19. }
复制代码
7.Golang中的defer语句 

  1. package main
  2. import "fmt"
  3. func main(){
  4.         //写入defer关键字--类似C++中的析构函数--出它作用域时会调用
  5.         defer fmt.Println("main end1")//先入栈
  6.         defer fmt.Println("main end2")//再入栈
  7.         fmt.Println("main run1")
  8.         fmt.Println("main run2")
  9. }
复制代码
输出结果: 

defer和return的执行顺序
  1. func deferFunc() int{
  2.         fmt.Println("defer func called...")
  3.         return 0
  4. }
  5. func returnFunc() int{
  6.         fmt.Println("return func called...")
  7.         return 0
  8. }
  9. func rad() int {
  10.         defer deferFunc()
  11.         return returnFunc()
  12. }
  13. func main() {
  14.         rad()
  15. }
复制代码
输出结果: return比defer先执行

8.Golang中的数组

—静态数组
静态数组传参是值拷贝传参,并且只能吸取特定格式的数组确定元素类型与元素个数
  1. package main
  2. import "fmt"
  3. //值拷贝传参,将实参数组拷贝给形参
  4. func printArray(myArray [10]int) { //只能接收1、2即int[10]数据类型
  5.         for index,value:=range myArray {
  6.                 fmt.println(index," ",value)
  7.         }
  8. }
  9. func printArray(myArray [4]int) {  只能接收3即int[4]数据类型
  10.         for index,value:=range myArray {
  11.                 fmt.println(index," ",value)
  12.         }
  13. }
  14. func main(){
  15.         //固定长度的数组
  16.         var myArray1 [10]int
  17.         myArray2 := [10]int{1,2,3,4}
  18.         myArray3 := [4]int{1,2,3,4}
  19.         //for i:= 0; i<10; i++
  20.         for i:=0; i<len(myArray1); i++{
  21.                 fmt.println(myArray1[i])
  22.         }
  23.         for index,value:=range myArray1 {
  24.                 fmt.println(index," ",value)
  25.         }
  26.         //查看数组的数据类型
  27.         fmt.printf("myArray1 types = %T\n",myArray1)
  28.         fmt.printf("myArray2 types = %T\n",myArray2)
  29.         fmt.printf("myArray3 types = %T\n",myArray3)
  30. }
复制代码
—动态数组(slice切片)
  1. package main
  2. import "fmt"
  3. //动态数组具有传参上的优势
  4. //传递的是当前数组的指针首地址,引用传递
  5. func printArray(myArray []int) {
  6.         // _ 表示匿名的变量
  7.         for _, value := range myArray {//不关心下标,但必须用两个接收
  8.                 fmt.Println("value = ",value)
  9.         }
  10.         myArray[0] = 100
  11. }
  12. func main() {
  13.         myArray := []int{1,2,3,4} //动态数组,切片 slice
  14.         fmt.Printf("myArray type is %T\n",myArray)//输出:myArray type is []int
  15.         printArray(myArray)
  16.         for _, value := range myArray {
  17.                 fmt.Println("value = ",value)
  18.         }
  19. }
复制代码
—四种声明一个切片的方式 
  1. func main () {
  2.         //声明slice是一个切片,并且初始化,默认值是1,2,3;长度len是3
  3.         slice := []int{1,2,3}
  4.        
  5.         //声明slice1是一个切片,但没有给它分配空间
  6.         var slice1 []int  //此时长度就是0
  7.         slice1 = make([]int,3)//通过make给slice1分配空间,默认值是0
  8.         //声明slice2是一个切片,同时通过make给slice2分配空间,默认值是0
  9.         var slice2 []int = make([]int,3)
  10.         //声明slice3是一个切片,同时分配空间,通过:=推导出slice是一个切片
  11.         slice := make([]int,3)
  12.         fmt.Printf("len = %d,slice = %v\n",len(slice1),slice1)
  13.         //判断一个slice是否为0
  14.         if slice == nil {
  15.                 fmt.printf("slice是一个空切片")
  16.         }else{
  17.                 fmt.printf("slice不是一个空切片")
  18.         }
  19. }
复制代码
—切片容量的追加 
  1. func main () {
  2.         var numbers = make([]int,3,5)//开辟五个空间只初始化3个为0
  3.         fmt.Printf("len = %d,cap = %d,numbers = %v\n",len(numbers),cap(numbers),numbers)
  4.         //向numbers切片追加一个1
  5.         numbers = append(numbers,1)
  6.         fmt.Printf("len = %d,cap = %d,numbers = %v\n",len(numbers),cap(numbers),numbers)
  7.         numbers = append(numbers,2)
  8.         fmt.Printf("len = %d,cap = %d,numbers = %v\n",len(numbers),cap(numbers),numbers)
  9.         numbers = append(numbers,3)//会进行2倍扩容
  10.         fmt.Printf("len = %d,cap = %d,numbers = %v\n",len(numbers),cap(numbers),numbers)
  11.         var numbers2 = make([]int,3)//开辟三个空间并全部初始化为0
  12.         fmt.Printf("len = %d,cap = %d,numbers2 = %v\n",len(numbers2),cap(numbers2),numbers2)
  13.         numbers2 = append(numbers2,1)//会进行2倍扩容
  14.         fmt.Printf("len = %d,cap = %d,numbers2 = %v\n",len(numbers2),cap(numbers2),numbers2)
  15. }
复制代码
 输出结果:

—切片的截取
  1. func main () {
  2.         s := []int{1,2,3} //len=3,cap=3
  3.         //[0,2)
  4.         s1 := s[0:2] //取1和2,前面省略表示从第0个开始取,后面省略表示取到最后一个
  5.         fmt.Println(s1)
  6.        
  7.         s1[0] = 100
  8.         fmt.Println(s1) //s1此时也指向s的第一个,相当于浅拷贝
  9.         fmt.Println(s)
  10.         //copy深拷贝,将底层数组的slice一起进行拷贝
  11.         s2 := make([]int,2) //s2 = [0,0,0]
  12.         copy(s2,s1)
  13.         fmt.Println(s2) //可以先将s切片成s1,再进行深拷贝给s2,就可以分离
  14. }
复制代码
9.Golang中基于哈希的Map

—Map的三种声明界说方式 
  1. func main() {
  2.         //第一种声明方式
  3.         var myMap1 map[string]string //仅仅是声明,没有实际的空间,并不能被使用
  4.         if myMap1 == nil {
  5.                 fmt.Println("myMap1是一个空map")
  6.         }
  7.         myMap1 = make(map[string]string,10) //用make给Map开辟十个键值对的空间
  8.         myMap1["one"] = "java"
  9.         myMap1["two"] = "C++"
  10.         myMap1["three"] = "python"
  11.         //...当插入十个之后也会二倍扩容
  12.         fmt.Println(myMap1)//打印出来是无序的
  13.         //第二种声明方式
  14.         myMap2 := make(map[int]string)
  15.         myMap2[1] = "java"
  16.         myMap2[2] = "C++"
  17.         myMap2[3] = "python"
  18.         fmt.Println(myMap2)
  19.         //第三种声明方式
  20.         myMap3 := map[int]string {
  21.                 4 : "java",
  22.                 5 : "C++",
  23.                 6 : "python",
  24.         }
  25.         fmt.Println(myMap3)
  26. }
复制代码
—Map的根本利用 
  1. func printMap(cityMap map[string]string) {
  2.         for key,value := range cityMap {
  3.                 fmt.Printf("key = %s ",key)
  4.                 fmt.Printf("value = %s\n",value)
  5.         }
  6.         cityMap["one"] = "golang"
  7. }
  8. //指向当前map内存结构体地址的指针cityMap
  9. func main() {
  10.         cityMap := make(map[string]string,3)
  11.         //添加
  12.         cityMap["one"] = "java"
  13.         cityMap["two"] = "C++"
  14.         cityMap["three"] = "python"
  15.         //删除
  16.         delete(cityMap,"three")
  17.         //修改
  18.         cityMap["two"] = "php"
  19.         //传参
  20.         printMap(cityMap)
  21.         //遍历
  22.         for key,value := range cityMap {
  23.                 fmt.Printf("key = %s ",key)
  24.                 fmt.Printf("value = %s\n",value)
  25.         }
  26. }
  27. //将一个map赋值给另一个时只能完成指针之间的浅拷贝,只能通过make开辟一个Map进行遍历赋值
复制代码
10.struct(类)的界说和利用 

—struct类的界说
  1. //声明一种行的数据类型,是Int的一个别名
  2. type myint int
  3. type Book struct {
  4.         title string
  5.         auth string
  6. }
  7. func changeBook(book Book) {
  8.         //传递book的一个副本
  9.         book.auth = "666"
  10. }
  11. func changeBook2(book *Book) {
  12.         //传递指向Book结构体的指针
  13.         book.auth = "777"
  14. }
  15. func main() {
  16.         // var a myint = 10
  17.         // fmt.Printf("type = %T",a)
  18.         var book1 Book
  19.         book1.title = "Golang"
  20.         book1.auth = "zhang3"
  21.         fmt.Printf("book1 = %v",book1)
  22. }
复制代码
—类的封装和方法的调用
  1. //go语言中的类实际上是通过结构体来绑定方法
  2. package main
  3. //方法名、类名如果首字母大写,其它包也可以访问
  4. type Hero struct {
  5.         Name string
  6.         Ad int
  7.         Level int
  8. }
  9. //当前括号表示该方法绑定到了Hero结构体,this表示调用对象,谁调用该方法this就指哪个对象
  10. func (this Hero) GetName() string{
  11.         return this.Name
  12. }
  13. //this是当前调用对象的一个副本
  14. func (this Hero) SetName(newName string) {
  15.         this.Name = newName
  16. }
  17. //此时this就是指向当前对象的指针,就可以修改了
  18. func (this *Hero) SetName(newName string) {
  19.         this.Name = newName
  20. }
  21. func main() {
  22.         //创建一个对象
  23.         hero := Hero{Name: "zhang3",Ad: 100,Level: 1}
  24. }
复制代码
—继承的根本语法 
  1. type Human struct {
  2.         name string
  3.         sex string
  4. }
  5. func (this *Human) Eat() {
  6.         fmt.Println("human Eat().....")
  7. }
  8. func (this *Human) Walk() {
  9.         fmt.Println("human Walk().....")
  10. }
  11. type SuperMan struct {//Go中实际是以组合的形式实现继承
  12.         Human //Superman继承了Human类的所有方法
  13.         level int
  14. }
  15. //重写(覆盖)父类方法
  16. func (this *SuperMan) Eat() {
  17.         fmt.Println("SuperMan Eat().....")
  18. }
  19. //子类的新方法
  20. func (this *SuperMan) Fly() {
  21.         fmt.Println("SuperMan Fly().....")
  22. }
  23. func main() {
  24.         h := Human{"zhang3","female"}
  25.         h.Eat()
  26.         h.Walk
  27.         s := SuperMan{Human{"li4","female"},88}
  28.         // var s SuperMan
  29.         // s.name = "li4"//...
  30.         s.Walk() //子类调用父类的方法
  31.         s.Eat() //子类调用子类重写的方法
  32.         s.Fly() //子类调用子类的新方法
  33. }
复制代码
—interface实现多态 
  1. package main
  2. //面向对象的多态:定义一个接口完成多态的现象;接口定义抽象方法,子类去继承实现重写这个方法
  3. //interface本质上是一个指针,指向当前类型包含的函数列表
  4. type AnimalIF interface {
  5.         Sleep()
  6.         GetColor() string //获取动物的颜色
  7.         GetType() string //获取动物的类型
  8. }
  9. //具体的值--要继承AnimalIF interface只需要将他的三个方法实现,不需要显式继承
  10. type Cat struct {
  11.         color string //猫的颜色
  12. }
  13. func (this *Cat) Sleep() {
  14.         fmt.Println("cat is sleep")
  15. }
  16. func (this *Cat) GetColor() string {
  17.         return this.color
  18. }
  19. func (this *Cat) GetType() string {
  20.         return "cat"
  21. }
  22. //具体的值--狗
  23. type Dog struct {
  24.         color string
  25. }
  26. func (this *Dog) Sleep() {
  27.         fmt.Println("Dog is sleep")
  28. }
  29. func (this *Dog) GetColor() string {
  30.         return this.color
  31. }
  32. func (this *Dog) GetType() string {
  33.         return "Dog"
  34. }
  35. func showAnimal(animal AnimalIF)//调用该函数,形参为父类指针,实参为子类对象实现多态
  36. {
  37.         animal.Sleep()
  38. }
  39. func main() {
  40.         // var animal AnimalIF //接口的数据类型,相当于定义了一个父类指针
  41.         // animal = &Cat("green") //让父类的指针指向一个子类对象
  42.         // animal.Sleep() //指向子类对象的父类指针调用子类方法实现多态
  43.         cat := Cat("green")
  44.         dog := Dog("yellow")
  45.         showAnimal()
  46. }
复制代码
—interface{}空接口万能类型
  1. //interface{} 空接口,万能类型-》可以引用任意数据类型
  2. package main
  3. import "fmt"
  4. func myFunc(arg interface{}) { //可以传任意类型的实参
  5.         fmt.Println("myFunc is called..")
  6.         fmt.Println(arg)
  7.         //类型断言
  8.         value,ok := arg.(string) //value是数据值,ok是error
  9.         if !ok {
  10.                 fmt.Println("arg is not a string")
  11.         }else{
  12.                 fmt.Println("arg is a string")
  13.         }
  14.         fmt.Println(value)
  15. }
  16. type Book struct {
  17.         auth string
  18. }
  19. func main() {
  20.         book := Book{"Golang"}
  21.         myFunc(book)
  22.         myFunc("abcd")
  23.         myFunc(888)
  24.         myFunc(23.45)
  25. }
复制代码
11.Golang中反射的概念

—接口type interface { }的类型
Golang中一个变量包含一个pair即type和value对。
type分为static type(在编译时就确定并且不会改变)和concrete type(在运行时确定并且会改变)。
  1. var i int           // static type 为 int;
  2. var i interface{}   // pair()
  3. i = 18             // concrete type 为 int
  4. i = "Go编程时光"   // concrete type 变为 string
复制代码
  1. type Reader interface {
  2.         ReadBook()
  3. }
  4. type Writer interface {
  5.         WriteBook()
  6. }
  7. //具体类型
  8. type Book struct {
  9. }
  10. func (this *Book) ReadBook() {
  11.         fmt.Println("Read a book.")
  12. }
  13. func (this *Book) WriteBook() {
  14.         fmt.Println("Write a book.")
  15. }
  16. func main() {
  17.         b := &Book{}  //type:*Book  value:0xc000012028
  18.         var r Reader  //concrete type:nil,static type:Reader  value:nil
  19.         r = b         //concrete type:Book*,static type Reader  value:0xc000012028
  20.         r.ReadBook()  //Reader - Book* 多态
  21.         var w Writer  //concrete type:nil,static type:Writer  value:nil
  22.         w = r.(Writer)//类型断言,检查r是否实现了Writer,并将Book*给w
  23.         w.WriteBook()
  24. }
复制代码
—reflect.ValueOf 和 reflect.TypeOf
 
  1. package main
  2. import "fmt"
  3. import "reflect"
  4. type User struct {
  5.         Id int//一个filed
  6.         Name string//第二个filed
  7.         Age int                //第三个filed
  8. }
  9. func (this *User) Call() {
  10.         fmt.Println("User is called ...")
  11.         fmt.Println("%v\n",this)
  12. }
  13. func main() {
  14.         user := User{1,"bfr",18}
  15.         DoF(user)
  16. }
  17. func DoF(input interface{}) {
  18.         //获取input的type
  19.         inputType := reflect.TypeOf(input)
  20.         fmt.Println("inputType :",inputType.Name())//?直接打印出当前类型的名称?
  21.         //获取input的value
  22.         inputValue := reflect.ValueOf(input)
  23.         fmt.Println("inputValue :",inputValue)
  24.         //通过type获取里面重要字段
  25.         //通过inputType可以获取NumFiled,进行遍历,就能得到每个filed
  26.         for i := 0;i < inputType.NumField(); i++ {
  27.                 field := inputType.Field(i)
  28.                 value := inputValue.Field(i).Interface()//?获取字段的值
  29.                 fmt.Printf("%s: %v = %v\n",field.Name,field.Type,value)//ID,int,1
  30.         }
  31.         //通过Type获取里面的方法,调用
  32.         for i:=0; i<inputType.NumMethod(); i++ { //遍历User有多少个方法
  33.                 m := inputType.Method(i)
  34.                 fmt.Printf("%s: %v\n",m.Name,m.Type)
  35.         }
  36. }
复制代码

12.结构体标签 

  1. package main
  2. import "fmt"
  3. import "reflect"
  4. //在不同包中有不同的解释说明
  5. type resume struct {
  6.         Name string `info:"name" doc:"我的名字"`
  7.         Sex string `info:"sex"`
  8. }
  9. func findTag(str interface{}) {
  10.         t := reflect.TypeOf(str).Elem()//Elem当前结构体的全部元素
  11.         for i := 0; i < t.NumField(); i++ {
  12.                 taginfo := t.Field(i).Tag.Get("info")
  13.                 tagdoc := t.Field(i).Tag.Get("doc")
  14.                 fmt.Println("info: ",taginfo," dac:",tagdoc)
  15.         }
  16. }
  17. func main() {
  18.         var res resume
  19.         findTag(&res)
  20. }
复制代码
  1. //结构体标签-key已知,value未知
  2. type Movie struct {
  3.         Title string `json:"title"` //在json中显示的字段
  4.         Year int        `json:"year"`
  5.         Price int        `json:"price"`
  6.         Actors []string  `json:"actors"`
  7. }
  8. func main() {
  9.         movie := Movie{"喜剧之王",2000,10,[]string{"xingye","zbz"}}
  10.        
  11.         //编码的过程 将结构体->json
  12.         jsonStr,err := json.Marshal(movie)//Marshal可以将结构体转化为json格式
  13.         if err != nil {
  14.                 fmt.Println("json marshal error",err)
  15.         }else{
  16.                 fmt.Printf("josnStr = %s\n",jsonStr)
  17.         }
  18.         //解码的过程 json->结构体
  19.         myMovie := Movie{}
  20.         err = json.Unmarshal(jsonStr,&myMovie)//将json字符串解析给myMovie结构体
  21.         if err != nil {
  22.                 fmt.Println("json unmarshal error",err)
  23.                 return
  24.         }
  25. }
复制代码
13.Golang中的协程:goroutine

—协程的演变发展
—单进程的操纵系统只能顺序执行任务,一旦某个任务壅闭,别的任务都不能处置惩罚。
—多进程/多线程解决了,CPU调度器进行轮询调度切换进程/线程 ,当某个时间片到了就会切换。但是进程/线程间切换具有成本,一旦数量过大,CPU的利用服从就会大大降低。进程占4GB左右,线程占用4MB左右,也有高内存占用的毛病。

—将一个线程拆分,一半在用户层面供用户调用(协程:co-routine),一半在内核层供CPU调度。
    —N : 1,如果有一个协程壅闭,那它的下一个协程就会受到影响。操纵系统感知不到用户级协程的存在,无法将壅闭的协程与线程分离,线程资源被完全占用‌
    —M : N,利用多核,一个CPU绑定多个线程;解决了某个协程壅闭影响别的协程的问题;通过优化写成调度器优化服从,CPU不做调度。

—Golang对协程的处置惩罚
co-routine -> goroutine;将占用内存优化到KB单元(可以大量生产),(可以机动调度)。
   —通过优化调度器实现机动调度


  1. package main
  2. import "fmt"
  3. import "time"
  4. func newTask() {
  5.         i:=0
  6.         for {
  7.                 i++
  8.                 fmt.Printf("new Goroutine : i = %d\n",i)
  9.                 time.Sleep(1 * time.Second)
  10.         }
  11. }
  12. func main() {
  13.         //创建一个go程 去执行newTask()流程
  14.         go newTask()
  15.         time.Sleep(10*time.Second)
  16.         fmt.Println("main goroutine exit")
  17.         // i:=0
  18.         // for { //死循环main
  19.         //         i++
  20.         //         fmt.Printf("main goruntine: i = %d\n",i)
  21.         //         time.Sleep(1*time.Second)
  22.         // }
  23. }
复制代码
  1. package main
  2. import "fmt"
  3. import "time"
  4. import "runtime"
  5. func main() {
  6.         //调匿名无参goroutine
  7.         go func() {//匿名方法,直接用Go承载一个形参为空返回值为空的一个函数
  8.                 defer fmt.Println("A.defer")
  9.                 func() {//仅仅是函数定义
  10.                         defer fmt.Println("B.defer")
  11.                         //return
  12.                         runtime.Goexit()
  13.                         fmt.Println("B")
  14.                 }()
  15.                 fmt.Println("A")
  16.         }()//调用
  17.         //调匿名有参goroutine
  18.         go func(a int,b int) bool { //并不是阻塞操作,是一个异步操作,不能拿到返回值
  19.                 fmt.Println("a = ",a," b = ",b)
  20.                 return true
  21.         }(10,20)
  22.         time.Sleep(1*time.Second)
  23. }
复制代码
 14.channel-go语言中协程间通讯的机制

—构成死锁:
1.无缓存channel、只写不读或只读不写、导致主线程壅闭。
2.有缓存channel、已满只写不读或为空只读不写、导致主线程壅闭。
  1. package main
  2. import "fmt"
  3. //import "time"
  4. func main() {
  5.         c := make(chan int,3)//带有缓冲的channel
  6.         fmt.Println("len(c) = ",len(c)," cap(c) = ",cap(c))
  7.         go func() {
  8.                 defer fmt.Println("子go程结束")
  9.                 for i:=0;i<6;i++{
  10.                         c <- i
  11.                         fmt.Println("running...:","i = ",i," len(c) = ",len(c)," cap(c) = ",cap(c))
  12.                 }
  13.         }()
  14.         //time.Sleep(2 * time.Second)
  15.         // for i:=0;i<2;i++ {
  16.         //         num := <-c //从c中接收数据,并赋值给num
  17.         //         fmt.Println("num =",num)
  18.         // }
  19.        
  20.         fmt.Println("main 结束")
  21. }
复制代码
—close关闭channel 
关闭channel后,无法向channel再发送数据(再发会引发 panic 错误后导致吸取立刻返回零值)
关闭channel后,仍旧具有缓存,等读端读完了才会返回。
简朴var声明一个channel数据类型,没有进行make,称为nil channel。无论收发都会壅闭。
  1. package main
  2. import "fmt"
  3. func main() {
  4.         c := make(chan int)
  5.         go func() {
  6.                 for i:=0;i<5;i++ {
  7.                         c <- i
  8.                 }
  9.                 //close可以关闭一个channel
  10.                 close(c)
  11.         }()
  12.         for {
  13.                 //ok=true表示channel没有关闭
  14.                 if data,ok := <-c; ok { //原子性操作‌:确保通道接收与状态检查在同一个代码块中完成
  15.                         fmt.Println(data)
  16.                 }else{
  17.                         break
  18.                 }
  19.         }
  20.         fmt.Println("Main Finished..")
  21. }
复制代码
—channel 和 range 
实验从c中读数据,range会壅闭等待这个结果;c中有数据range就会返回并进入本轮for循环,没有数据就会壅闭
  1. //可以使用range来迭代不断操作channel
  2. for data := range c {
  3.                 fmt.Println(data)
  4.         }
复制代码
—channel 和 select
单流体下的一个go只能监视一个channel状态,壅闭监听,select可以解决一个go监听多个channel状态,如果某个channel可读或可写它就会立刻返回。一般会循环进行select监控多个channel。
  1. package main
  2. import "fmt"
  3. func fibo(c,quit chan int){
  4.         x,y := 1,1         //1,1->1; 1,2->1;
  5.         for{
  6.                 select{
  7.                 case c <- x: //只要func可读这边就可写
  8.                         //如果c可写,则该case就会进来
  9.                         t := x
  10.                         x = y
  11.                         y = t+y
  12.                 case <-quit: //只要quit被写入这边就可读就退出
  13.                         fmt.Println("quit")
  14.                         return
  15.                 }
  16.         }
  17. }
  18. func main() {
  19.         c := make(chan int)
  20.         quit := make(chan int)
  21.         go func() {
  22.                 for i := 0; i < 6; i++{
  23.                         fmt.Println(<-c)//读c
  24.                 }
  25.                 quit <- 0 //循环结束退出
  26.         }()
  27.         //main go
  28.         fibo(c,quit)
  29. }
复制代码
 


 






免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

兜兜零元

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表