go语言基础

拈花ヽ惹草 提交于 2019-11-27 19:03:09

GO语言

优点:

  1. 编译速度快
  2. 运行效率直逼C语言
  3. 简单
  4. 并发牛逼到没有朋
/*
Docker Codis Glow 类似于Hadoop  Cockroach(蟑螂)
*/
package main 
import "fmt"
func main() //入口函数 {
    
    fmt.Println("Hello World")
    
}

golang语言特性

1.垃圾回收
a 内存自动回收,再也不需要开发人员管理内存
b 开发人员专注业务实现,降低了心智负担
c 只需要new分配内存,不需要释放

2.天然并发特性
a 从语言层面支持并发,非常简单
b goroute 轻量级线程,创建成千上万个goroute成为可能
c 基于CSP(通信序列进程)模型实现

3. channel(管道)
 a 管道,类似于unix/Linux中的pipe
 b 多个goroute之间通过channel进行通信
 c 支持任何类型
    
package main

import "fmt"

func main() {
    pipe := make(chan int,3) //make 作用类似于new关键字
    pipe <- 1
    pipe <- 2
    pipe <- 3
fmt.Println(len(pipe))
}
   
    
4.多返回值
 a 一个函数返回多个值
  package main
  import "fmt"
 func calc(a int,b int)(int,int){
     sum := a+b
     avg := (a+b)/2
     return sum,avg}
func main(){
    a,b := calc(10,20)
    fmt.Println(a,b)
}

包的概念

1、和python一样,把相同功能的代码放到一个目录,称之为包
2、包可以被其他包所引用
3、main包是用来生成可执行文件,每个程序只有一个main()包
4、包的主要用途是提高代码的可复用性。 

go语言基础

关键字:break default func interface select 
       case defer go map struct chan else
       goto  package switch const fallthrough if 
       range type continue for inport return var

go程序是通过package来组织的
main()函数是每一个独立函数的可运行程序的入口点

var:
   var关键字是go最基本的定义变量方式,与c语言不同的是go把变量类型放在变量名后面:
   var name string
   var age int
   var price float

简短声明 :=(注意:简短声明不能用于函数体之外,只能用于函数体之内)
e.g 
v1,v2,v3 := 10,20,30
name:= "江西理工大学" 

const 常量:
eg: const Pi int  = 314
    const hello string = "China"

数据类型

bool 
int int8 int16 int32 int64
float32 float64
complex64  complex128
string 
array  就是数组 var arr [n]type
slice  是go的动态数组(切片)  var fslice []int || s := make([]int,10,20) || 常用x := 
map

/*
package main
import "fmt"
func main() {
    x := [10] int{1,2,3,4,5,6,7,8}  // 定义数组
    y := x[1:3]  // 切片
    fmt.Println(x) // [1 2 3 4 5 6 7 8 0 0]
    fmt.Println(y) // [2 3]
}

*/

import "fmt"

func main() {
    y := make([]int,3,5) //产生一个切片 ,5表示容量,长度为3,make生成内存空间
    fmt.Println(len(y),y) 3,[0 0 0]
}


package main

import "fmt"

func main() {

    y := make([]int,3,5) // 5表示容量,长度为3
    fmt.Println(len(y),y)
    y1 := append(y,2,3,8,4,9,9)
    fmt.Println(y1)  //[0 0 0 2 3 8 4 9 9]

}





常用的go命令
  /*
  4个go命令:
  go命令 文件名   要么根据绝对路径去找,要么能在当前cmd路径下找到
  go命令 项目名   去src下找
  
  1 go run 编译并执行,不保存编译后的文件
  2 go build 编译并保存,默认放在当前的cmd路径下;指定保存路径 -o
  3 go install  编译并放在gopath下的bin目录下。
  4 go fat  格式化,统一格式化项目比较多
  */

变量

/*
变量声明五种方式:
1 var 变量1,2... 类型字面量  有默认值,int 0;bool false;string 空;
*/

package main
import (
    "fmt"
)
// 声明一个变量
func main() {
    var a int
    var b string
    var c  bool
    fmt.Println(a) //默认为0
    fmt.Println(b) //默认为空
    fmt.Println(c) //默认为false
    }

/*
2 var 变量1,2... 类型字面量  = 变量值    (声明变量,给定初始值)
*/

 package main
import (
    "fmt"
)
// 声明变量给定初始值
func main() {
    var a,d int = 10,100
    var b string = "hello world"
    var c bool = true
    fmt.Println(a,b,c,d)
}
 
/*

3 var 变量名1 = 变量名值 

*/
package main

import (
    "fmt"
)

func main() {
    var a = 100
    var c  = "hello"
    var b = true
    fmt.Println(a,b,c)
}


package main

import ( 
    "fmt"
    "reflect"
)

func main() {
    var a,b,c = 100,"Hello",true
    fmt.Println(a,reflect.TypeOf(a))
    fmt.Println(b,reflect.TypeOf(b))
    fmt.Println(c,reflect.TypeOf(c))
}
/*
3 var 变量名1,变量名2、、、、 = 变量值1,变量值2、、、、、
*/

package main

import (
    "fmt"
    "reflect"
)

func main() {
    var a,b,c = 100,"Hello",true
    var d int64 = 20   // d 设置为int64型
    fmt.Println(a,reflect.TypeOf(a)) // 默认为int
    fmt.Println(b,reflect.TypeOf(b)) // 默认为string
    fmt.Println(c,reflect.TypeOf(c))  // 默认为bool
    fmt.Println(d,reflect.TypeOf(d))  // 为int64
}

/*

4 变量名1...:= 变量值1...   适用条件:只能用于局部

*/

package main

import "fmt"

func main() {
     a := 100 // := 只能用在局部
    fmt.Println(a)
}

/*
5 var(//变量组
变量名1...类型字面量
量名1...  类型字面量 = 变量值1...
变量名1.... = 变量值
)

*/
package main
import "fmt"
func main() {
    var(
        a int = 10
        b string = "江西理工大学"
        c,d = 10.2,true
    )
    fmt.Println(a,b,c,d)
}
变量赋值
  1. 先声明后赋值
  2. 赋值类型要一致
  3. a,b,c = 值1,值2,值3
  4. 交叉赋值
变量的命名规范

推荐使用驼峰体

小写开头,只用于本包下使用(projected)

大写开头,用于开放(public)

常量

/*
常量 内存权限只读
定义常量:
    const 常量名1  类型字面量 = 值1 ,没有初始值.   //常量定义完可以不立即使用
    const 变量名1 = 值1
    const(  常量组  若没有指定类型和值,会继承上面最靠近它的非空常量,并且列数要相等
    ) 
*/

package main

import "fmt"

func main() {
    const a,b int = 100,10 //常量定义完,可以不立马使用
    fmt.Println(a)
    fmt.Println(b)
}

package main

import "fmt"

func main() {
    const a,b = 100,20
    fmt.Println(a,b)
    
}

package main

import "fmt"

func main() {
    const (//常量组
        a,d int = 10,100
        c string = "徐王娟"
        b bool = true
    )
    fmt.Println(a,b,c)
    fmt.Println(d)
}
    

自增常量组

/*
iota 是从0开始计数
_ 占位符  占着茅坑不拉屎
iota 中断 定义一个值
iota 恢复 
多个iota
*/

package main

import "fmt"

func main() {
//自增常量组
    const(
        a = iota //从0开始计数
        b
        c
        d
        e = "江西理工大学"
        f
        g
        h  = iota 中断
        m
        n
    )
    fmt.Println(a,b,c,d) // 0 1 2 3
    fmt.Println(e,f,g) // 江西理工大学 江西理工大学 江西理工大学
    fmt.Println(h,m,n)  // 7 8 9
}


package main

import "fmt"

func main() {
    const(
        a,b = iota,iota
        c,d
        e,f
    )
    fmt.Println(a,b) //0,0
    fmt.Println(c,d) //0,0
    fmt.Println(e,f) //0,0
}


package main

import "fmt"

func main() {
    const(
        _=iota+1
        a
        b
        c
        d
    )
    fmt.Println(a) //1
    fmt.Println(b) //2
    fmt.Println(c) //3
    fmt.Println(d) //4
}

基本运算符

/*
数字与数字之间加减乘除,只要其中一个是小数,结果是浮点型,整形与整形之间加减乘除,结果一定是整形。
程序只会在特定情况下(遇到浮点型,不管是变量还是数字) 会把整形数字转成浮点型,再进行运算,但是不会自动转换整形变量
*/


package main

import (
    "fmt"
    "reflect"
)

func main() {
    var a = 1+2.0
    var b = 3*a
    var c = 5.0*b
    fmt.Println(a,reflect.TypeOf(a))
    fmt.Println(b,reflect.TypeOf(b))
    fmt.Println(c,reflect.TypeOf(c))
}
/*
 常量(const)存储方式和变量(var)存储方式不一样。
*/
package main

import (
    "fmt"
    "reflect"
)

func main() {
    const a  = 3
    var b  =  2.5
    var c = a/b
    fmt.Println(c,reflect.TypeOf(c))
}

流程控制语法

/*
用户交互:
var name string
fmt.Scanln(&name) // 传入指针内存地址    
fmt.Println(name)
*/
 
// if - else语句
package main

import "fmt"

func main() {
    var age int //定义变量age
    fmt.Print("请输入你的年龄:")
    fmt.Scanln(&age) //
    fmt.Println(age)
    if age >= 25{
        fmt.Println("阿姨你好")
    } else {
        fmt.Println("小姐你好")
    }
}
package main

import "fmt"

func main(){
    var score int
    fmt.Print("请输入你的成绩>>")
    fmt.Scanln(&score)

    if score >= 90{
        fmt.Println("优秀")
    } else if score >= 70{
        fmt.Println("去python9期吧")
    } else {
        fmt.Println("回家吧")
    }
}
if - else if - else/ if[嵌套]
package main
import (
    "debug/elf"
    "fmt"
    "go/ast"
)

func main() {
    var score int
    fmt.Print("输入你的分数")
    _,err := fmt.Scanln(&score):if err != nil {
        fmt.Println("输入有误")
    }else {
        if score >= 90{
            fmt.Println("成绩优秀")
        }else if score >= 70{
            fmt.Println("成绩良好")
        }else {
            fmt.Println("回家歇着")
        }
    }
}
/*if 可执行语句; 判断条件{ }*/

package main

import "fmt"

func main() {
    if fmt.Println("江西理工大学");true{
        fmt.Println("电气工程与自动化学院")
    }else{
        fmt.Println("控制工程")
    }
}
// switch 分支语句
//switch 比if 更简洁明了

/*
 switch [可执行语句;] 判断量{
 case 被判断量1,被判断量2:
     代码
 case 被判断量3:
     代码
 default:  
     代码
 }
*/

package main

import (
    "fmt"
)

func main() {
    var people string
    fmt.Println("来访客户:")
    fmt.Scanln(&people)

    switch people {
    case "男经理","女经理":
        fmt.Println("经理你好")
    case "客户":
        fmt.Println("客户你好")
    default:
        fmt.Println("不存在")
    }
}


/*
switch 可执行语句;{
    case 条件1,条件2:
        代码块
    case 条件3
}
*/

package main

import "fmt"

func main() {
    switch score:= 60;{
    case score>= 90:
        fmt.Println("优秀")

    case score >= 70:
        fmt.Println("良好")

    case score >= 40:
        fmt.Println("不及格")
    }
}

break 和fallthrough语句(很少用,能不用就不用)
//break 和fallthrough 主要为了 解决c和c++


package main

import (
    "fmt"
)

func main() {
    var people string
    fmt.Println("来访客户:")
    fmt.Scanln(&people)

    switch people {
    case "男经理","女经理":
        fmt.Println("经理你好")
    case "客户":
        fmt.Println("客户你好")
    default:
        fmt.Println("不存在")
    }
}
 

for 循环

/*

格式:
for  初始条件;判断条件;追加条件{
          循环体代码
}

*/
package main

import "fmt"

func main() {
    for a:=1;a<=3;a++{
        fmt.Println("江西理工大学")
    }
}

//省略初始条件
for ;循环条件;追加条件{
    代码体
}
package main

import "fmt"

func main() {
    a:=1
    for ;a<=3;a++{
        fmt.Println("江西理工大学")
    }
}

//省略初始条件和追加条件
package main

import "fmt"

func main() {
    a:=1
    for ;a<=3;{
        fmt.Println("江西理工大学")
        a++
    }
}
for 循环退出
/*
break  continue  变量开关
*/
package main

import "fmt"

func main() {
    for a:=1;a<=3;a++{
        fmt.Println("河海大学")
        if a == 2{
            coinunte
        }
    }
}
标签(2019.7.17)
什么是标签?
   记录被标签者的信息
   在程序中记录当前代码位置

为什么要有标签?
   标记不是目的,目的是使用,记录位置是为了快速找到它

怎么使用标签?
定义标签:直接在代码上加上标签名,大写+数字 和变量区分开。// 如:LABEL1
定义完标签就一定要使用标签。

使用标签:
     1  break + 标签
     2  continue + 标签 // 结束被标记的循环
     3  goto + 标签    //  降低了代码的可读性和可维护性,能不用则不用   
          注意点: 1 只能用于函数内部跳转
                 2 不能挑过变量声明

基本数据类型及其操作

硬盘(utf-8) 内存(utf-16)
/*
整型: 
有符号:int  int8 int32  int64(正常使用:int,int64,uint uint64)
无符号:uint uint8 uin64 uint64 


浮点型: float32 float64
       float32 显示8位,精确到7位
       float64 显示17位,精确到16位
       
复数类型
complex64(complex里,a,b 皆为float32)
complex128(complex里,a,b 皆为float64) 


强制类型转换:
eg: var a int8 = 123
    var b int64 = int64(a) //强制转换
    fmt.Println(b)
数字类型和数字类型之间进行转换,转换类型要能够完全表示被转换类型。  


字符串类型:
   string
   
字符串的操作。
支持 != + > <

字符串输出格式化:
fmt.Printf( "XXX,%d",a)
 
 遍历
 
  for i,v:= range "江西理工大学"
      fmt.Printf("%d,%c\n",i,v)
      
 
*/

package main

import (
    "fmt"
)

func main() {
    var  s string = "Jiangxi University of Science and Techlonogy" //定义字符串变量
    for i,v:= range s{//遍历
        fmt.Printf("%d,%c\n",i,v)
        fmt.Println(string(v))
    }
}
备注
switch[可执行语句;]判断量{
    case 被判断量1,被判断量2...: //相当于 if 判断量 == 被判断量1||判断量 == 被判断量2
        代码
        break     //用于提前终止switch,后面的代码不会执行
        代码
        fallthrough // 用于跳过下一个case判断,直接执行代码,fallthrough 必须写在最后
     case 被判断量3:
        代码
     .....
     
     default: //相当于else,所有case都不能满足时,才执行
         代码...          
}

for循环语句:
     for 初始语句;判断条件;追加语句{
        执行体
     }
标签:定义(大写+数字),定义完一定得使用,标记的代码位置
1. break + 标签  //快速结束被标记循环
2. continue + 标签 // 跳过被标记循环的本次循环
3. goto+ 标签: 只能用于内部跳转,不能挑过变量声明语句

// go语言切片中没有步长。

String 包

Go语言是为了简化字符串的复杂操作,在标准库中提供了一个名为Strings的包,里面集成了很多功能,我们之间调用就好,不需要再自己编写。

string包:字符串常用操作。
1.判断是否以...开头,// string.HasPrefix(str,"")
eg:
/*
package main

import (
    "fmt"
    "strings"
)

func main(){
    str := "上海浦东新区张江镇" //strings包中的HasPrefix() 检测以...开头
    str2:= "jiangxi university of science and technology"
    str3:= "TOM IS HELLO"
    str4:= "###golang##"
    str5:= "Jiangxi\nand\t"
    str6:= "a,b,c,d,hello"
    
    fmt.Println(strings.HasPrefix(str,"浦东")) //false
    fmt.Println(strings.HasPrefix(str,"张江镇")) //false
    fmt.Println(strings.HasPrefix(str,"上")) //true
    
    fmt.Println(strings.HasSuffix(str,"张江镇")) //以....结尾
    fmt.Println(strings.HasSuffix(str,"新区")) //false
    
    fmt.Println(strings.Contains(str,"江西")) //false
    fmt.Println(strings.Contains(str,"浦东")) //True
    
    fmt.Println(strings.ContainsAny(str,"张")) //true
    fmt.Println(strings.ContainsAny(str,"吴")) //false
    
    fmt.Println(strings.Index(str,"海")) //索引值 3 ,一个汉字占3个字节
    fmt.Println(strings.Index(str,"")) //索引值为0,字符串开头默认值为0
    
    fmt.Println(strings.LastIndex(str,"镇")) // 24
    fmt.Println(strings.LastIndex(str," ")) // -1
    
    fmt.Println(strings.Replace(str,"张江镇","康桥镇",1)) // 原来字符串替换新的字符串
    fmt.Println(strings.Replace(str,"浦东新区","黄浦区",-1)) // -1 表示全部替换掉
    
    fmt.Println(strings.ToUpper(str2)) //小写改成大写
    fmt.Println(strings.ToLower(str3)) // 大写变成小写
    fmt.Println(strings.ToTitle(str2)) // 等同于 ToUpper
    
    fmt.Println(strings.Trim(str4,"#")) // 除去指定字符
    fmt.Println(strings.TrimSpace(str5)) // 除去空格等字符
    fmt.Println(strings.Split(str6,",")) //变成切片 [a b c d hello]
    
    
}
*/
    
2.判断是否以...结尾。Strings.HasSuffix(str," ")
3.是否包含...。contains(str,"...")
4.是否包含...中任意字符 ContainsAny(str,"....")

注:
contains 和 containsAny区别:
fmt.Println(strings.Contains(str,"")) //true
fmt.Println(strings.ContainsAny(str,"")) //false

5.查找...的第一次出现的所有...,Index(str,"...")
  汉字一个字节占3位

6.从后往前找,第一次出现的索引. LastIndex(str,"...")

7.替换Replace(str,oldstr,newstr,n) 
// oldstr为老字符串,newstr为新的字符串,n为替换次数,n=-1,全部替换掉

8.统计字符串出现次数 count(str,"...")
9 大小写之间转换 ToUpper(str)/ ToLower(str)
10 单词大写 ToTitle(str)
11 除去指定字符 Trim(str,"...") #除去左右两边指定的字符(除去指定字符(首/尾))
12 除去右侧字符 TrimRight(str,"....") 
13 除去左侧字符 TrimLeft(str,"...") 
14 除去空格字符 Trimspace(str)
15 split(str,"...")  根据指定分隔符,转成切片[a b c d...]
16 拼接,Join(字符串切片,拼接符)
strconv 包(字符串转换包)
/*
strconv包
conv->convert(转换)
*/
1 bool 转 字符串:FormatBool(bool值) 将布尔值转换为字符串
2 字符串 转 bool: ParseBool(str) //str 为 1,t,T,TRUE,true,True 或者 0,F,f,FALSE,False,false
   当str不是 1,t,T,TRUE,true,True 或者 0,F,f,FALSE,False,false时,如"江西理工大学"
    var v,err = strconv.ParseBool("江西理工大学")
    fmt.Println(v) //false
    fmt.Println(err) // strconv.ParseBool: parsing "江西理工大学": invalid syntax

3 int64类型 转换为 字符串;strconv.FormatInt(int64,进制数) //把int64转换成相应进制,然后以字符串显示
字符串 转 int64 ; strconv.ParseInt(str,参数进制数,范围)//
eg: strcov.ParseInt("123",参数的进制数,范围)
    如范围:8  -128~127

代码示例: 
package main

import (
    "fmt"
    "reflect"
    "strconv"
)

func main() {
    var a bool = true
    b:= "true"
    var c = "江西理工大学"
    fmt.Println(strconv.FormatBool(a)) //将bool型转化为字符串类型
    fmt.Println(reflect.TypeOf(strconv.FormatBool(a)))


    fmt.Println(strconv.ParseBool(b)) // 将字符串转化为bool型
    var v,err = strconv.ParseBool(c)// v表示结果(true or false),err表示返回错误信息。

    fmt.Println(v)
    fmt.Println(err)

    var v1,err1 = strconv.ParseBool("t")
    fmt.Println(v1)
    fmt.Println(err1) //没有错误信息时,返回nil

    fmt.Println("*************************************************")
    var v2,err2 = strconv.ParseBool("oldboy education")
    fmt.Println(v2)
    fmt.Println(err2)

    fmt.Println("********************************")
    var v3, err3 = strconv.ParseBool("f")
    if err3 == nil{
        fmt.Println("转换成功",v3)
    }else {
        fmt.Println("转换失败",v3)
    }

    var d = strconv.FormatInt(int64(46),5) //将46转换为5进制数
    fmt.Println(d,reflect.TypeOf(d))

    fmt.Println("**********************************")

    var str = "520"
    var v4,err4 = strconv.ParseInt(str,32,9)
    fmt.Println(v4)
    fmt.Println(err4)

}
map类型(映射)
map类型 字面量 定义 操作 增 删 改 查 遍历
类型字面量  map[ktype]vtype
ktype:是映射中键的类型,强调:此类型要能够判断 “==” 
vtype:是映射中值的类型,可以是任意类型。

定义:var 变量 类型字面量
     变量 = 类型字面量{}

package main
/*
 map类型定义操作
*/
import "fmt"

func main() {
    var mymap map[string]string //定义一个map类型,系统默认自动给其赋值,不能再为mymap进行赋值操作,
    // 如mymap["name"] = "Kevin" //报错
    // fm.Println(mymap) 
    fmt.Println(mymap)
    fmt.Println(mymap == nil)//true

    youmap:= map[string]string{"name":"徐王娟"}//简短声明一个youmap变量
    //var youmap = map[string]string = map[string][string]{"name":"徐王娟"}
    fmt.Println(youmap)//map[name:徐王娟]
    
    hemap:= map[string]string{} //赋初始值为空值
    fmt.Println(hemap == nil) //false

}

/*
map映射的操作
*/
1.赋值/改值操作
mymap:= map[string]string{}  //声明一个mymap
mymap["school"] = "江西理工大学" //增加操作
fm.Println(mymap)

mymap["school"] = "河海大学"//更改值操作
var v,isexist = map["sex"] //判断"sex"是否存在map中

mymap["gender"] = "male" //添加{gender:male}
mymap["address"] = "shanghai" //添加address:shanghai

2.删除操作:delete(map,key)
delete(mymap,"gender") //删除指定键

package main
import (
    "fmt"
)

func main() {
    mymap := map[string]string{} //生成一个mymap,其初始值为空值
    fmt.Println(mymap)

    mymap["school"] = "江西理工大学" //增加操作
    fmt.Println(mymap)

    mymap["school"] = "安徽大学" //修改
    fmt.Println(mymap)

    var v,isexists = mymap["sex"] // 判断sex是否存在于mymap中
    fmt.Println(v,isexists)

    mymap["gender"] = "male"
    fmt.Println(mymap)

    mymap["language"] = "Go"
    fmt.Println(mymap)

    delete(mymap,"gender")  // 删除操作
    fmt.Println(mymap)

    mymap["location"] = "China"

    for k,v:= range mymap{ // map遍历
        fmt.Println(k,v)
    }

}

 
3.遍历
package main

import "fmt"

func main() {
    mymap := map[string]string{}
    mymap["name"] = "徐王娟"
    mymap["age"] = "28"
    mymap["gender"] = "male"
    mymap["huji"] = "Anhui"

    for i,v := range mymap{
        fmt.Println(i,v)
    }
}

}
/*

name 徐王娟
age 28
gender male
huji Anhui

*/
在包中,如果变量名是小写,在包内可以相互访问,相当于JaVa中的projected。
在包中,如果变量名是大写,可以被包外所访问,相当于Java中的public。
函数定义与使用
定义:
func 函数名(形参1 类型1,形参2 类型2,...)(返回值类型1,返回值类型2){
    代码体
    return 返回值1,返回值2,...
    
}
注:go语言不支持函数的默认参数

package main

import (
"fmt"
"reflect"
)

func test1(x int,y string){
    fmt.Println(x,y)
}

func test2(x,z int,y string){
    fmt.Println(x,y,z)
}

func test3(x...int){ //x...int为变参
    fmt.Println(x)//x输出为切片
}

func test4(x...int)(int,string,string){ //定义返回值
    fmt.Println(x)
    fmt.Println(reflect.TypeOf(x))
    return 1,"hello world","返回值" //返回值
}


func main() {
    test1(1,"hello")
    test2(1,3,"go")
    test3(1,2,3,4,5,6) //产生一个切片
    fmt.Println(test4(3,5,6,3,2,2))
    
}

*****************************************************************************************
/*

命名返回值

*/

package main

import "fmt"

func test()(aaa int,bbb int){ // aaa int 默认为0,bbb int 默认为0
    return 
}

func main() {
    a,b:= test()
    fmt.Println(a,b) // 0,0
}

****************************************************************
package main
import "fmt"
func test()(aaa int,bbb int){//
    aaa = 123
    bbb = 123
    return 
}

func main() {
    a,b:= test()
    fmt.Println(a,b) //123,123
}

***************************************************************
package main

import "fmt"

func test()(aaa int,bbb int){//
    aaa = 123
    bbb = 123
    return 1,2
}

func main() {
    a,b:= test()
    fmt.Println(a,b) //1,2
}
函数变量
package main

import (
    "fmt"
    "reflect"
)

func test(){
    fmt.Println("我是函数变量")

}

func main() { 
    fmt.Println(test) // 将函数名当做变量,输出的是 函数内存地址
    x := test
    fmt.Println(reflect.TypeOf(x))
    x()
}

/*
函数类型字面量:
    func(参数 类型, 参数 类型)(返回值类型1,返回值类型2...)
*/
函数嵌套定义
在go语言里面不支持一个func下出现另一个func,所以要实现函数嵌套,就得用变量声明的方式  去声明函数。
eg:
package main
import "fmt"
//函数嵌套
func test(){
        var test1  = func() {// var声明一个函数
            fmt.Println("我是内部函数")
        }
        test1()
    }

func main() {
    test()
}
注:go不支持多个func()连用,所以得用声明变量的方式。如上所示。
匿名函数
go里 函数变量名存放的是函数内存地址
说明:我们定义函数的时候,其实就是定义了一个变量,只不过这个变量的类型是函数类型
函数类型:func 函数名(形参类型1,形参类型2...) (返回值类型1,返回值类型2...)
既然知道了函数类型,那么我们很明显可以用声明变量的方式去声明函数:
变量:= 函数类型(值--函数体)。

eg:
test1 := func(){fmt.Println("我是test1")}
test2 := func(x int){fmt.Println("我是test2,我有参数%v\n",v)}
test3 := func()string{return "我有返回值"}
函数作用域
语法块:
{}扩起来的叫做一个语法块,其内部变量就是局部变量,{}外面的叫做全局变量 
作用域:    
{}叫局部作用域
{}外面叫做全局作用域
查找:局部作用域——>全局作用域
package main

import "fmt"

var a int = 10 // 全局变量
func test(){
    a = 20 //局部作用域
    {
        a = 100 //函数体局部作用域
    }
    fmt.Println(a)
}
func main() {
    fmt.Println(a) //a = 10
    test()//a = 100
}
闭包函数
 




panic恐慌
程序出错:1.编译阶段就会出错 2 运行时出错
package main

import "fmt"

func test(){
    fmt.Println("我进来了")
    panic("我是一个错误信息")
    fmt.Println("我走了")

}

func main() {
    test()
}

面向对象

结构体
/*

结构体:
    type 变量名 struct{
    字段名 类型,
    字段名1 字段名2 类型,
    ...
    }

*/

eg:
package main
import "fmt"
type student struct { //定义一个学生的结构体
    name string
    age int
    gender string
    id int
}

func main() {
    var xwj = student{ //相当于实例化
        name:"徐王娟",
        age: 23,
        gender:"male",
        id: 6720160375,
    }

    fmt.Println(xwj)
    fmt.Println(xwj.age) //打印xwj中的age属性值,访问字段

    xwj.age = 28  //修改属性值
    xwj.name = "蓝河"
    xwj.id = 320238025
    xwj.gender = "female"
    fmt.Println(xwj)
}

/*

实例化对象没有初始值时

*/

package main

import "fmt"

type person struct { //定义一个person类的结构体
    name string
    age int
    loc string
    id int
}

func main() {
    var p = person{//以实例化一个结构体
        //name:"李明",
        //age:26,
        //loc:"上海",
        //id:340823,
    }
    
    fmt.Println(p) // 0 0
}

/*
传递给函数
*/

package main

import "fmt"

type animal struct { //定义一个结构体
    name string
    age int
    gender string
}

func test(aa animal){
    aa.name = "阿狗"
}

func main() {
    var dog = animal{ //实例化结构体对象
        name: "阿黄",
        age: 20,
        gender:"male",
    }

    test(dog)
    fmt.Println(dog) //{阿黄 20 male}
}

eg:
package main

import "fmt"

type animal struct { //定义一个结构体
    name string
    age int
    gender string
}

func test(aa *animal){ //*传递指针
    aa.name = "阿狗"
}

func main() {
    var dog = animal{ //实例化结构体对象
        name: "阿黄",
        age: 20,
        gender:"male",
    }

    test(&dog) //传入地址
    fmt.Println(dog) // {阿黄 20 male} 
}
匿名结构体
/* 
匿名结构体就是我们不自定义结构体类型,直接通过结构体字面量的形式产生一个实例(只用一次)
eg:
  var 变量名 = struct{
    
}{}
*/

package main
import "fmt"
func main() {
    var test1 = struct {
        name string
        id int
    }{name:"孙悟空",
        id:340823}
    fmt.Println(test1) //{孙悟空 340823}
}

*************************************************

package main

import "fmt"

func main() {
    var test1 = struct {
        name string
        id int
    }{}

    fmt.Println(test1)//{0}
}
结构体嵌套
package main

import (
    "fmt"
)

type classes struct {//定义一个classes结构体
    className string
}

type teachers struct {//定义一个teachers结构体
    teachersName string
    class classes
}
type students struct {//定义一个students结构体
    studentName string
    class classes
}

func main() {
     class1 := classes{//实例化class1结构体
        className:"江西赣州",
    }

     teachers1 := teachers{ //实例化teachers结构体
        teachersName:"何凯文",
        class:class1,
    }

     students1 := students{
        studentName:"徐王娟",
        class:class1,
    }
    
    fmt.Println(teachers1)
    fmt.Println(students1)
    fmt.Println(teachers1.class.className) //访问classes中的className值
  
}
匿名字段

go语言中的方法
/*
方法的定义:
    方法就是函数,只是这个函数是绑定给指定类型的,只有该类型的数据才能调用
    func(参数 指定类型) 函数名(参数及类型) 返回值类型{
    代码体...
    }

*/
eg: 
  
package main

import "fmt"

type students struct {//定义一个students结构体
    name string
}

func(s *students)change(name string){//*student,如果不加*,则没有改变,方法中的参数传入
    s.name = name
}

func main() {
    student1 := student{
        name:"孙悟空",
    }

    student2 := student{
        name:"贝吉塔",
    }

    student1.change("孙悟饭")
    student2.change("特南克斯")
    fmt.Println(student1)  //孙悟饭
    fmt.Println(student2)  //特南克斯
}
***********************************************************************
package main

import "fmt"

type student struct {//定义一个student结构体
    name string
}

func(s student)change(name string){
    s.name = name
}

func main() {
    student1 := student{
        name:"孙悟空",
    }

    student2 := student{
        name:"贝吉塔",
    }

    student1.change("孙悟饭")
    student2.change("特南克斯")
    fmt.Println(student1) //孙悟空
    fmt.Println(student2) //贝吉塔
}

**********************************************************************
package main

import "fmt"

type students struct {//定义一个students结构体
    name string  //存放学生姓名
    score []int  // 存放学生成绩(切片)
}

//定义一个方法,用来给学生添加成绩
func (student *students) appendScore(score int){ //student *student 绑定方法
    student.score = append(student.score.score)
}

func main(){
    student1 := students{
        name:"弗利萨",
    }
    student1.appendScore(90)
    student1.appendScore(100)

    fmt.Println(student1)
}
接口 (interface)
接口(interface)核心知识点
1、任何类型的数据都可以传给(interface)

2 interface 统一了功能调用方式
   统一调用方式的意思是:接口只管统一功能调用方式,不管函数怎么实现的。

3 interface 不管功能的实现。
  那函数实现交给谁?
  1.谁要传进来就由谁来实现。
  2.实现了接口里所有函数的,叫做实现了这个接口

定义接口:
type 接口名 interface{}

/*
任何类型的数据都可以传给interface
*/
接口断言
我们知道了接口的核心是接收任意类型,统一调用方式
现在由这么个需求,假设我有一个接口,可以接收结构体类型a和字符串类型b,但我现在需要根据不同的类型写不同的代码,这怎么处理?很明显,这里需要一个类型判断

断言,就是用来处理接口类型的判断


var v,ok = 具体接口(实现了接口的类型a)

// ok得到了是bool值,用来判断传入接口的类型是不是类型a
// 如果ok为true,则v就会得到该类型的值,否则就是类型a的初始值
接口嵌套
type mine1 interface{
    test1()
    test2()
}

type mine2 interface{
    mine1
    test3()
}
/*
mine2就相当于: 
  type mine2 interface{ //程序自动拓展开
  test1()
  test2()
  test3()
  }

*/
type switch(类型选择)
/*type switch和switch的用法基本上是一致的*/
switch t:= 具体接口(type){
    case mystring:
    代码
    case mystruct:
    代码
    ...
    dafault:
    代码
}
回顾
1 map 类型 map[string]string  var 变量名 类型字面量(map == nil)
接口:
   1.任何类型都可以传给接口
   2.统一了调用方式
   3.不负责方法的实现
          谁要传给接口,就由谁去实现方法(绑定方法的的方式)
          实现了接口中规定的所有方法,叫做实现了这个接口
          只有实现了这个接口的类型才可以传递给接口

type 接口名 interface{
    方法名(形参类型 新参类型) 返回值类型
}

var 接口 接口名
接口 = 类型 (绑定方法,至少需要绑定接口中所有的方法)
接口.方法名()
补充
继承方法:
type school struct{
    schoolName string
}

type struct2 struct{
    studentName string
}
func() 
并发
用户级线程 和 系统级线程
内核级线程:
    内核级线程是操作系统执行程序的最小单元,就是说:CPU会在内核级线程之间切换并执行,如果有多个cpu,那就是多个cpu这些线程之间切换并执行。我cpu去执行的就是内核级线程。
 
用户级线程:
   用户级线程说的简单直白一点,就是用用户自己规定的一个代码块。

常见并发设计模式:
1.协程设计模式(用户级线程和内核级线程之间多对一,需要切换)
//一旦发生无法切换的阻塞,整条内线程都会被阻塞
//这个模式的优点在于开销小,切换效率快,但有也有两个很致命的问题:一,就是不能实现并行,二,就是一旦阻塞整个线程都会被阻塞。python里的gevent就是这个模式。

2.多线程设计模式(用户级线程和内核级线程之间一对一) 
//一对一绑定,由操作系统调度进行线程间的切换,真正意义上做到了并行
这个模型的优点在于简单、和并行。缺点:一、切换操作系统调度的,效率比较低。二,Linux操作系统下开一个线程默认需要8M空间,资源成本大。
 
3.go并发设计模式(将 多对一模式 和 一对一模式 结合起来)
4.
创建go并发
1.创建gorounte:
格式如下:
go函数名(参数)
或者用匿名函数创建:
go func(形参) {函数体}(实参)

package main

import "fmt"

func test1(){
    fmt.Println("我是test1")
}

func test2(){
    fmt.Println("我是test2")
}


func main() {
    for i:=0;i<10;i++{
        go test1()
        go test2()
    }

    var myinput string
    fmt.Scanln(&myinput) // 开go并发进程
}

通道channel

正常多线程,比如python里Threading,都是以共享内存的方式来进行数据交换
这时,我每个线程都可以访问同一个数据,并对它进行修改,这就造成了数据的不安全,为了保证数据修改的正确性,就得用互斥来解决这个问题。这样虽然问题解决了,就是造成了性能的下降。

go就与众不同,它不用共享内存的方式共享数据,它用通道的方式来共享数据。
通道的声明

我们使用make关键字来创建一个通道

mychan:= make(chan 类型) //chan:表示通道 ;类型:用来指定通道里数据的类型
收发数据

我们用<-来收发数据

发数据

mychan <- 数据

收数据

数据 <- mychan

```

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!