代码改变世界

go语言基础

2019-08-18 18:48  錾子  阅读(104)  评论(0)    收藏  举报

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