通用技术 Go--Go 基础之包、函数、变量、常量

stack · 2017年05月15日 · 1702 次阅读

一门编程语言总是有它自己独特的结构和语法。同时,同属编程语言,它们之间又或多或少有着许许多多相似的地方。

本文将分享 Go 语言的函数变量常量等知识。如果你有其它编程语言的基础,那么你可以在学习 Go 的过程中进行 对照,感受多种不同的语言在解决同类问题上的规则和设定;如果你是编程零基础,那么 Go 语言的学习是你的 Coding 启蒙;因此,无论怎样,你都将受益。

包声明

示例文件:package.go

package main

import (
    "fmt"
    "math/rand"
)

func main() {
    fmt.Println("My favorite num is", rand.Intn(10))
}

package main定义了包名。在源文件中非注释的第一行指明这个文件属于哪个包,如package mainpackage main表示一个可独立执行的程序,每个 Go 应用程序都包含一个名为 main 的包。

引入包

示例:import.go

package main

import (
    "fmt"
    "math"
)

func main() {
    fmt.Printf("Now you have %g problems.", math.Sqrt(7))
}

import 语句告诉 Go 编译器该 go 程序需要使用的包名。

如果要引入的包有多个,可以使用:

  1. 括号形式;
import (
    "fmt"
    "math/rand"
)

推荐使用该形式。

  1. 分行形式;
import "fmt"
import "math"

导出名称(Exported names)

Exported names 翻译成导出名称不知道是否合理,此处待确认。

包可以通过控制哪些名称是外部可见的来隐藏内部实现信息。一个简单的规则是:

如果一个名字是大写字母开头的,那么该名字是导出的(Exported)

换句话说,如果方法或结构体等需要提供给外部访问,那它们就必须是首字母大写。如果你引入了一个包,那么也只能使用这个包的导出名称。

示例:exported-names.go

package main

import (
    "fmt"
    "math"
)

func main() {
    fmt.Println(math.pi)
}

注意:math.pi 的 p 是小写。

执行结果:

# command-line-arguments
.\exported-names.go:9: cannot refer to unexported name math.pi
.\exported-names.go:9: undefined: math.pi

将 math.pi 中的 p 改为大写后可正常执行:

3.141592653589793

函数

函数

函数可以没有参数,也可以一个或多个参数,参数的类型在参数名称之后。

示例:functions.go

package main

import "fmt"

func add(x int, y int) int {
    return x + y
}

func main() {
    fmt.Println(add(42, 13))
}

如果一组参数具有相同的类型,不必为它们一一声明类型,可以用一个类型代替:

x int, y int等价于x, y int

但类型要写在最后一个参数的后面,如果写成x int, y则会保错:

# command-line-arguments
.\functions-continued.go:5: syntax error: mixed named and unnamed function parameters

多返回值

Go 语言的函数支持多个返回值。

示例:multiple-results.go

package main

import "fmt"

func swap(x, y string) (string, string) {
    return y, x
}

func main() {
    a, b := swap("hello", "world")
    fmt.Println(a, b)
}

结果:

world hello

命名返回值

Go 语言函数的返回值可以被命名,这意味着,它们可以被当作函数体中已定义的变量来处理。

不带参数的 return 语句将返回那些被命名了的函数返回值。这种情况通常称之为 “bare return” 或 “naked return”。naked return 虽然可以减少代码的重复,但却使代码可读性降低,尤其是当代码中有多处 return 和多个返回值时。因此,naked return 应该只用在简单的函数体里。

示例:named-results.go

package main

import "fmt"

func split(sum int) (x, y int) {
    x = sum * 4 / 9
    y = sum - x
    return
}

func main() {
    fmt.Println(split(17))
}

变量

变量声明

var 语句声明一组变量,如同函数中的参数一样,类型放在最后。

示例:variables.go

package main

import "fmt"

var c, python, java bool

func main() {
    var i int
    fmt.Println(i, c, python, java)
}

变量初始化

变量在声明时也可以对变量进行初始化。这种情况下,变量的类型可以忽略,变量的类型将采用初始化的值的类型。

示例:variables-with-initializers.go

package main

import "fmt"

//var i, j int = 1, 2
var i, j = 1, 2

func main() {
    var c, python, java = true, false, "no!"
    fmt.Println(i, j, c, python, java)
}

简洁声明

函数体内:=可以代替 var 对变量进行初始化和赋值:

xxx := yyy 等价于 var xxx = yyy

示例:short-variable-declarations.go

package main

import "fmt"

func main() {
    var i, j int = 1, 2
    k := 3
    c, python, java := true, false, "no!"

    fmt.Println(i, j, k, c, python, java)
}

在函数体外,每个语句都应该以 Go 的关键字开头(如varfunc等等),所以:=在函数体外不可用,否则将报错:

# command-line-arguments
.\short-variable-declarations.go:5: syntax error: non-declaration statement outside function body

基本类型

Go 语言的基本类型有:

bool

string

int  int8  int16  int32  int64
uint uint8 uint16 uint32 uint64 uintptr

byte // alias for uint8

rune // alias for int32
     // represents a Unicode code point

float32 float64

complex64 complex128

int, uint, 和 uintptr根据操作系统的位数不同而不同。

零值

变量声明时,如果没有显性地指明初始值,将自动为它们分配零值。

零值的意思并不是数字 0,不同的类型有不同的零值

  • numeric(数值)类型的零值是数字 0
  • boolean(布尔)类型的零值是 false
  • strings(字符串)类型的零值是""(空字符串)

示例:zero.go

package main

import "fmt"

func main() {
    var i int
    var f float64
    var b bool
    var s string
    fmt.Printf("%v %v %v %q\n", i, f, b, s)
}

类型转换

示例:type-conversions.go

package main

import (
    "fmt"
    "math"
)

func main() {
    var x, y int = 3, 4
    var f float64 = math.Sqrt(float64(x*x + y*y))
    var z uint = uint(f)
    fmt.Println(x, y, z)
}

T(v)将把值v转换为类型T,如示例中的float64(x*x + y*y)uint(f)

Go 语言的不同类型之间的赋值需要进行显式转换。如将示例中的float64(x*x + y*y)中的float64去掉,将会报错:

# command-line-arguments
.\type-conversions.go:10: cannot use x * x + y * y (type int) as type float64 in argument to math.Sqrt

TIPS:在 LiteIDE 中,按住 Ctrl,点击引入的函数名称,可以跳转到该函数的源代码中,如 Sqrt 的源代码显示:

func Sqrt(x float64) float64

可见,Sqrt的参数要求是float64类型的,所以如果不对(x*x + y*y)进行类型转换,就会报错。

类型推断

当没有显式声明一个变量的类型时(使用:=var =),该变量的类型由等号右边的值(推断)决定。

当右边的值是无类型的数值常量时,左边变量的值的类型可能是intfloat64complex128的,具体取决于这个常量的精度,如:

i := 42           // int
f := 3.142        // float64
g := 0.867 + 0.5i // complex128

示例:type-inference.go

package main

import "fmt"

func main() {
    a := 42
    fmt.Printf("a is of type %T\n", a)
    b := 42i
    fmt.Printf("b is of type %T\n", b)
    c := "42"
    fmt.Printf("c is of type %T\n", c)
    d := 42.0
    fmt.Printf("d is of type %T\n", d)
    e := false
    fmt.Printf("e is of type %T\n", e)
    f := 'c'
    fmt.Printf("f is of type %T\n", f)
}

结果:

a is of type int
b is of type complex128
c is of type string
d is of type float64
e is of type bool
f is of type int32

常量

常量声明

常量的声明同变量类似,只是使用的关键字是const

常量的类型:character(字符), string(字符串), boolean(布尔), numeric(数值)

常量不能使用:=声明。

示例:constants.go

package main

import "fmt"

const Pi = 3.14

func main() {
    const World = "世界"
    fmt.Println("Hello", World)
    fmt.Println("Happy", Pi, "Day")

    const Truth = true
    fmt.Println("Go rules?", Truth)
    fmt.Println("")

    fmt.Printf("pi is of type %T\n", Pi)
    fmt.Printf("World is of type %T\n", World)
    fmt.Printf("Truth is of type %T\n", Truth)
}

结果:

Hello 世界
Happy 3.14 Day
Go rules? true

pi is of type float64
World is of type string
Truth is of type bool

数值常量

数值常量是高精度的值。

示例:numeric-constants.go

package main

import "fmt"

const (
    // Create a huge number by shifting a 1 bit left 100 places.
    // In other words,the binary number that is 1 followed by 100 zeroes.
    Big = 1 << 100
    // Shift it right again 99 places,so we end up with 1<<1,or 2.
    Small = Big >> 99
)

func needInt(x int) int { return x*10 + 1 }
func needFloat(x float64) float64 {
    return x * 0.1
}

func main() {
    fmt.Println(needInt(Small))
    fmt.Println(needFloat(Small))
    fmt.Println(needFloat(Big))
    //fmt.Println(needInt(Big))
}

如果运行fmt.Println(needInt(Big))则报overflows(溢出)

# command-line-arguments
.\numeric-constants.go:22: constant 1267650600228229401496703205376 overflows int

小结

本官方教程所承载的内容比较少,更像是一门简明教程。如果有不明白的地方,除了参阅其它教材、询问有经验的人,还可以通过多敲代码、主动试错等方式加深印象和理解。

牢记一句话:

好记性永远比不上烂笔头,大多数技能的熟练掌握都是多次重复(刻意练习)造就的。

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
暂无回复。
需要 登录 后方可回复, 如果你还没有账号请点击这里 注册