手记

第三章 Go语言表达式


第三章 Go语言表达式

[toc]

运算符

二元运算符:

除位操作之外,操作数据类型必须相同。如果其中一个是无显式类型声明的常量,那么该常量就会自动转型。代码实验如下:

package main

import "fmt"

func main(){

const v = 20

var a byte = 10

b := v + a

fmt.Printf("%T,%v\n",b,b)   //此时b的类型为int8

const c float32 = 3.14

d := c + v

fmt.Printf("%T,%v",d,d)   //此时d的类型是float32

}

指针

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

取址运算符:&用于获取对象地址

指针运算符:*用于间接引用目标对象

二级指针: **T,如果包含包名的话则写成*package.T

package main

import "fmt"

func main(){

x := 10

var p *int = &x

fmt.Printf("%v\n%v",*p,p)

}

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

初始化

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

初始化表达式必须包含标签

左花括号必须在类型尾部,不能另起一行

多个成员初始值以逗号分隔

允许多行,但是每行必须用逗号或者花括号结束

正确的初始化栗子如下:

package main

import "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 main

import "fmt"

func xinit(){

fmt.Println("heheheh")

}

func If_else(){

x := 10

if 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 main

import (

"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 := 10

if err := check(x);err == nil{

    x++

    fmt.Println(x)

}else {

    log.Fatal(err)   //如果x<0的话会输出错误日志

}

}

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

func main()  {

x := 100

if err := check(x);err !=nil{

    log.Fatal(err)

}

x++

fmt.Println(x)

}

如果在多个条件中使用局部变量,那么只能保留原层次,或者直接使用外部变量

package main

import (

"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 main

import (

"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 main

import (

"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 main

import "fmt"

func main(){

switch x := 5;x {

default:

x+=100

fmt.Println(x)

case 5:

x+=50

fmt.Println(x)

}

}

fallthrougth:继续执行下一个case,但是不匹配下一个case的条件

package main

import "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

只有一种循环语句,支持常用的方式:

``` go

package main

import "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 main

func 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 main

func main(){

data := [3]string{"a","b","c"}

for i,s := range data{

    println(&i,&s)

}

}

range会复制目标数据,直接受影响的是数组;可以改用切片或者数组指针类型

package main

import (

"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 main

import "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 main

func 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()

}

©著作权归作者所有:来自51CTO博客作者Walix的原创作品,如需转载,请注明出处,否则将追究法律责任


0人推荐
随时随地看视频
慕课网APP