Golang 基本语法速查——变量、控制结构与函数

rollingstarky · · 654 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

一、基本结构

hello world 程序:

package main

import "fmt"

func main(){
        fmt.Println("你好,世界")
}

直接运行:

$ go run hello.go
你好,世界

构建可执行程序:

$ go build hello.go
$ ./hello
你好,世界

PS

  • Package 用于组织代码架构,类似于其他语言中的命名空间
  • 每个 go 源文件都必须属于(且只属于一个)特定的 package,一个 package 可以包含多个 go 代码文件
  • import 导入某个 package ,意味着获取了该 package 中可见对象的访问权限
  • import 导入的 package 未在后面的代码中使用会报错,no unnecessary code! 原则
  • main 函数没有任何参数且不返回任何值,它通常作为程序执行的入口

导入多个包:

import (
        "fmt"
        "os"
)

二、变量

变量定义和赋值:var identifier [type] = value

var a int
var b bool
var str string = "hello"
var i = 5
GOROOT := os.Getenv("GOROOT")

PS

  • b := false 等同于 var b = false 。借助 Go 语言的类型推断可以省略类型声明
  • := 或者 var 形式的变量赋值,包含变量初始化动作。即 a = 1 表示将 1 赋值给变量 a(a 必须已经创建),a := 1 表示新建变量 a,并将 1 赋值给 a。
  • 使用未定义的变量,定义的本地变量未在后续代码中使用,新建变量的名称已存在等都会报错
  • 推荐使用 := 的形式,但只应该在函数内部使用

三、字符串

连接字符串,+

s := "hel" + "lo"
s += " world"
fmt.Println(s)    // prints out "hello world"
  • 前缀匹配:strings.HasPrefix(s, prefix string) bool
  • 后缀匹配:strings.HasSuffix(s, suffix string) bool
  • 包含关系:strings.Contains(s, substr string) bool
  • 字符串替换:strings.Replace(str, old, new, n) string
  • 计算子字符串出现次数:strings.Count(s, str string) int
  • 分割字符串:strings.Split(s, sep string) []string
  • join 字符串:strings.join(sl []string, sep string) string

示例代码:

package main

import (
        "fmt"
        "strings"
)

func main() {
        str := "The quick brown fox jumps over the lazy dog"
        sl := strings.Split(str, " ")
        fmt.Printf("Splitted in slice: %v\n", sl)
        // 字符串分割后的返回值 sl 是数组
        for _, val := range sl {
                fmt.Printf("%s,", val)
        }

        fmt.Println()
        str2 := strings.Join(sl, "/")
        fmt.Printf("sl joined by / is: %s\n", str2)
}
// output
// Splitted in slice: [The quick brown fox jumps over the lazy dog]
// The,quick,brown,fox,jumps,over,the,lazy,dog,
// sl joined by / is: The/quick/brown/fox/jumps/over/the/lazy/dog

四、控制结构

if-else

if-else 结构语法如下:

if condition1 {
    // do something
} else if condition2 {
    // do something
} else {
    // catch-all or default
}

PSelse 旁边的 }{ 不能隔行,否则无法编译通过。

switch
switch var1 {
case val1:
    // do something
case val2:
    // do something
default:
    // catch-all or default
}
switch {
case condition1:
    // do something
case condition2:
    // do something
default:
    // catch-all or default
}
switch initialization {
case val1:
    // do something
case val2:
    // do something
default:
    // catch-all or default
}

示例代码:

package main

import (
    "fmt"
)

func Abs(x int) int {
    if x < 0 {
        return -x
    }
    return x
}

func main() {
    switch num := Abs(-5); {
    case num > 0:
        fmt.Println("Result is positive")
    case num < 0:
        fmt.Println("Never gonna happen")
    default:
        fmt.Println("Exact 0")
    }
}
// Result is positive
for

参考如下示例:

package main

import (
    "fmt"
)

func main() {
    str := "Go is a beautiful language"

    for ix :=0; ix < len(str); ix ++ {
        fmt.Printf("Character on position %d is: %c \n", ix, str[ix])
    }

    for pos, char := range str {
        fmt.Printf("Character on position %d is: %c \n", pos, char)
    }
}

五、函数

定义函数语法:

func g() {
}

注意不能写成如下形式:

func g()
{
}

函数调用语法:pack1.Function(arg1,arg2, ... ,argn)

Go 中的函数可以接收另一个函数作为参数,比如有下面两个函数:
f1(a, b, c int) 接收三个参数
f2(a, b int) (int, int, int) 有两个参数和三个返回值
则可以这样调用:f1(f2(a, b))

函数本身可以赋值给变量,如 add := binOp

参数与返回值

Go 中的函数可以接收 0 个或多个参数,返回 0 个或多个结果。
传给函数的参数通常会有名称,但是也可以没有名称只包含类型:func f(int, int, float64)

Go 函数的传参默认是按值传递,即实际传给函数的是参数值的复制。如调用 Function(arg1),函数 Function 收到的是 arg1 指向的值的副本,而不是 arg1 本身。
如果需要函数操作传入的参数本身,即 Function(arg1) 操作 arg1 本体的值,则需要传入参数的指针(内存地址)。使用如下形式:Function(&arg1)

大部分函数都需要返回值,可以是命名的也可以不命名。

数量未知的参数

函数的最后一个参数可以是 ...type 这样的形式,即 func myFunc(a, b, arg ...int) {} 。这表示函数可以接收相同类型的不定数量的参数。参考如下示例:

package main

import (
        "fmt"
)

func main() {
        x := Min(1, 3, 2, 0)
        fmt.Printf("The minimum is: %d\n", x)

        arr := []int{7, 9, 3, 5, 1}
        x = Min(arr...)
        fmt.Printf("The minimum in the array arr is: %d", x)
}

func Min(a ...int) int {
        if len(a) == 0 {
                return 0
        }
        min := a[0]
        for _, v := range a {
                if v < min {
                        min = v
                }
        }
        return min
}
// The minimum is: 0
// The minimum in the array arr is: 1
Defer

defer 关键字用于“延迟”执行某个函数或命令,由 defer 修饰的语句会在外部函数返回结果之后再执行。

package main

import (
    "fmt"
)

func main() {
    fmt.Printf("In Main function at the top\n")
    defer Function2()
    fmt.Printf("In Main function at the bottom\n")
}

func Function2() {
    fmt.Printf("Function2: Deferred until the end of the calling function")
}
// In Main function at the top
// In Main function at the bottom
// Function2: Deferred until the end of the calling function% 

如果 defer 语句中包含变量参数,则该参数的值在 defer 的位置已经确定。参考如下代码:

package main

import (
    "fmt"
)

func main() {
    i := 0
    defer fmt.Println(i)
    i++
    fmt.Println("The number is:")
}
// The number is:
// 0

defer 修饰的 Println 函数虽然在程序执行流的最后输出 i 值。但变量 idefer 处的值为 0,因此最后输出 0 而不是执行 i++ 后的 1 。

当代码中包含有多个 defer 语句时,这些语句会以 LIFO(后进先出,类似 stack)的顺序执行。

package main

import (
    "fmt"
)

func main() {
    for i := 0; i < 5; i++ {
        defer fmt.Printf("%d", i)
    }
}
// 43210
递归函数
package main

import (
    "fmt"
)

func main() {
    result := 0
    for i := 0; i <= 10; i++ {
        result = fibonacci(i)
        fmt.Printf("fibonacci(%d) is: %d\n", i, result)
    }
}

func fibonacci(n int) (res int) {
    if n <= 1 {
        res = 1
    } else {
        res = fibonacci(n-1) + fibonacci(n-2)
    }
    return
}
高阶函数

函数作为参数

package main

import "fmt"

func main() {
        callback(1, Add)
}

func Add(a, b int) {
        fmt.Printf("The sum of %d and %d is: %d\n", a, b, a+b)
}

func callback(y int, f func(int, int)) {
        f(y, 2)
}
// => The sum of 1 and 2 is: 3

(匿名)函数赋值给变量

package main

import "fmt"

func main() {
        for i := 0; i < 4; i++ {
                g := func(i int) { fmt.Printf("%d", i) }
                g(i)
                fmt.Printf(" - g is of type %T and has value %v\n", g, g)
        }
}
// => 0 - g is of type func(int) and has value 0x4839d0
// => 1 - g is of type func(int) and has value 0x4839d0
// => 2 - g is of type func(int) and has value 0x4839d0
// => 3 - g is of type func(int) and has value 0x4839d0

函数作为返回值

package main

import "fmt"

func main() {
        p2 := Add2()
        fmt.Printf("Call Add2 for 3 returns: %v\n", p2(3))

        TwoAdder := Adder(2)
        fmt.Printf("The result is: %v\n", TwoAdder(3))
}

func Add2() func(b int) int {
        return func(b int) int {
                return b + 2
        }
}

func Adder(a int) func(b int) int {
        return func(b int) int {
                return a + b
        }
}
// => Call Add2 for 3 returns: 5
// => The result is: 5

另一个版本的累加器,涉及到闭包:

package main

import "fmt"

func main() {
        f := Adder()
        fmt.Print(f(1), " - ")
        fmt.Print(f(20), " - ")
        fmt.Print(f(300))
}

func Adder() func(int) int {
        var x int
        return func(delta int) int {
                x += delta
                return x
        }
}
// => 1 - 21 - 321

参考资料

The Way To Go: A Thorough Introduction To The Go Programming Language


有疑问加站长微信联系(非本文作者)

本文来自:简书

感谢作者:rollingstarky

查看原文:Golang 基本语法速查——变量、控制结构与函数

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

654 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传