热门IT资讯网

第三章 Go语言表达式

发表于:2024-11-27 作者:热门IT资讯网编辑
编辑最后更新 2024年11月27日,第三章 Go语言表达式[toc]运算符二元运算符:除位操作之外,操作数据类型必须相同。如果其中一个是无显式类型声明的常量,那么该常量就会自动转型。代码实验如下:package mainimport "

第三章 Go语言表达式

[toc]

运算符

  • 二元运算符:
    除位操作之外,操作数据类型必须相同。如果其中一个是无显式类型声明的常量,那么该常量就会自动转型。代码实验如下:
    package mainimport "fmt"func main(){const v = 20var a byte = 10b := v + afmt.Printf("%T,%v\n",b,b)   //此时b的类型为int8const c float32 = 3.14d := c + vfmt.Printf("%T,%v",d,d)   //此时d的类型是float32}

    指针

    不能将内存地址与指针混为一谈,内存地址是内存中的每个字节单元的唯一编号;指针是一个实体;指针会分配内存空间,相当于一个专门用来 保存地址的整型变量

  • 取址运算符:&用于获取对象地址
  • 指针运算符:*用于间接引用目标对象
  • 二级指针: **T,如果包含包名的话则写成*package.T
    package mainimport "fmt"func main(){x := 10var p *int = &xfmt.Printf("%v\n%v",*p,p)}

    指针类型支持相等运算符,但不能做加减法运算或者类型转换。两个指针执行同一个地址,或者都为nil。那他们相等。

    初始化

    对于复合类型(数组,切片,字典,结构体)变量进行初始化时,有一些语法限制,如下:

  • 初始化表达式必须包含标签
  • 左花括号必须在类型尾部,不能另起一行
  • 多个成员初始值以逗号分隔
  • 允许多行,但是每行必须用逗号或者花括号结束
    正确的初始化栗子如下:

    package mainimport "fmt"func test1() {type data struct {    x int    y string}var a data = data{123, "abc"} //初始化b := data{    234,    "bcd",}c := []int{    1,    2,}d := []int{1, 23, 4,    233, 5,    12,    22,}fmt.Println(a)fmt.Println(b)fmt.Println(c)fmt.Println(d)}func main()  {test1()}

    流控制

    条件判断类

    if else:
    package mainimport "fmt"func xinit(){fmt.Println("heheheh")}func If_else(){x := 10if xinit();x == 0{    fmt.Println("hehehe")}if a,b := x+1,x+10;a < b{    fmt.Println("a < b")}else {    fmt.Println("error!")}}func main()  {If_else()}
  • 尽量减少代码块嵌套,让正常逻辑处于相同层次
    package mainimport ("fmt""errors""log")func check(x int) error {if x <=0 {    return errors.New("x <= 0")}return nil}func main()  {//If_else()//If_else2()x := 10if err := check(x);err == nil{    x++    fmt.Println(x)}else {    log.Fatal(err)   //如果x<0的话会输出错误日志}}

    main可以改造成如下的样子,以便查看

    func main()  {x := 100if err := check(x);err !=nil{    log.Fatal(err)}x++fmt.Println(x)}

  • 如果在多个条件中使用局部变量,那么只能保留原层次,或者直接使用外部变量
    package mainimport ("strconv""log""fmt")func main(){s := "9"n,err := strconv.ParseInt(s,10,64)     //将字符串转换成数字if err != nil{    log.Fatal(err)}else if n < 0 || n > 10{    log.Fatalln("invalid number!!")}fmt.Println(n)fmt.Println(err)}
  • 对于某些复杂的组合条件,就需要改成函数的形式
    package mainimport ("strconv""log""fmt")func main(){s := "9"if n,err := strconv.ParseInt(s,10,64);err != nil || n <0 || n > 10{    log.Fatalln("invalid num!!")}fmt.Println("ok")   //条件判断外层,不能引用条件参数}

    通过函数调用改进的版本:

    package mainimport ("strconv""errors""log""fmt")func check(s string) error {n ,err := strconv.ParseInt(s,10,64)if err != nil || n <0 || n > 10{    return errors.New("invalid number!")        }return nil}func main(){s := "8"if err := check(s);err != nil{    log.Fatalln(err)}fmt.Println("ok")}
    switch
    • 选择其中的一个分支执行
      package mainimport "fmt"func main(){switch x := 5;x {default:x+=100fmt.Println(x)case 5:x+=50fmt.Println(x)}}
  • fallthrougth:继续执行下一个case,但是不匹配下一个case的条件
    package mainimport "fmt"func main(){switch x:=5;x{default:    fmt.Println(x)case 5:    x += 10    fmt.Println(x)    fallthrough      //继续执行下一个case,但是不匹配条件    /*if x >= 15 {        break      //直接跳出循环    }    fallthrough*/case 6:    x += 20    fmt.Println(x)}}
  • 多条件switch
    package main

import (
"fmt"
)
func test1(){
switch x:=5;x{
default:
fmt.Println(x)
case 5:
x += 10
fmt.Println(x)
fallthrough //继续执行下一个case,但是不匹配条件
case 6:
x += 20
fmt.Println(x)
}
}
func test2(){
switch x:=5;x {
case 5:
x += 10
fmt.Println(x)
if x >= 15 {
break
}
fallthrough
case 6:
x += 20
fmt.Println(x)
}
}
func test3(){
switch x:=5; {
case x > 5:
fmt.Println("a")
case x > 0 && x <= 5:
fmt.Println("b")
default:
fmt.Println("z")
}
}
func main(){
test1()
test2()
test3()
}

### 循环#### for只有一种循环语句,支持常用的方式:``` gopackage mainimport "fmt"func count() int{    fmt.Println("count.")    return 3}func main(){    for i,c :=0,count();i < c;i++{        fmt.Println("a",i)    }    c := 0    for c < count(){        fmt.Println("b",c)        c++    }}
  • 循环数组,切片,字典要用for range;返回单值的话用_
    package mainfunc main(){data := [3]string{"a","b","c"}for i,s := range data{    println(i,s)}for i,_ range data{        println(i)    //返回单值}}
  • 无论是for还是for range,其定义的局部变量会重复使用
    package mainfunc main(){data := [3]string{"a","b","c"}for i,s := range data{    println(&i,&s)}}
  • range会复制目标数据,直接受影响的是数组;可以改用切片或者数组指针类型

    package mainimport ("fmt")func main(){data := [3]int{10,20,30}for i,x := range data{    if i == 0 {        data[0] += 100        data[1] += 200        data[2] += 300    }    fmt.Printf("x: %d\tdata: %d\n",x,data[i])    //经过复制的x,值不变}for i,x := range data[:]{    if i == 0 {        data[0] += 100        data[1] += 200        data[2] += 300    }    fmt.Printf("x: %d\tdata: %d\n",x,data[i])   //循环的切片,x发生了变化} }

    相关数据类型中,字符串,切片基本结构是很小的结构体;而字典,管道本身是指针封装,复制成本都比较低,无需专门做优化。

  • 如果range目标表达式是函数调用,也仅被执行一次
    package mainimport "fmt"func data() []int {fmt.Println("original data....")return []int{10,20,30}}func main(){for i,x := range data(){    fmt.Println(i,x)}}

    建议嵌套不要超过两层,否则会难以维护。必要时可以剥离,重构函数

  • break & continue
    package mainfunc test1(){for i :=0;i < 10 ;i++{    if i > 7{        break    }    println(i)}}func test2(){outer:    //定义标签,break和continue可在多层嵌套中指定标签    for x := 0;x < 5 ;x++{        for y := 0; y < 10 ; y++{            if y > 2 {                println()                continue outer            }            if x > 2{                break outer            }            print(x,":",y,":")        }    }}func main(){test1()test2()}
0