Golang 入门~~基础知识
变量声明
//通用形式,指定变量名,变量类型,变量值 var name int = 99 fmt.Println(name) //指定变量名,以及变量类型,未指定值的时候默认是类型零值 var age int //可以后面赋值 age = 88 fmt.Println(age) //短变量声明,指定变量名,以及变量的值,而变量类型会自动由值的类型决定。 gender := "male" //gender变量的类型是string fmt.Println(gender) //变量列表 要求:左右两边变量名与值的数量相同 //先定义,然后赋值 var x, y, z int //x,y,z都是int类型 x, y, z = 1, 2, 4 fmt.Println(x, y, z) //先定义,同时赋值 var o, p, q = "abc", true, 3.14 fmt.Println(o, p, q) //使用短变量的变量列表形式,需要注意,左边至少有一个新变量声明,否则报错 o, r, s, t := "changed", "xyz", false, 99 fmt.Println(o, r, s, t)
注意,在函数中(包括自己定义的函数或者主函数中)声明的变量如果没有使用,在编译的时候,会报错。
在函数外面定义全局变量不能使用短变量形式。
常量
const x = 13 const p int = 13 const pp, ppp = 1, 2 const ( i = 10 ii = 20 )
在声明常量的时候,必须指定值,否则出错。
声明在函数中的常量不使用,并不会报错,只有声明的变量或者导入的包未使用才会报错。
注意下面这个用法:
const ( i = 1 ii iii = 2 iiii ) fmt.Println(i, ii, iii, iiii)// 1 1 2 2
定义多个常量时,如果某个变量没有执行值,那么就会沿用上一个常量的值。
const与iota
在和const联用时,iota的作用是:iota初始值为0,每出现一个常量,iota就加1
const ( i = iota ii iii = 4 iiii = iota ) fmt.Println(i, ii, iii, iiii) //0 1 4 3
数据类型
基本数据类型:string、bool、intX、floatX
复合数据类型:array、struct
引用类型:point、slice、map、func、channel
接口类型:interface
运算符
和其他语言一样,注意--、 ++只能后置,即只能i++、i--。
逻辑运算符||、&&、!,这3个运算符左右两边的表达式必须是bool型,不能是int或者string类型。
类型强制转换
在两种类型的变量相互赋值或者进行比较时,Go语言不会像其他语言一样进行隐式转换,所以必须进行显式地转换。
所以下面两种做法是不可行的:
var f1 float32 = 3.14 var f2 float64 = 6.28 //类型不同,不能进行比较,会报错 // fmt.Println(f1 == f2) //类型不同,不能进行运算 f3 := f1 - f2 fmt.Println(f3)
解决方法:
var f1 float32 = 3.14 var f2 float64 = 6.28 //进行强制转换 f := float32(f2) fmt.Println(f1 == f) //false f3 := f1 - f fmt.Println(f3) //0
复数
c := complex(3, 4) fmt.Println(real(c), imag(c))//3 4
布尔值
注意bool值的true或者false,并不会自动转换为整型的1或者0。
字符型
单引号只能用来表示单个字符,不能用来括字符串。
双引号技能括单个字符,又能括字符串。
a := 'ab' //wrong b := 'x' //correct c := "y" //correct d := "abc" //correct
字符串
str1 := "你 " str2 := "好" //使用 + 进行字符串拼接 str3 := str1 + str2 //你 好 fmt.Println(str3) length := len(str1) //使用len()求字符串的长度时,求的是字节数,不是字符数 fmt.Println(length) //4 str := "hello world" //取某一个索引的字符 fmt.Println(str[0]) //104 fmt.Println(string(str[0])) //h //错误用法,不能修改字符串内部的值 //str[0] = "d" //可以改变字符串的值 str = "go to hell" fmt.Println(str) //go to hell
字符串截断
截断格式str[start:end],左闭右开区间,即end位置的字符不会包含在内。省略start时,默认start为0。省略end时,默认end为字符串长度len(str)。
str := "abcdefg" fmt.Println(str[2:4]) //cd fmt.Println(str[2:]) //cdefg fmt.Println(str[:4]) //abcd
字符串遍历
str := "abcdefg" length := len(str) for i := 0; i < length; i++ { fmt.Println(str[i], string(str[i])) } for index, value := range str { fmt.Println(index, string(value)) }
原生字符串字面值
使用``代替双引号。可以保存内容的格式,原样输出
str := ` menu: 1、 2、 ` fmt.Println(str)
指针
var num int = 10 var p *int = &num // 等价于 //p := &num fmt.Println(num, p, *p) //10 0xc42001a0f0 10
注意事项:
指针的默认值是nil,不是NULL,并且go语言中没有NULL常量
使用&取地址,使用*解引用
不支持C语言类似的指针运算,比如指针自增等。
使用“.”来访问目标成员,不支持“->”运算符
不存在函数指针
结构体指针
package main import "fmt" type person struct { Name string Age int } func main() { p := &person{"abc", 90} name := p.Name //等价于 //name := (*p).Name fmt.Println(name) }
数组指针
arr := [3]int{99, 999, 9999} p := &arr fmt.Println(arr) //[99 999 9999] fmt.Println(p) //&[99 999 9999] fmt.Println(*p) //[99 999 9999]
指针数组
var p [3]*int x, y, z := 1, 11, 111 p[0], p[1], p[2] = &x, &y, &z fmt.Println(p[0], p[1], p[2]) //0xc42001a0f0 0xc42001a0f8 0xc42001a100 fmt.Println(*p[0], *p[1], *p[2]) //1 11 111
二级指针
var num int = 10 p := &num //p保存着num的地址 pp := &p //pp保存着p的地址,即地址的地址 fmt.Println(p, *pp) //0xc42001a0f0 0xc42001a0f0 fmt.Println(&p, pp) //0xc42000c028 0xc42000c028 fmt.Println(*p, **pp) //10 10
type定义类型
使用type关键字定义新的类型名,一般出现在包一级,即函数外部,如果新建的类型名字首字母大写,则在包外可以使用,否则只能在包内使用。
格式:type new_type base_type
注意type和C语言的typedef不同,typedef只是定义别名而已,而Go语言的type不仅定义类型名称,还包括类型的行为。
package main import "fmt" type Score int func (s Score) Pass() bool { return s >= 60 } func main() { var s1 Score = 69 fmt.Println(s1.Pass()) //true }
虽然使用type关键字定义了一个新的类型,就像上面的Score和int,虽然在底层都是int,底层都是同一个类型,但是:不能直接进行比较、计算,必须要先转换后才可比较和计算。
标准输入输出
Print、Println、Printf
a, b, c := 1, "abc", true fmt.Println(a, b, c) //1 abc true fmt.Print(a, b, c, "\n") //1abctrue fmt.Printf("%d,%s,%t\n", a, b, c) //1,abc,true
Scan
var ( name string age int ) for { fmt.Println("please intput name,age") fmt.Scan(&name, &age) fmt.Println("name:", name, "\t age:", age, "\n") }
运行结果如下:
please intput name,age abc 30 name: abc age: 30 please intput name,age abc 50 name: abc age: 50 please intput name,age abc 50 xyz 99 name: abc age: 50 please intput name,age name: xyz age: 99
Scanln
var ( name string age int score int ) for { fmt.Println("please intput name,age,score") fmt.Scanln(&name, &age, &score) fmt.Println("name:", name, "\t age:", age, "\t score:", score, "\n") }
运行结果如下:
please intput name,age,score abc name: abc age: 0 score: 0 please intput name,age,score abc 30 name: abc age: 30 score: 0 please intput name,age,score abc 30 99 name: abc age: 30 score: 99
Scanf
var ( name string age int ) fmt.Println("please intput name,age") fmt.Scanf("%s %d", &name, &age) //输入时以空格分隔 fmt.Println("name:", name, "\t age:", age, "\n") fmt.Println("please intput name,age") fmt.Scanf("%s,%d", &name, &age) //输入时,以逗号分隔 fmt.Println("name:", name, "\t age:", age, "\n")
运行结果
please intput name,age abc 99 name: abc age: 99 please intput name,age xyz 88 name: xyz age: 99
注意,Scan并不会在遇到回车换行的时候结束输入。而Scanln和Scanf都是一旦遇到回车换行,就认为本轮输入(一个Scanln或者Scanf)结束,执行下一个Scanln或者Scanf。当然,缓冲的数据,可以自动赋值。
if选择结构
if score := 61; score > 80 { fmt.Println("优秀") } else if score > 60 { fmt.Println("及格") } else { fmt.Println("不及格") }
注意:花括号不可省,切不可另起一行。如果要声明变量,可以在if后面声明,并用分号分隔,分号后面跟条件。
最最重要的是:if后面的条件必须是bool类型的值或者结果为bool类型的表达式,不可以是整型或者其他类型。
switch选择结构
var length int = 3 switch length { case len("abc"): //可以是表达式 fmt.Println(3) case 4: fmt.Println(4) default: fmt.Println(5) } //输出 //3
Go语言中的switch case结构中,每一个case条件分支末尾不用加break;
case可以后面的条件可以使变量,也可以是常量,但是有一点:case后面的类型,要和switch后面的类型相同。
fallthrough关键字
var score int = 12 switch score { case 6: fallthrough case 12: fmt.Println(12) fallthrough case 24: fmt.Println(24) default: fmt.Println(36) }
//输出
//12
//24
如果某个case里面有fallthrough,那么,这个case的紧接着的下一个case条件会默认满足,直接执行写一个case中的语句,并不会判断下一个case的条件是否满足。
case可以这样写
var score int = 12 switch score { case 6, 12: fmt.Println(6, "或者", 12) default: fmt.Println(36) }
省略switch后面的表达式,此时相当于if else
var score int = 90 switch { case score > 80: fmt.Println("优秀") fallthrough case score > 60: fmt.Println("及格") default: fmt.Println("不及格") } //输出 //优秀 //及格
for循环
Go语言中没有while循环和do..while循环,只有一个for循环,但是for循环有三种形式,可以替代while循环和do while循环。
for i:=0;i<10;i++{ fmt.Println(i) } for { fmt.Println("这是死循环,相当于while(1)") } for i,v := range m{ fmt.Println("同样是死循环") }
上面三种用法分别对应其他语言中的for循环,while()循环,do..while循环。
在循环中可以使用break和continue来控制循环。