3.1.循环
func main() {
sum:=0
for i:=0;i<10;i++{
sum+=i
}
fmt.Println(sum)
sum := 1
for ; sum < 1000; {
sum += sum
}
fmt.Println(sum)
//仿while
for sum < 1000 {
sum += sum
}
fmt.Println(sum)
//无限循环
for{
}
}
3.2.条件
func main(){
if true {
fmt.Println("true")
}
if false{
fmt.Println("false");
}
// if简短语句
n:=2
if num:=math.Pow(float64(n),10);num<100{
fmt.Println("xxx")
}
// if else
if {
...
}else {
...
}
//go中switch的每个case自动添加了break语句;
//使用fallthrough可取消该功能;
//取值无需为常量
switch n {
case 1:
fmt.Println(1)
fallthrough
case 2:
fmt.Println(2)
case 3:
fmt.Println(3)
}
//无条件switch
n = 10
switch{
case n<10:
fmt.Println("n<10",n)
case n<20:
fmt.Println("n<20",n)
case n<30:
fmt.Println("n<30",n)
default:
fmt.Println("default")
}
3.3.defer
defer所包裹的语句会延迟执行,其执行顺序在return语句之后
若一个作用域中包含多个defer域,则按照栈调用的方式,后进先出进行延迟域的调用;类似fianlly语句,进行资源释放等操作;
//一下函数返回 "ret"
func hello() (ret string){
defer func(){
ret = "ret"
}()
fmt.Println("Hello")
ret = "111"
return "222"
}
//(1)当编译到defer语句时,其内的参数总是被直接传入
func a(){
i:=0
defer fmt.Println("i: ",i) //输出0
i++
return
}
//(2)多个defer语句的执行如同入栈,后进先出
func b(){
for i:=0;i<10;i++{
defer fmt.Prinltn(i);//输出 9 8 7 6 5 4 3 2 1 0
}
}
//(3)defer中的值总是会被预先编译算好,但只是延迟到最后返回
//函数返回 1
func c() (i int) {
defer func() {i++}()
return i
}
3.4.panic
往上抛出异常,类似 throw new RuntimeException();
3.5.recover
与defer语句中捕获异常,由于defer语句被延迟至最后执行,因此可检查到同一作用域下的异常;
func main() {
f()
}
func f() {
fmt.Println("Calling g.")
g(0)
fmt.Println("Returned normally from g.")
}
func g(i int) {
defer func() {
if r := recover(); r != nil {
fmt.Println("recovered in f", r)
}
}()
if i > 3 {
fmt.Println("Panicking")
panic(fmt.Sprintf("%v", i))
}
defer fmt.Println("Defer in g", i)
fmt.Println("Printing in g", i)
g(i + 1)
}
3.6.指针
指针保存了值的内存地址
类型 *T 是指向T类型值的指针,其值为nil
var p *int
func main() {
i:=10
p = &i
*p = -1
fmt.Println(i) // -1
}
3.7. 结构体
type Student struct{
Name string
Number string
}
func main(){
student := Student{Name: "liyuan", Number: "20181001332"}
//通过 . 来访问结构体字段
student.Name = "-1"
fmt.Println(student) //{-1 20181001332}
//结构体指针:结构体字段可以通过结构体指针来访问
// (*student).Name <=> stduent.Name
student2 := &student
student2.Name = "-2"
fmt.Println(student) //{-2 20181001332}
//结构体文法
v1 := Student{Name:"l1",Number:"num1"}
v2 := Student{Name: "l2"}
v3 := Student{Number: "num3"}
v4 := &Student{"l4","num4"} //创建一个*Student类型的结构体指针
}
3.8.数组
var a [2]string
a[0] = "name1"
a[1] = "name2"
fmt.Println(a) //[name1 name2]
//切片 -> 范围区间 [lo, hi)
//语法类似python,但没有负数概念 如 nums[0:-3]
var nums [10]int{0,1,2,3,4,5,6,7,8,9}
var nums1 [int] = num[1:4] //[1 2 3]
//切片共享底层数据
nums[1] = -1
fmt.Println(nums1) //[-1 2 3]
//切片文法
stus := []struct {
Name string
Number string
}{
{Name: "liyuan1", Number: "0001"},
{Name: "liyuan2", Number: "0002"},
{Name: "liyuan3", Number: "0003"},
}
fmt.Println(stus)
//切片默认取值
nums2 := nums[0:] //上界为切片的长度
nums3:= nums[:5] //下界为0
nums4:=nums[:]
//有了切片的概念,就会产生切片实际长度以及其总容量的概念 ,类似ArrayList<>();初始化时容量默认为
nums5:= nums[5:9]
fmt.Println(nums5) //[5 6 7 8]
fmt.Println(len(nums5)) //4
fmt.Println(cap(nums5)) //5
//参考 ArrayList<>()实现可知,ArrayList<>()时长度为0
//当我们向其中添加元素时
//会重设容器的大小
//并设置默认大小为0,就是所谓的容量
// 经过这些操作,我们现在就获得了一个容量为10,但长度为1的容器
func main(){
//nil切片,切片的零值为nil, nil切片的长度和容量均为0,且无共享底层数组
//使用make来创建数组
a: = make([]int, 5)
b:= make([]int,0,5)
fmt.Println(b) // []
b = b[:cap(b)]
fmt.Println(b) // [0,0,0,0,0]
b = b[1:]
fmt.Println(b) // [0,0,0,0]
//切片的切片
nums:= []int{1,2,3,4,5,6,7,8,9,10}
nums2 = nums[1,5] //[2 3 4 5]
nums3 = nums2[1,2] //[3]
//向切片添加元素
// func append(s []T, vs ...T) []T
//会产生一个新的数组
nums4 := append(nums,11,12,13)
// 切片遍历 index: 索引;value:值的副本
for index,value :=range nums{
fmt.Println(index,value)
}
//可通过 _ 来忽略参数
for index, _ := range nums{
...
}
for _, value := range nums{
...
}
}
3.9.map映射
打法和python如出一辙,其中nil表示没值,使用make进行初始化
var m map[int]string
type Stu struct{
Name string
Number string
}
func main(){
m = make(map[int]string)
m[0] = "liyuan0"
m[1] = "liyuan1"
fmt.Println(m) //map[0:liyuan0 1:liyuan1]
//结构体映射
m1 := map[string]Stu {
"0":{"liyuan0","0000"},
"1":{"liyuan1","0001"},
}
//修改映射值
m["0"] = {"liyuan2","0002"}
delete(m,"0")
//查找元素是否存在,若元素存在,则elem为该值,ok为true
elem, ok :=m["2"]
}
3.10.函数值(闭包)
函数本身也是值,我们可以像其他值一样传递它;
可用作函数的参数或返回值
//函数闭包,闭包是一个函数值,其引用了其他函数体之外的变量这些函数可以访问并赋予其引用的变量的值,一下为fibonacci闭包实现
func fibonacci() func() int {
pre0 := 0
pre1 := 1
return func() int {
tmp:=pre0 + pre1
pre0 = pre1
pre1 = tmp
return tmp
}
}
func main() {
f := fibonacci()
for i := 0; i < 10; i++ {
fmt.Println(f())
}
}
3.11.方法
type Vertex struct {
X, Y float64
}
//接受者的类型形式为 *T, 指针接受者的方法可以修改接受者指向
//的值。由于方法经常需要修改它的接受者,指针接受者比值接受者更为常用
func (self *Vertex) Abs() float64 {
return math.Sqrt(self.X*self.X + self.Y*self.Y)
}
//方法即带接受者参数的函数
//指针指向值的内存地址,类似于java中的引用,
//默认为传值调用,只不过指针传递的为地址
func SetVal1(t Teacher, name string, age uint) {
t.Name = name
t.Age = age
}
func SetVal2(t *Teacher, name string, age uint) {
t.Name = name
t.Age = age
}
func (self *Teacher) ToString() string {
ret := "name: " + self.Name + " age: " + strconv.Itoa(int(self.Age))
return ret
}
func main() {
t := Teacher{}
SetVal1(t, "liyuan1", 21)
fmt.Println(t)
SetVal2(&t, "liyuan2", 21)
fmt.Println(t)
//可以看出,此时t可以解释为 *t
fmt.Println(t.ToString())
fmt.Println((&t).ToString())
}
3.12.接口
3.12.1.接口定义与实现
接口类型是由一组方法签名定义的集合
接口类型的变量可以保存任何实现了这些方法的值;
类似于java中的接口,只不过在这里实现接口仅需要结构体实现相应的接口方法即可
//LiyuanConfiguration实现了InitializingBean接口
type InitializingBean interface {
afterPropertiesSet()
}
type LiyuanConfiguration struct {
}
func (self*LiyuanConfiguration) afterPropertiesSet() {
}
3.12.2.接口值
接口也是值,可以像值一样进行传递,可作为函数参数胡返回类型
接口值可看做包含值和具体类型的元组,调用时会执行具体接口实现
type InitializingBean interface {
afterPropertiesSet()
}
type Liyuan1Configuration struct {
}
func (self *Liyuan1Configuration) afterPropertiesSet() {
fmt.Println("liyuan1 set properties")
}
type Liyuan2Configuration struct {
}
func (self *Liyuan2Configuration) afterPropertiesSet() {
fmt.Println("liyuan2 set properties")
}
func main() {
var i InitializingBean
//选择不同的实现类
//i = &Liyuan1Configuration{}
i = &Liyuan2Configuration{}
i.afterPropertiesSet()
}
3.13.空接口
空接口:指定了0个方法的接口值;
空接口可以保存任何类型的值,因为每个类型都至少实现了0个方法,用于处理类型位置的值
func describe(i interface{}) {
fmt.Printf("(%v, %T)\n", i, i)
}
func main() {
describe("liyuan")
describe(1)
}
3.14.类型断言(类型强转)
//interface{}类型才有该功能
func main(){
var i interface{} = 1
s, ok := i.(string)
fmt.Println(s, ok)
}
//类型选择
func main(){
var i interface{} = 1
switch i.(type) {
case string:
fmt.Println("string")
case int:
fmt.Println("int")
case float64:
fmt.Println("float64")
default:
//没有匹配
}
3.15.异常错误
type error interface{
Error() string
}
func main(){
i, err := strconv.Atoi("42")
if err != nil {
fmt.Printf("couldn't convert number: %v\n", err)
return
}
fmt.Println("Converted integer: ", i)
}