Go语言编程第二章顺序编程

参考书:Go语言编程

第二章  顺序编程

 

1 变量声明使用关键字var ,如下

    var v1 int

    var v2 string

    var v3  [10]int         //数组

    var v4 []int             //数组切片

    var v5  struct {

            f  int 

    }

    var v6  *int           //指针

    var v7  map[string]int    //  map类型,key为string类型,value为int类型

    var v8  func(a int) int

2 var可以将若干个同样需要声明的同种类型的变量放在一起,如下

    var (

            v1  int

            v2  string

    )

3 变量初始化

    var v1 int  =  10

    var v2  =  10     // 编译器根据赋值自动定义变量类型

    v2 :=  10  

 4 用“:=”初始化变量时,左侧的变量必须是未声明过的变量,否则会导致编译错误。只能在函数体内出现

 5 Go语言支持多重赋值,如下

        i , j = j , i

6 Go语言支持匿名变量为了避免不会因为返回多个值的函数来定义一堆不需要的变量,如下

        func GetName( ) ( firstName , lastName , nickName string) {

                return "May" , "Chan" , "Chibi" 

        }

        _ , _ , nickName := GetName( )

7 常量定义

        const Pi float64 = 3.1415926535

        const zero = 0.0

        const (

                size int64 = 1024

                eof = -1

        )

        const u , v  float32 = 0 , 3

        const a , b , c = 3, 5.0 , "foo"      // a = 3 , b = 5.0 , c = "foo"

8 常量定义的右值也可以是一个在编译期运算的常量表达式,如下

        const  mask  =  1 << 3      // ok 

         const Home = os.GetEnv("HOME")     //error , 因为os.GetEnv()只有在运行期才能知道返回结果,在编译期并不能确定

9 Go语言预定义了这些常量:true ,false和iota

10 iota在每一个const关键字出现时被重置为0,然后在下一个const出现之前,每出现一次iota,其所代表的数字会自动增1,如下

            const (               // iota重置为0

                    c0 = iota    // c0 = 0

                    c1 = iota    //  c1 = 1

                    c2 = iota    //  c2 = 2

            )

            const x = iota     // x = 0

            const (               // iota重置为0

                    c0 = iota    // c0 = 0

                    c1             //  c1 = 1

                    c2             //  c2 = 2

            )

 补充:const中每新增一行常量声明将使iota计数一次(iota可理解为const语句块中的行索引) 

const (
	n1 = iota    // 0
	n2           // 1
	n3           // 2
	n4           // 3
)
const (
	n1 = iota    // 0
	n2           // 1
	_            // 2
	n4           // 3
)
const (
	n1 = iota    // 0
	n2           // 1
	h2 = 100     // 100
	h3           // 100
	n4 = iota    // 4
	n5           // 5
)
const (
	a, b = iota + 1, iota + 2 //1,2
	c, d                      //2,3
	e, f                      //3,4
)

 

11 Go语言不支持enum关键字,Go常用const来实现枚举,如下

        const (

                Sunday = iota

                Monday

                Tuesday

                Wednesday

                Thursday

                Friday

                Saturday

                Sunday

         )

12 Go的基础类型,布尔类型(bool) ,整型(int8 , byte , int16 , int , uint , uintptr等) , 浮点类型(float32 , float64),复数类型(complex64 , complex128),字符串(string),字符类型(rune),错误类型(error),指针(pointer),数组(array),切片(slice),字典(map),通道(chan),结构体(struct),接口(interface)

13 布尔类型不能接受其他类型的赋值,也不支持自动或强制类型转换,如下

        var  b  bool

        b = true

        c := (1 == 2) 

        b = 1    // 编译错误

        b = bool(1)   // 编译错误

14 整型

 

  • int8        一个字节        -128 ~ 127
  • uint8        一个字节        0 ~ 255
  • int16        二个字节        -32768 ~ 32767
  • uint16        二个字节        0 ~ 65535
  • int32        四个字节        -2147483648 ~ 2147483647
  • uint32        四个字节        0 ~ 4294967295
  • int64        八个字节     
  • uint64
  • int            平台相关,在32位平台下为4字节,64位平台下为8字节
  • uint          平台相关,在32位平台下为4字节,64位平台下为8字节
  • uintptr      平台相关,在32位平台下为4字节,64位平台下为8字节

注:int和int32在Go语言里是被认为两种不同的类型,编译器是不会帮助做类型转换的

var value1 int32
value2 := 64     //  value2被自动推导为int类型
value1 = value2   // cannot use value2 (type int) as type int32 in assignment

    value1 = int32(value2)    // ok

15 两个不同类型的整型数不能直接比较,比如int8类型的数和int类型的数不能直接比较

16 Go语言定义了两个类型float32和float64,没有float类型。float32相当于C语言的float,float64相当于C语言的double。

        fvalue :=  12.0    // 默认推导为float64

17 因为浮点数不是精确的表达方式,直接用==来判断两个浮点数是否相等会有风险

18 复数

        var value1  complex64

        value1 = 3.2+12i

        value2 := 1 + 3i

        value3 := complex(3.2 , 12)       // value3 := 3.2 + 12i

19 字符串,字符串的内容可以用类似于数组下标的方式获取。字符串是不可变类型

        var str string

        str = "Hello world"

        ch := str[0]

20 字符串操作

        x + y        字符串拼接        "Hello" + "123"    // "Hello123"

        len(s)        字符串长度        len("hello")     // 5

        s[i]        取字符            "Hello"[0]         // 'H'

21 字符串遍历,Go语言支持两种方式遍历字符串,如下

  • 字节数组的方式遍历  

        str := "Hello,world"

        n := len(str)

        for i := 0 ; i < n ; i++ {

                ch := str[i]                  // ch的类型为byte

                fmt.Println(i , ch)

        }

  • 以Unicode字符遍历

        str := "Hello,world"

        for i , ch := range str {

                fmt.Println(i , ch)         // ch的类型为rune

        }

注:Go语言支持两种字符类型,一个是byte(uint8的别名),代表UTF-8字符串的单个字节的值,另一个是rune,代表单个Unicode字符。

22 数组的声明方式

  • [32]byte
  • [2*N] struct { x , y int32 }       // 复杂类型数组
  • [1000] *float64
  • [3][5] int
  • [2][2][2] float64

数组长度在定义后就不可更改,在声明时长度可以是常数也可以是变量。长度可以通过len( )函数获取

23 访问数组除了下标访问,可以使用关键字range,range会返回2个值,元素的数组下标和元素的值

        for i , v := range array {

                fmt.Println("Array element[" , i , "] = " , v)

        }

24 在Go语言中数组是一个值类型,不是引用类型,在赋值或参数传递时都会生成一个副本,修改不会改变原始数组。        

 

func main(){
   array := [5]int{1,2,3,4,5}
   array2 := array
   array2[2] = 4

   modify(array)
   fmt.Println("In main(), array values: ",array)
   fmt.Println("In main(), array2 values: ",array2)
}

func modify(array [5]int){
   array[0] = 10
   fmt.Println("In modify(), array values: ",array)
}
输出结果

In modify(), array values:  [10 2 3 4 5]
In main(), array values:  [1 2 3 4 5]
In main(), array2 values:  [1 2 4 4 5]

24.1 补充:数组切片看似是一个指向数组的指针,实际上是有自己的数据结构,可以抽象为以下3个变量

  • 一个指向原生数组的指针
  • 数组切片中的元素个数
  • 数组切片已分配的存储空间

25 创建数组切片的方法主要有两种 --- 基于数组和直接创建

  • 基于数组创建

        var myArray [10]int = [10]int {1,2,3,4,5,6,7,8,9,10}

        var mySlice []int = myArray[:5]   

  • 使用内置函数make( )创建数组切片

        mySlice1 :=  make([]int , 5)       // 创建元素个数为5,元素值都为0的数组切片

        mySlice2 :=  make([]int , 5 , 10)     // 创建元素个数为5,元素值都为0,实际预留10个元素的存储空间。len(mySlice2)是5

        mySlice3 := []int { 1 , 2 , 3 , 4 , 5 }

26 数组切片较数组多了一个存储能力(capacity),即元素个数和分配的空间可以是两个不同的值。

        mySlice :=  make([]int , 5 , 10)

        fmt.Println("len(mySlice): " , len(mySlice))       //  5,即元素个数

        fmt.Println("cap(mySlice): " , cap(mySlice))     //  10 即数组切片分配的空间大小

27 数组切片新增元素可以使用append( ),如下

  • mySlice = append(mySlice , 1 , 2 , 3)     // 在切片尾新增3个元素1,2,3
  • mySlice2 := []int { 8 , 7 , 9 }

      mySlice  =  append(mySlice , mySlice2 . . . )       // 后面必须有省略号,表示将mySlice2的所有元素都传入

28 基于数组切片创建数组切片

        oldSlice := []int { 1 , 2 , 3 , 4 , 5 }

        newSlice := oldSlice[ : 3]

补充一点,切片和数组创建的一个区别

func f(k [3]int){     // 要求参数是元素个数为3的数组
    fmt.Printf("%v\n",k)
}

func main(){
    a := [...]int{1,2,3}   // 元素个数是3的数组
    b := []int{1,2,3}
    f(a)    // ok
    f(b)    // error
}

29 数组切片内容复制,copy( src , des ) 函数将des的元素赋值到src中,同时函数返回一个复制个数值。如果两个数组切片个数不一样,按个数小的个数进行复制,如下

        slice1 :=  []int { 1 , 2 , 3 , 4 , 5 }

        slice2 :=  []int { 5 , 4 , 3 }

        copy(slice2 , slice1)     // 只会复制slice1的前3个元素到slice2中

        copy(slice1 , slice2)     // 只会复制slice2的3个元素到slice1的前3个位置

30 map

type PersonInfo struct {
	ID string
	Name string
	Address string
}
func main(){
	var personDB map[string]PersonInfo
	personDB = make(map[string]PersonInfo)
	personDB["12345"] = PersonInfo{"12345","Tom","Room123"}
	personDB["1"] = PersonInfo{"1","Tom","Room1"}
	person,ok := personDB["12345"]   // 找到了ok值为true,否则为false
	if ok {
		fmt.Println("Found person ",person.Name," with ID 1234.")
	}else {
		fmt.Println("Did not find person with ID 1234")
	}
}

        myMap := make(map[string] int)     // 创建map

        myMap := make(map[string] int , 100)    // 创建一个初始存储能力为100的map

        myMap := map[string] int {         // 创建并初始化

                "abc":123 ,

                "bcd":333 ,

        }

        delete( myMap , "abc")     // 删除某个key值的元素

31 map查找

        value , ok :=  myMap["abc"]      //查找会返回两个值,ok表示是否有这个元素

        if  ok  {

                    // toDo

         }

32 Go语言支持如下几种流程控制语句,还有break,continue和fallthrough

 

  • 条件语句,关键字为if ,else 和else if
  • 选择语句,关键字为switch,case和select
  • 循环语句,关键字为for和range
  • 跳转语句,关键字为goto

33 if语句,如下

        if  a < 5 {           // 条件语句不用加小括号(),大括号{ }一定要有

                return 0

        } else {

                return 1

        }

34 switch语句,如下       

i := 1
switch i {      // 左大括号{一定要和switch同一行
case 0:
   fmt.Println(0)    // 不需要用break来声明退出case
case 1:
   fmt.Println(1)
case 2:
   fallthrough      // fallthrough表示继续执行紧跟的下一个case
case 3:
   fmt.Println(3)
case 4, 5, 6:       //  单个case中可以出现多个结果选项
   fmt.Println("4,5,6")
default:
   fmt.Println("default")
}

switch{            //  可以不设定switch之后的条件表达式,只写一个switch
case 0<=i && i < 1:    // 条件表达式可以不只限制为常量或整数
   fmt.Println(0)
case 1<=i && i < 2:
   fmt.Println(1)
}

35 Go语言循环语句只支持for,不支持while和do-while

        for  i := 0 ; i < 10 ; i ++ {     // 条件语句不用加小括号( )

                fmt.Println(i)

        }

        sum := 0

        for {     // 无限循环

                sum ++

                if sum > 100 {

                        break

                }

        }

        a := []int{1,2,3,4,5,6,7}

        for i , j := 0 , len(a) - 1 ; i < j ; i , j = i+1 , j-1 {

                a[i] , a[j]  =  a[j] , a[i]

        }

补充:Go语言不支持以逗号为间隔的多个赋值语句,必须使用平行赋值的方式来初始化多个变量,即如下所示

for i:=1,j:=2;i<n;i++,j++ {   // error, 不支持多个赋值语句

}

for i,j :=1,2;i<n;i,j=i+1,j+1 {    // ok,支持平行赋值

}

36 Go语言的for循环支持continue和break来控制循环

37 跳转语句

        func myfunc( ) {

                i :=  0

                HERE :

                        fmt.Println(i)

                        i++

                        if i < 10 {

                                goto HERE

                        }

        }

38 函数定义

            func  Add(a int , b int) (ret  int , err error)

            func  Add(a , b int) int 

39 函数调用,先导入该函数所在的包,调用即可,如下

            import "mymath"      // 假设Add被放在一个叫mymath的包中

            c := mymath.Add(1 , 2)

40 Go语言有这样的规则,小写字母开头的函数只能在本包内可见,即为private,大写字母开头的函数才能被其他包使用,即public

41 不定参数,. . . type实际就是一个切片,即[ ] type

        func myfunc( args . . . int ) {   // 该函数可以接受不定数量的参数,并且这些参数类型都是int

                for _ , arg := range args {

                        fmt.Println(arg)

                }

        }

        myfunc(2 , 3)     // ok

        myfunc(1, 2, 3)   //  ok

42 不定参数的传递

        func myfunc( args . . . int) {

                myfunc3(args . . . )      // 不定参数的传递必须在后面加上省略号

                myfunc3(args[1 : ] . . . )    // 不定参数的传递必须在后面加上省略号

        }

43 任意类型的不定参数,使用interface{ }

        func Printf(format string , args . . . interface{ })

44 函数的一个实例

func MyPrintf(args ...interface{}){
   for _,arg:= range args{
      switch arg.(type){
      case int:
         fmt.Println(arg," is an int value")
      case string:
         fmt.Println(arg, " is a string value")
      case int64:
         fmt.Println(arg, " is an int64 value")
      default:
         fmt.Println(arg, " is an unknown type")
      }
   }
}

func main(){
   var v1 int = 1
   var v2 int64 = 234
   var v3 string = "hello"
   var v4 float32 = 1.234
   MyPrintf(v1,v2,v3,v4)
}

输出结果:

1  is an int value
234  is an int64 value
hello  is a string value
1.234  is an unknown type

45 匿名函数由一个不带函数名的函数声明和函数体组成,可以直接赋值给一个变量或直接执行

         f := func (a , b int , z float64 ) bool  {    // 没有函数名,直接给变量f赋值

                    return a * b < int(z)

         }

         func ( ch chan int ) {

                ch <- ACK    

        }  (reply_chan)     // 函数后带括号即直接执行,将reply_chan值传入函数中

补充:46 闭包,Go的匿名函数是一个闭包

  • 基本概念:闭包是可以包含自由(未绑定到特定对象)变量的代码块,这些变量不在这个代码块内或任何全局上下文中定义,而是在定义代码块的环境中定义。要执行的代码块(由于自由变量包含在代码块中,所以这些自由变量以及它们引用的对象没有被释放)为自由变量提供绑定的计算环境(作用域)
  • 闭包的价值:可以作为函数对象或匿名函数

在如下的闭包例子中,变量a指向的闭包函数引用了局部变量i和j,i的值被隔离了,在闭包外不能被修改。只有内部的匿名函数才能访问变量i,保证了i的安全性。

func main(){
	var j int = 5
	a := func()func(){    // 这个函数返回一个函数
		var i int = 10
		return func(){
			fmt.Printf("i,j: %d , %d\n",i,j)    // 引用了这个j变量,即外面j被修改,这里的j就引用了新值
		}
	}()     // 加上这个括号表示,返回的函数是会执行。
	a()
	j *= 2
	a()
}

47 error其实只是一个接口,定义如下

            type error interface {

                    Error() string

            }

48 一个函数可以有多个defer语句。defer语句调用顺序为先进后出,最后一个defer语句先执行

补充:Go语言引入了两个内置函数panic( )和recover( )以报告和处理运行时错误和程序中的错误场景:

func panic(interface{})
func recover() interface{}
  • panic( ): 当函数执行过程中调用panic( )函数时,正常的函数执行流程将立即终止,但函数中之前使用defer关键字延迟执行的语句将正常展开执行,之后该函数将返回到调用函数,并导致逐层向上执行panic流程。 
  • recover( ): 用于终止错误处理流程。一般情况下,recover( )应该在一个使用defer关键字的函数中执行以有效截取错误处理流程。

49 当函数执行过程中调用panic( ),正常的函数执行流程将立即终止。recover( )用于终止错误处理流程

补充:Go语言标准库提供了用于快速解析命令行参数的flag包。如下所示

var infile *string = flag.String("i","infile","File contains values for sorting")
var outfile *string = flag.String("o","outfile","File to receive sorted values")

func main(){
	flag.Parse()
	if infile != nil {
		fmt.Println("infile=",*infile," , outfile=",*outfile)
	}
}


$ ./test1 -i "hello" -o "ok"
infile= hello  , outfile= ok

 

1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值