Go语言基础,一

国庆体验一下大名鼎鼎的Go语言,IDE使用IEDA+Go插件,边敲代码边体会,感觉Go语言好酷

一、Hello World

和Java类似,go文件需要一个package包含,代码结构如下:

main

└── hello.go

// 包声明
// 每个Go应用程序都包含一个main的包,表示可以独立执行的程序
package main

// 引入包,fmt提供格式化IO
import "fmt"

// 函数
func main()  {
        /* 这是我的第一个Hello World程序 */
        fmt.Println("Hello World")  // 首字母大写表示暴露给外部使用
}

运行

go run hello.go

二、基本数据类型

类型和描述
布尔型布尔型的值只可以是常量 true 或者 false。一个简单的例子:var b bool = true。
数字类型整型 int 和浮点型 float,Go 语言支持整型和浮点型数字,并且原生支持复数,其中位的运算采用补码。
字符串类型:字符串就是一串固定长度的字符连接起来的字符序列。Go的字符串是由单个字节连接起来的。Go语言的字符串的字节使用UTF-8编码标识Unicode文本。
派生类型:包括: (a) 指针类型(Pointer) (b) 数组类型 (c) 结构化类型(struct) (d) 联合体类型 (union) (e) 函数类型 (f) 切片类型 (g) 接口类型(interface) (h) Map 类型 (i) Channel 类型

三、变量&常量

和C语言用法类似,但又动态语言的感觉,直接上代码:

// 包声明
// 每个Go应用程序都包含一个main的包,表示可以独立执行的程序
package main

// 引入包,fmt提供格式化IO
import "fmt"

// 自动判断类型
var a  = "Test"
var b = 10

// 连续声明多变量
var x, y int
var (
        c float32 = 1.25
        d bool = false  // 这个bool其实可以省略
        )

// 函数
func main()  {
        // 调用默认的打印方法
        fmt.Println(a, b)
        x, y = 4, 5
        x, y = y, x // 交换,和Python写法一致
        _, y = 100, 200  // _为只写变量,处理没用的返回值

        fmt.Println(c, d, x, y)

        t:=1  // 声明变量的简写形式,只能用在函数内部,不能在全局
        const PI  = 3.14  // 常量
        fmt.Println(&t, PI)  // C语言的取地址
}

运行结果:

Test 10
1.25 false 5 200
0xc420084040 3.14

四、基本运算符

和C语言几乎一样

package main

import "fmt"

func main()  {
        a := 21
        b := 10

        // 算术运算符
        fmt.Println("a + b = ", a + b)
        fmt.Println("a - b = ", a - b)
        fmt.Println("a * b = ", a * b)
        fmt.Println("a / b = ", a / b)
        fmt.Println("a % b = ", a % b)
        a ++
        fmt.Println("a ++ = ", a)
        a --
        fmt.Println("a -- = ", a)

        // 关系运算&逻辑运算
        fmt.Println("a < b = ", a < b)
        fmt.Println("a < b || a > 0 = ", a > b || a > 0)

        // 位运算
        fmt.Println("a ^ b = ", a ^ b)
        fmt.Println("a | b = ", a | b)
        fmt.Println("a & b = ", a & b)

        // 赋值运算
        a += 2
        fmt.Println("a += 2 = ", a)
        b <<= 2
        fmt.Println("b <<= 2 = ", b)
}

运行结果:

a + b =  31
a - b =  11
a * b =  210
a / b =  2
a % b =  1
a ++ =  22
a -- =  21
a < b =  false
a < b || a > 0 =  true
a ^ b =  31
a | b =  31
a & b =  0
a += 2 =  23
b <<= 2 =  40

五、条件分支

if和switch和C类似,select还不了解细节

package main

import "fmt"

func main() {
        a := 10
        // if语句
        if a > 20 {
                fmt.Println("a > 20")
        } else {
                fmt.Println("a <= 20")
        }

        // switch语句,不用break分隔,默认只会执行一个case
        // 如果要执行多个case,使用fallthrough关键字,然后用break终止
        var x interface{}

        switch xType := x.(type) {
        case nil:
                fmt.Println("类型", xType)
        case int:
                fmt.Println("类型为int")
        case float64:
                fmt.Println("类型为float64")
        case func(int) float64:
                fmt.Println("类型为func(int) float64")
        case bool, string:
                fmt.Println("类型为bool或string")
        default:
                fmt.Println("未知类型")
        }

        // select语句
    // 每个case是一个通信,每个channel的表达式都会被求值
        // 所有channel表达式都会被求值
        // 如果任意某个通信可以进行,它就执行;其他被忽略
        // 如果有多个case都可以运行,Select会随机公平地选出一个执行。其他不会执行
        // 否则:
        //              如果有default子句,则执行该语句
        //              如果没有default字句,select将阻塞,直到某个通信可以运行;Go不会重新对channel或值进行求值

        var c1, c2, c3 chan int
        var i1, i2 int
        select {
        case i1 = <-c1:
                fmt.Println("received ", i1, "from c1")
        case c2 <- i2:
                fmt.Println("sent ", i2, " to c2")
        case i3, ok := <-c3:
                if ok {
                        fmt.Println("received ", i3, "from c3")
                } else {
                        fmt.Println("c3 is closed")
                }
        default:
                fmt.Println("no communication")
        }
}

运行结果:

a <= 20
类型 <nil>
no communication

六、循环语句

go语言的循环只保留了for语句,控制语句break,continue、goto和C一样

package main

import "fmt"

func main() {
        // 指定次数
        var s = 0
        for i:=1; i<=5; i++ {
                s += i
        }
        fmt.Println("s = ", s)

        // while
        var a = 1
        var b = 3
        for a < b {
                a ++
                fmt.Println("a = ", a)
        }

        // 无限循环
        var t  = 0
        for {
                t ++
                if t > 3{
                        break
                }
                fmt.Println("t = ", t)
        }
}

运行结果:

s =  15
a =  2
a =  3
t =  1
t =  2
t =  3

七、定义函数

基本用法与C相同,不过增加了一些动态性

package main

import "fmt"

// 基本用法
func max(num1, num2 int) (string, int) {
        if num1 > num2 {
                return "max num: ", num1 // 返回多个值
        } else {
                return "max num: ", num2
        }
}

type Circle struct {
        radius float64
}

// 函数方法的用法,getArea绑定接收者Circle
func (c Circle)  getArea() float64 {
        return 3.14 * c.radius * c.radius
}


// 使用匿名函数实现闭包,可以使用外部变量而不必声明
// 注意这里返回一个匿名函数func int
func getSequence()  func() int{
        // 这里模拟了C语言的静态变量
        i := 0
        return func() int {
                i += 1
                return i
        }
}

func main() {
        // 函数可以作为值来传递
        op := max
        fmt.Println(op(100, 200))

        // 函数方法
        var c1 Circle
        c1.radius = 10
        fmt.Println("Area of Circle(c1) = ", c1.getArea())

        // 闭包
        nextNum := getSequence()
        fmt.Println(nextNum())
        fmt.Println(nextNum())
        fmt.Println(nextNum())

        nextNum2 := getSequence()  // 创建另一个函数,重新计数
        fmt.Println(nextNum2())
        fmt.Println(nextNum2())
}

运行结果

max num:  200
Area of Circle(c1) =  314
1
2
3
1
2