• GO程序设计2——面向过程基础知识


    1 简介                                                                       

    GO语言google开发的新语言。有如下特性:
      自动垃圾回收、更丰富的内置数据类型、函数多返回值、错误处理、匿名函数和闭包、类型和接口、并发编程、反射、多语言混合编程

    package main
    
    // 我们需要使用fmt包中的Println()函数
    
    import "fmt"
    
    func main() { 
        fmt.Println("Hello, world!") 
    } 

    1.1 代码结构                        

    package main:每个GO源代码文件的开头声明该Go代码所属的包,包是Go语言里最基本的分发单位,要生成可执行程序,必须建立一个名字为main的包,并且在该包中包含一个叫main()的函数(该函数是Go可执行程序的执行起点)。
    func main():主函数main(),该函数是执行程序的起点,不能带参数,也不能定义返回值。命令传入的参数在os.Args变量中保存。如果需要支持命令行开关,使用flag包。

    import 语句:导入该程序所需要的其他包。由于用到了系统函数Println(),所以导入该函数所属的fmt包。
    注意:不能把源代码文件中没有用到的包导进去,否则Go编译器会报编译错误

    func关键字:
    所有的Go函数(包括在对象编程中会提到的类型成员函数)以关键字func开头。一个常规的函数定义如下:

    func 函数名(参数列表)(返回值列表){
      //函数体
    }

      可以看出Go语言与其他语言定义函数的区别,它把返回值列表也列在里面。

    对应示例:

    func Compute(value1 int,value2 float64)(result float64,err error){
      //函数体
    }

      Go支持多个返回值。上面的函数Compute()返回了两个值,一个叫result,一个是err,并不是所有返回值都必须赋值,如果没有明确赋值的返回值被设置为默认值,会根据基本数据类型对返回值初始化,float64为0.0, error为nil,也就是result是0.0 err为nil

    注释:
    Go程序的代码注释有两种:块注释和行注释
    /*
    块注释
    */
    //行注释
      关于语句结束符号:Go程序不要求开发者在每个语句后面加上分号表示语句结束,当然加上也可以,但Google提供的IDE开发工具在加上分号;后编译时会自动消掉分号
    函数体外的大括号位置:
      在Java程序设计里面有提到过大括号怎么放。Go语言中,在函数的返回值后面紧着函数体的左大括号,不能另起一行,这一点与Java通常用法是一致的,也有人把同一个级别的函数体左括号单独起一行,与右括号放在一列,这样在Go语言中是不行的。

    func 函数名(参数列表)(返回值列表)
    {
      //函数体
    }

      其实可以发现左括号放在返回值列表后面是有一个好的地方是:在很多编辑器里面,比如notepad,它把左括号和右括号之间用线连起来,显得是一个整体,如果把左括号单独起一行,会显得函数定义时候func行不与函数体一起,而把左大括号放在func行,会显得整个函数浑然一体。

    若干命令:

    查看go版本:
    cmd —— go version输出 go version go1.0.3
    编译源程序
    go build HelloWorld.go
    运行编译后代码
    HelloWorld.exe

    函数的单元测试:
    xxx.go对应的单元测试是xxx_test.go,这是go工程里的命名规则

    2 顺序编程                                                           

    2.1 变量                             

      从根本上说,变量是对一块数据存储空间的命名,程序可以通过定义一个变量来申请一块数据存储空间,之后通过调用(引用)变量名来使用这块存储空间

    2.1.1 变量声明    

      Go语言的变量声明方式与其他语言相差比较大。引入了一个关键字var(但不是必须的),表示一个变量
    var 变量名 变量类型
    示例:var name string

      这种方式其实更符合英语习惯 可以把上面的定义方式扩展成英语:the variable name is a string 变量name是一个string,如果去掉动词、量词就可以看出var name string 比较近似我们平时使用的英语语法结构。

    类似地:

    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    //字典,或者说关联数组与Java的map类似,key为string类型,value为int类型
    var v8 func(a int) int

    可以使用var关键字声明若干个关键字

    var(
      v1 int
      v2 string
    )

      从上面多出的var关键字可以看出,有一个var关键字更加符合英语习惯,不仅如此,可以同时声明多个变量,把变量用一个关键字var包起来,形成一个整块,这样可读性更好,不会让变量乱放。

    2.1.2 变量赋值:      

    //定义一个变量
    var v1 int
    //对一个变量初始化赋值
    v1 = 10
    上面的两步可以合成,也就是定义加初始化用一个语句完成。

    有三种方式
    var v1 int = 10 //正确使用方式1
    var v2 = 10 //正确使用方式2,编译器可以自动推导出v2的类型
    v3 := 10 //正确使用方式3,编译器可以自动推导v3的类型
    :=这个运算符包含了定义和初始化两步操作。出现这个运算符的变量不应该是已经被定义过的,否则会编译错误。
      指定变量类型不是必须的,看起来有点像动态类型语言。但实际是静态语言。

    2.1.3 多重赋值    

      Go语言提供了多重赋值功能
      i,j = j,i

    2.1.4匿名变量    

      我们在使用传统的强类型语言编程时,经常会出现这种情况,即在调用函数时为了获取一个值,却因为该函数返回多个值而不得不定义一堆没用的变量。在Go中这种情况可以通过结合使
    用多重返回和匿名变量来避免这种丑陋的写法,让代码看起来更加优雅。
      假设GetName()函数的定义如下,它返回3个值,分别为firstName、lastName和nickName:

    func GetName() (firstName, lastName, nickName string) { 
      return "May", "Chan", "Chibi Maruko" 
    } 

      若只想获得nickName,则函数调用语句可以用如下方式编写: 

      _, _, nickName := GetName()
      这种用法可以让代码非常清晰,基本上屏蔽掉了可能混淆代码阅读者视线的内容,从而大幅降低沟通的复杂度和代码维护的难度。

    2.2 常量                               

      常量是指编译期间已知且不可改变的值,常量可以是数值类型(包括整型、浮点型和复数类型)、布尔类型、字符串类型

    2.2.1 字面常量        

      字面常量是指程序中硬编码的常量,如
    无类型 2 //由于2在许多数值类型定义域内,并且没有规定2的类型,因此是一个无类型,当然也可以指定2L,是一个long型的
    浮点型 3.1415926
    复数型 3.2+12i
    布尔型 true
    字符串 "true"

    2.2.2常量定义        

    通过const关键字,可以指定字面常量名字

    const Pi float64 = 3.1432423424234
    const zero = 0.0
    const(
    size int64 = 1024
    eof = -1//无类型整型常量
    )
    const u,v float32 = 0.3 //定义多重赋值
    const a,b,c = 3,4,"true" //a = 3,b = 4,c = "true",无类型整型和字符串常量

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

    const mask = 1 <<3
      常量的赋值是一个编译期行为,所以右值不能出现任何需要运行期才能得出结果的表达式(否则就不是常量了)
      下面的例子就会导致编译错误,常量就是运行前就已经确定的值。
    const Home = os.GetEnv("HOME")

    2.2.3 预定义常量   

      Go语言预定义了这些常量true、false和iota
      iota比较特殊,可以被认为是一个可被编译器修改的常量,在每一个const关键字出现时被
    重置为0,然后在下一个const出现之前,每出现一次iota,其所代表的数字会自动增1。
    从以下的例子可以基本理解iota的用法:

    const ( // iota被重设为0 
    c0 = iota // c0 == 0 
    c1 = iota // c1 == 1 
    c2 = iota // c2 == 2 
    ) 
    
    const ( 
    a = 1 << iota // a == 1 (iota在每个const开头被重设为0) 
    b = 1 << iota // b == 2 
    c = 1 << iota // c == 4 
    ) 
    
    const ( 
    u = iota * 42 // u == 0 
    v float64 = iota * 42 // v == 42.0 
    w = iota * 42 // w == 84 
    ) 
    const x = iota // x == 0 (因为iota又被重设为0了) 
    const y = iota // y == 0 (同上) 

      如果两个const的赋值语句的表达式是一样的,那么可以省略后一个赋值表达式。因此,上

    面的前两个const语句可简写为:

    const ( // iota被重设为0 
    c0 = iota // c0 == 0 
    c1 // c1 == 1 
    c2 // c2 == 2 
    ) 
    
    const ( 
    a = 1 <<iota // a == 1 (iota在每个const开头被重设为0) 
    b // b == 2 
    c // c == 4 
    ) 

    2.3 枚举                                

      枚举指一系列相关的常量,比如下面关于一个星期中每天的定义。通过上一节的例子,我们看到可以用在const后跟一对圆括号的方式定义一组常量,这种定义法在Go语言中通常用于定义
    枚举值。Go语言并不支持众多其他语言明确支持的enum关键字。
    下面是一个常规的枚举表示法,其中定义了一系列整型常量:

    const ( 
    Sunday = iota 
    Monday 
    Tuesday 
    Wednesday 
    Thursday 
    Friday 
    Saturday 
    numberOfDays // 这个常量没有导出 
    ) 

      同Go语言的其他符号(symbol)一样,以大写字母开头的常量在包外可见。 

    以上例子中numberOfDays为包内私有,其他符号则可被其他包访问。

    2.4 数据类型                       

    Go支持如下数据类型
    布尔类型:bool
    整型:byte int8 int16 int uint uintptr
    浮点类型:float32、float65
    复数类型:complex64、complex128
    字符串:string
    字符类型:rune
    错误类型:error

    此外Go语言也支持以下复合类型

    指针:pointer
    数组:array
    切片:slice
    字典:map
    通道:chan
    结构体:struct
    接口:interface
      在这些基础类型之上Go还封装了下面这几种类型:int、uint和uintptr等。这些类型的特点在于使用方便,但使用者不能对这些类型的长度做任何假设。对于常规的开发来说,用int
    和uint就可以了,没必要用int8之类明确指定长度的类型,以免导致移植困难。

    2.4.1布尔类型        

    Go语言中的布尔类型与其他语言基本一致,关键字也为bool,可赋值为预定义的true和false

    var v1 bool
    v1 = true
    //v2也会被推导为bool类型
    v2 := (1 == 2)

    布尔类型关键字是bool,只有true和false两种取值,不能接受其他类型的赋值,不支持自动或强制的类型转换。以下示例是错误的用法:

    var b bool
    b = 1
    b = bool(1)

    以下是正确的

    var b bool
    b = (1 != 0)

    2.3.2 整型              

      整型是所有编程语言里最基础的数据类型。下面是Go语言所支持的类型。

    1.类型表示

    需要注意的是,int 和int32在Go语言里被认为是两种不同的类型,编译器也不会帮你自动做类型转换,比如下面的例子是错误的:

    var value2 int32
    value1 := 64
    value2 = value1 

    编译错误类似于: 

    cannot use value1 (type int) as type int32 in assignment。
    使用强制类型转换可以解决这个编译错误:
    value2 = int32(value1) // 编译通过
    当然,开发者在做强制类型转换时,需要注意数据长度被截短而发生的数据精度损失(比如
    将浮点数强制转为整数)和值溢出(值超过转换的目标类型的值范围时)问题。
    2. 数值运算
      Go语言支持下面的常规整数运算:+、?、*、/和%。加减乘除就不详细解释了,需要说下的
    是,% 和在C语言中一样是求余运算,比如:
      5 % 3 // 结果为:2
    3. 比较运算
    Go语言支持以下的几种比较运算符:>、<、==、>=、<=和!=。这一点与大多数其他语言相
    同,与C语言完全一致。
    下面为条件判断语句的例子:

    i, j := 1, 2 
    if i == j { 
    fmt.Println("i and j are equal.") 
    } 

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

    各种类型的整型变量都可以直接与字面常量(literal)进行比较,比如:

    var i int32 
    var j int64 
    
    i, j = 1, 2 
    
    if i == j { // 编译错误 
    fmt.Println("i and j are equal.") 
    }
    
    
    if i == 1 || j == 2 { // 编译通过 
    fmt.Println("i and j are equal.") 
    }

    4. 位运算 

    Go语言支持位运算符。
    运 算 含 义 样 例
    x << y 左移 124 << 2 // 结果为496
    x >> y 右移 124 >> 2 // 结果为31
    x ^ y 异或 124 ^ 2 // 结果为126
    x & y 与 124 & 2 // 结果为0
    x | y 或 124 | 2 // 结果为126
    ^x 取反 ^2 // 结果为?3
    Go语言的大多数位运算符与C语言都比较类似,除了取反在C语言中是~x,而在Go语言中
    是^x。

    2.3.3 浮点型

      浮点型用于表示包含小数点的数据,比如1.234就是一个浮点型数据。Go语言中的浮点类型采用IEEE-754标准的表达方式。
    1. 浮点数表示
      Go语言定义了两个类型float32和float64,其中float32等价于C语言的float类型,float64等价于C语言的double类型。 在Go语言里,定义一个浮点数变量的代码如下:

    var fvalue1 float32 
    fvalue1 = 12 
    fvalue2 := 12.0 // 如果不加小数点,fvalue2会被推导为整型而不是浮点型 

      对于以上例子中类型被自动推导的fvalue2,需要注意的是其类型将被自动设为float64,

    而不管赋给它的数字是否是用32位长度表示的。因此,对于以上的例子,下面的赋值将导致编译
    错误:
    fvalue1 = fvalue2
    而必须使用这样的强制类型转换:
    fvalue1 = float32(fvalue2)
    2. 浮点数比较
      因为浮点数不是一种精确的表达方式,所以像整型那样直接用==来判断两个浮点数是否相等是不可行的,这可能会导致不稳定的结果。
    下面是一种推荐的替代方案:

    import "math" 
    
    // p为用户自定义的比较精度,比如0.00001 
    func IsEqual(f1, f2, p float64) bool { 
    return math.Fdim(f1, f2) < p 
    }

    2.3.4 复数类型  

      复数由实部和虚步组成。go支持复数类型,关键字是complex64

    var value1 complex64 // 由2个float32构成的复数类型 
    value1 = 3.2 + 12i 
    value2 := 3.2 + 12i // value2是complex128类型 
    value3 := complex(3.2, 12) // value3结果同 value2 

    2. 实部与虚部 

      对于一个复数z = complex(x, y),就可以通过Go语言内置函数real(z)获得该复数的实部,也就是x,通过imag(z)获得该复数的虚部,也就是y。 更多关于复数的函数,请查阅math/cmplx标准库的文档。

    2.3.5 字符串         

      在Go语言中,字符串也是一种基本类型。相比之下, C/C++语言中并不存在原生的字符串类型,通常使用字符数组来表示,并以字符指针来传递。 Go语言中字符串的声明和初始化非常简单,举例如下:

    var str string // 声明一个字符串变量 
    str = "Hello world" // 字符串赋值 
    ch := str[0] // 取字符串的第一个字符 
    fmt.Printf("The length of "%s" is %d 
    ", str, len(str)) 
    fmt.Printf("The first character of "%s" is %c.
    ", str, ch) 

    输出结果为: 

    The length of "Hello world" is 11
    The first character of "Hello world" is H.
      字符串的内容可以用类似于数组下标的方式获取,但与数组不同,字符串的内容不能在初始化后被修改,比如以下的例子:
    str := "Hello world" // 字符串也支持声明时进行初始化的做法
    str[0] = 'X' // 编译错误
      编译器会报类似如下的错误:
    cannot assign to str[0]
      在这个例子中我们使用了一个Go语言内置的函数len()来取字符串的长度。这个函数非常有用,我们在实际开发过程中处理字符串、数组和切片时将会经常用到。 本节中我们还顺便示范了Printf()函数的用法。有C语言基础的读者会发现,Printf()函数的用法与C语言运行库中的printf()函数如出一辙。读者在以后学习更多的Go语言特性时,可以配合使用Println()和Printf()来打印各种自己感兴趣的信息,从而让学习过程更加直观、有趣。

      Go编译器支持UTF-8的源代码文件格式。这意味着源代码中的字符串可以包含非ANSI的字符,比如“Hello world. 你好,世界!”可以出现在Go代码中。但需要注意的是,如果你的Go代
    码需要包含非ANSI字符,保存源文件时请注意编码格式必须选择UTF-8。特别是在Windows下一般编辑器都默认存为本地编码,比如中国地区可能是GBK编码而不是UTF-8,如果没注意这点在编译和运行时就会出现一些意料之外的情况。
      字符串的编码转换是处理文本文档(比如TXT、XML、HTML等)非常常见的需求,不过可惜的是Go语言仅支持UTF-8和Unicode编码。对于其他编码,Go语言标准库并没有内置的编码转
    换支持。不过,所幸的是我们可以很容易基于iconv库用Cgo包装一个。这里有一个开源项目:https://github.com/xushiwei/go-iconv。 

  • 相关阅读:
    Hadoop的运行痕迹
    生活常识
    hadoop集群崩溃恢复记录
    Hadoop_NameNode_代码分析_目录树(2)
    .NET Is 和 As 的区别
    hadoop集群管理之 SecondaryNameNode和NameNode
    sql2005分页存储过程原创
    c#生成json数据 JavaScript对json数据处理
    LVS改变ConnectionHashtable值
    MySQL Cluster集群配置
  • 原文地址:https://www.cnblogs.com/people/p/3248379.html
Copyright © 2020-2023  润新知