Go基础1
基础语法: var [名称] [类型] var name string 1)声明的变量一定要使用 2)声明同时初始化,可以不写后面类型:var sum = 17 多变量声明同其他语言var a,b int ? // 自动推导类型 [名称] := [值] name := "Bill" 1)注意只能在函数局部使用 2)只能使用一次,用于初始化,第一次出现使用 ? //多重初始化 a,b,c := 10,"abc",1.0 ? //交换两个变量的值 A,b = b,a ? //_匿名变量,丢弃数据不处理,一般是配合函数返回值使用 tmp,_ = i,j?? //tmp=10,go函数支持返回多值 ? //不同类型变量的声明 var( ?? a int = 1 ?? b string = “abc” ) // ---------------------------------------常量 const [名称] [类型] = 值 const? a int = 3 const? b? = “abc” 1、 不能使用自动推导 2、 类型是可选选项 3、 同时声明多个:const a,c = 1,false,"str" //多重赋值 ? 常量还可以用作枚举(声明多个常量): const ( ??? Unknown = 0 ??? Female = 1 ??? Male = 2 ) ? ? // ---------------------------------------iota枚举 ??? const ( ??????? x = iota // x == 0 ??????? y = iota // y == 1 ??????? z = iota // z == 2 ??????? w? // 这里隐式地说w = iota,因此w == 3。其实上面y和z可同样不用"= iota" ??? ) ? ??? const v = iota // 每遇到一个const关键字,iota就会重置,此时v == 0 ? ??? const ( ??????? h,i,j = iota,iota,iota //h=0,i=0,j=0 iota在同一行值相同 ??? ) ? ??? const ( ??????? a?????? = iota //a=0 ??????? b?????? = "B" ??????? c?????? = iota???????????? //c=2 ??????? d,e,f = iota,iota //d=3,e=3,f=3 ??????? g?????? = iota???????????? //g = 4 ??? ) ??? ??? const ( ??????? x1 = iota * 10 // x1 == 0 ??????? y1 = iota * 10 // y1 == 10 ??????? z1 = iota * 10 // z1 == 20 ??? ) 1、 iota每隔一行,自动累计加1 2、 iota给常量赋值使用 3、 iota遇到const,重置为0 ? // ---------------------------------------注释 // 单行注释,CsCode快捷键Ctrl+/ /* ?Author by 多行注释 ?我是多行注释 ?*/ ? // ---------------------------------------?类型转换 分兼容的直接转换,和不兼容的利用类库转换 不兼容的一般会类似这样提示 cannot convert ?expression (type type_name) to type desctype_name 1、 兼容的可以直接转 type_name(expression) mean = float32(sum) / float32(count) var ch byte ch = ‘a’ var t int t = int(ch)//类型转换 2、 不兼容的可以利用函数strconv里面的方法进行转,一般会返回两个值,转换结果和报错信息 boolvalue,err := strconv.ParseBool("1")//int类型 转成 bool i,err := strconv.Atoi(“123”) //string 类型 转成 int ? ? // ---------------------------------------?变量输入 Var a int fmt.Scan(&a)//输入值赋给a ? ? // ---------------------------------------?类型别名type(把类型弄个自己的名字来用) 在结构体和方法里面会用到 Type 别名 类型 type bigint int64 //int64类型改名为bigint var x bigint = 100//等价于var x int64 = 100 ? type ( ??????myint int??? //int改名为myint ??????mystr string //string改名为mystr ) ? // ---------------------------------------??运算符 大同小异,这里列一些和C#不同的 1、++和—只有后自增和后自减 2、位运算符多了<<和>> 3、赋值运算符<<=、>>= 4、返回变量存储地址:& 5、指针变量:* /*? & 和 * 运算符实例 */ var a int = 4 ?? var ptr *int ?? ptr = &a????/* ‘ptr‘ 包含了 ‘a‘ 变量的地址,*ptr就是a的值 */ ?? fmt.Printf("a 的值为? %dn",a); ?? fmt.Printf("*ptr 为 %dn",*ptr); a 的值为? 4 *ptr 为 4 ? 一元运算符拥有最高的优先级,二元运算符的运算方向均是从左至右。 下表列出了所有运算符以及它们的优先级,由上至下代表优先级由高到低:
? ? // ---------------------------------------??if语句 If if a < 20 { ?????? fmt.Printf("a 小于 20n" ) ?? } //支持一个初始化表达式,初始化字句和条件表达式直接需要用分号分隔 ????if b := 3; b == 3 { ????????fmt.Println("b==3") ??? } ???? If else if a < 20 {//{不能跨行 ???? ??fmt.Printf("a 小于 20n" ); ?? } else if {//{不能跨行 fmt.Printf("a 不小于 20n" ); ?? }else {//{不能跨行 fmt.Printf("a 不小于 20n" ); ?? } ? if嵌套 if 布尔表达式 1 { ?? /* 在布尔表达式 1 为 true 时执行 */ ?? if 布尔表达式 2 { ????? /* 在布尔表达式 2 为 true 时执行 */ ?? } } ? ? ? Switch:和C#比,没括号(go里面,加括号,加分号,保存后,VsCode会自动去掉) switch var1 { ??? case val1: ??????? ... case val2: ?????? ... ??? default: ??????? ... } ? Type Switch switch x.(type){ ??? case type: ?????? statement(s);????? ??? case type: ?????? statement(s); ??? /* 你可以定义任意个数的case */ ??? default: /* 可选 */ ?????? statement(s); } 1. 支持多条件匹配 switch{ ????case 1,2,3,4: ????default: } 2. 不同的 case 之间不使用 break 分隔,默认只会执行一个 case。 3. 如果想要执行多个 case,需要使用 fallthrough 关键字(一般结尾加,没遇到break会继续执行下一个case分支),也可用 break 终止。 4、支持初始化语句 switch num := 1;num{ ?? case 1: ?? default: } 4、 switch可以没有条件,case放条件 score := 85 Switch{ Case score > 90: fmt.mrintlc(“优秀”) } ? // ---------------------------------------??循环 for 有三种形式 1、for init; condition; post { } 2、for condition { }? //和while类似 3、for { } //相当于while(true),里面要加break跳出的
? ????for a < b { ????????a++ ????????fmt.Printf("a 的值为: %dn",a) ???? } ? ? ? // ---------------------------------------??迭代器range相当于C#foreach 关键字 range 会返回两个值(可以选择定义一个变量只接受一个值),第一个返回值是元素的数组下标,第二个返回值是元素的值: ????s := "abc" ????for i := range s { //支持 string/array/slice/map。 ????????fmt.Printf("%cn",s[i])//只接受下标i ????} ? ????for _,c := range s { // 忽略 index ????????fmt.Printf("%cn",c) ????} ? ????for i,c := range s { ????????fmt.Printf("%d,%cn",c) ????} ? ? ? // ---------------------------------------? goto 用goto跳转到必须在当前函数内定义的标签: func main() { ????for i := 0; i < 5; i++ { ????????for { ????????????fmt.Println(i) ????????????goto LABEL //跳转到标签LABEL,从标签处,执行代码 ????????} ????} ? ????fmt.Println("this is test") ? LABEL: ????fmt.Println("it is over") } ? ? // ---------------------------------------?函数 func function_name( [parameter list] ) [return_types] { ?? 函数体 }
?
多个返回值
? 不定参数类型 不定参数是指函数传入的参数个数为不定数量。为了做到这点,首先需要将函数定义为接受不定参数类型: //形如...type格式的类型只能作为函数的参数类型存在,并且必须是最后一个参数 func Test(args ...int) { ????for _,n := range args { //遍历参数列表 ????????fmt.Println(n) ????} } ? func main() { ????//函数调用,可传0到多个参数 ????Test() ????Test(1) ????Test(1,4) } ? 2) 不定参数的传递 func MyFunc01(args ...int) { ????fmt.Println("MyFunc01")//len(args) ????for _,n := range args { //遍历参数列表 ????????fmt.Println(n) ????} } ? func MyFunc02(args ...int) { ????fmt.Println("MyFunc02") ????for _,n := range args { //遍历参数列表 ????????fmt.Println(n) ????} } ? func Test(args ...int) { ????MyFunc01(args...)???? //按原样传递,Test()的参数原封不动传递给MyFunc01 ????MyFunc02(args[1:]...) //Test()参数列表中,第1个参数及以后的参数传递给MyFunc02 } ? func main() { ????Test(1,3) //函数调用 } ? 返回写法比较多样 单个返回值 func Test01() int { //方式1 ????return 250 } ? //官方建议:最好命名返回值,因为不命名返回值,虽然使得代码更加简洁了,但是会造成生成的文档可读性差 func Test02() (value int) { //方式2,给返回值命名 ????value = 250 ????return value } ? func Test03() (value int) { //方式3,给返回值命名 ????value = 250 ????return } ? 多个返回值 func Test01() (int,string) { //方式1 ????return 250,"sb" } ? func Test02() (a int,str string) { //方式2,给返回值命名 ????a = 250 ????str = "sb" ????return } ? // ---------------------------------------?函数类型(有点像C#的委托) 在Go语言中,函数也是一种数据类型,我们可以通过type来定义它,它的类型就是所有拥有相同的参数,相同的返回值的一种类型。 ? type FuncType func(int,int) int //声明一个函数类型,func后面没有函数名 ? //函数中有一个参数类型为函数类型:f FuncType func Calc(a,b int,f FuncType) (result int) {//Calc是执行的 ????result = f(a,b) //通过调用f()实现任务 ????return } ? //实际调用的函数实现 func Add(a,b int) int { ????return a + b } ? //实际调用的函数实现 func Minus(a,b int) int { ????return a - b } ? func main() { ????//函数调用,第三个参数为函数名字,此函数的参数,返回值必须和FuncType类型一致 ????result := Calc(1,1,Add) ????fmt.Println(result) //2 ? ????var f FuncType = Minus ????fmt.Println("result = ",f(10,2)) //result =? 8 } ? 回调函数 就是利用函数类型实现 实际调用的函数是函数类型的实现 调用那个实现函数类型的是执行的主体 // ---------------------------------------?匿名函数与闭包 所谓闭包就是一个函数“捕获”了和它在同一作用域的其它常量和变量。这就意味着当闭包被调用的时候,不管在程序什么地方调用,闭包能够使用这些常量或者变量。它不关心这些捕获了的变量和常量是否已经超出了作用域,所以只有闭包还在使用它,这些变量就还会存在。 闭包需要匿名函数来实现(都是匿名函数) 在Go语言里,所有的匿名函数(Go语言规范中称之为函数字面量)都是闭包。匿名函数是指不需要定义函数名的一种函数实现方式。 func main() { ????i := 0 ????str := "mike" ? ????//方式1,先定义,再赋函数 ????f1 := func() { //匿名函数,无参无返回值 ????????//引用到函数外的变量 ????????fmt.Printf("方式1:i = %d,str = %sn",str) ????} ? ????f1() //函数调用 ? ????//方式1的另一种方式 ????type FuncType func() //声明函数类型,无参无返回值 ????var f2 FuncType = f1//这里f1就是没参数名的函数 ????f2() //函数调用 ? ????//方式2,直接赋函数 ????var f3 FuncType = func() { ????????fmt.Printf("方式2:i = %d,str) ????} ????f3() //函数调用= func() { ? ????//方式3,定义完了加()就是调用 ????func() { //匿名函数,无参无返回值 ????????fmt.Printf("方式3:i = %d,str) ????}() //别忘了后面的(),()的作用是,此处直接调用此匿名函数 ? ????//方式4,匿名函数,有参有返回值 ????v := func(a,b int) (result int) { ????????result = a + b ????????return ????}(1,1) //别忘了后面的(1,1),(1,1)的作用是,此处直接调用此匿名函数, 并传参 ????fmt.Println("v = ",v) ? } ? // ---------------------------------------?数组 var variable_name [SIZE]variable_type var balance [10]float32 var balance = [5]float32{1000.0,2.0,3.4,7.0,50.0}//初始化 /* 未定义长度的数组只能传给不限制数组长度的函数 */ /* 定义了长度的数组只能传给限制了相同数组长度的函数 */ ? ? ? ? 二维数组 var arrayName [ x ][ y ]variable_type //初始化 a = [3][4]int{? ?{0,3},?? /*? 第一行索引为 0 */ ?{4,5,6,7},?? /*? 第二行索引为 1 */ ?{8,9,10,11},?? /* 第三行索引为 2 */ } ? ? ? // ---------------------------------------?结构体 type struct_variable_type struct { ?? member definition; ?? member definition; ?? ... ?? member definition; } ? type Books struct { ?? title string ?? author string ?? subject string ?? book_id int } ? // 创建一个新的结构体 fmt.Println(Books{"Go 语言","www.runoob.com","Go 语言教程",6495407}) // 也可以使用 key => value 格式 fmt.Println(Books{title: "Go 语言",author: "www.runoob.com",subject: "Go 语言教程",book_id: 6495407}) ? // 忽略的字段为 0 或 空 fmt.Println(Books{title: "Go 语言",author: "www.runoob.com"}) ? var Book1 Books??????? /* 声明 Book1 为 Books 类型 */ /* book 1 描述 */ Book1.title = "Go 语言" Book1.author = "www.runoob.com" Book1.subject = "Go 语言教程" Book1.book_id = 6495407 ? // ---------------------------------------?defer 延迟调用 关键字 defer ?于延迟一个函数或者方法(或者当前所创建的匿名函数)的执行。注意,defer语句只能出现在函数或方法的内部。 func main() { ????defer fmt.Println("this is a defer") //main结束前调用 fmt.Println("this is a test") ????/* ????????运行结果: ????????this is a test ????????this is a defer ????*/ } ? defer语句经常被用于处理成对的操作,如打开、关闭、连接、断开连接、加锁、释放锁。通过defer机制,不论函数逻辑多复杂,都能保证在任何执行路径下,资源被释放。释放资源的defer应该直接跟在请求资源的语句后。 多个defer执行顺序 以LIFO(后进先出)的顺序执行。哪怕函数或某个延迟调用发生错误,这些调用依旧会被执?。 defer和匿名函数结合使用(注意里面的变量是否是闭包引用) func main() { ????a,b := 10,20 ????defer func(x int) { // a以值传递方式传给x ????????fmt.Println("defer:",x,b) // b 闭包引用,a是外部传参进来,已经传进来10,只是没执行 ????}(a) ? ????a += 10 ????b += 100 ? ????fmt.Printf("a = %d,b = %dn",a,b) ? ????/* ????????运行结果: ????????a = 20,b = 120 ????????defer: 10 120 ????*/ } // --------------------------------------- 获取命令行参数 import ( ????"fmt" ????"os"????//os.Args所需的包 ) func main() { ????args := os.Args //获取用户输入的所有参数,字符串 ? ????//如果用户没有输入,或参数个数不够,则调用该函数提示用户 ????if args == nil || len(args) < 2 { ????????fmt.Println("err: xxx ip port") ????????return ????} ????ip := args[1]?? //获取输入的第一个参数 ????port := args[2] //获取输入的第二个参数 fmt.Printf("ip = %s,port = %sn",ip,port) } ? // ---------------------------------------不同作用域的同名变量 在不同作用域可以声明同名的变量,其访问原则为:在同一个作用域内,就近原则访问最近的变量,如果此作用域没有此变量声明,则访问全局变量,如果全局变量也没有,则报错。 ? ? 基础数据类型2.4.1 分类Go语言内置以下这些基础类型:
? 格式化输出输入
(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |