一门编程语言总是有它自己独特的结构和语法。同时,同属编程语言,它们之间又或多或少有着许许多多相似的地方。
本文将分享 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 main
。package 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 程序需要使用的包名。
如果要引入的包有多个,可以使用:
import (
"fmt"
"math/rand"
)
推荐使用该形式。
import "fmt"
import "math"
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 的关键字开头(如var
、func
等等),所以:=
在函数体外不可用,否则将报错:
# 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,不同的类型有不同的零值
:
示例: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 =
),该变量的类型由等号右边的值(推断)决定。
当右边的值是无类型的数值常量时,左边变量的值的类型可能是int
、float64
或complex128
的,具体取决于这个常量的精度,如:
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
本官方教程所承载的内容比较少,更像是一门简明教程。如果有不明白的地方,除了参阅其它教材、询问有经验的人,还可以通过多敲代码、主动试错等方式加深印象和理解。
牢记一句话:
好记性永远比不上烂笔头,大多数技能的熟练掌握都是多次重复(刻意练习)造就的。