3 变量
变量是什么
声明单个变量
var name type 是声明单个变量的语法。
声明变量并初始化
声明变量的同时可以给定初始值。 var name type = initialvalue 的语法用于声明变量并初始化。
类型推断(Type Inference)
type
如果变量声明的语法是 var name = initialvalue,Go 能够根据初始值自动推断变量的类型。
ageint
声明多个变量
Go 能够通过一条语句声明多个变量。
声明多个变量的语法是 var name1, name2 type = initialvalue1, initialvalue2。
width is 100 height is 50
你可能已经想到,如果 width 和 height 省略了初始化,它们的初始值将赋值为 0。
上面的程序将会打印:
在有些情况下,我们可能会想要在一个语句中声明不同类型的变量。其语法如下:
使用上述语法,下面的程序声明不同类型的变量。
my name is naveen , age is 29 and height is 0
简短声明
Go 也支持一种声明变量的简洁形式,称为简短声明(Short Hand Declaration),该声明使用了 := 操作符。
声明变量的简短语法是 name := initialvalue。
my name is naveen age is 29
cannot assign 1 values to 2 variables
简短声明的语法要求 := 操作符的左边至少有一个变量是尚未声明的。考虑下面的程序:
在上面程序中的第 8 行,由于 b 已经被声明,而 c 尚未声明,因此运行成功并且输出:
但是如果我们运行下面的程序:
no new variables on left side of :=
变量也可以在运行时进行赋值。考虑下面的程序:
在上面的程序中,c 的值是运行过程中计算得到的,即 a 和 b 的最小值。上述程序会打印:
cannot use "naveen" (type string) as type int in assignment
4. 类型
下面是 Go 支持的基本类型:
-
bool
-
数字类型
-
int8, int16, int32, int64, int
-
uint8, uint16, uint32, uint64, uint
-
float32, float64
-
complex64, complex128
-
byte
-
rune
-
-
string
bool
bool 类型表示一个布尔值,值为 true 或者 false。
在上面的程序中,a 赋值为 true,b 赋值为 false。
c 赋值为 a && b。仅当 a 和 b 都为 true 时,操作符 && 才返回 true。因此,在这里 c 为 false。
当 a 或者 b 为 true 时,操作符 || 返回 true。在这里,由于 a 为 true,因此 d 也为 true。我们将得到程序的输出如下。
有符号整型
int8:表示 8 位有符号整型大小:8 位范围:-128~127
int16:表示 16 位有符号整型大小:16 位范围:-32768~32767
int32:表示 32 位有符号整型大小:32 位范围:-2147483648~2147483647
int64:表示 64 位有符号整型大小:64 位范围:-9223372036854775808~9223372036854775807
int:根据不同的底层平台(Underlying Platform),表示 32 或 64 位整型。除非对整型的大小有特定的需求,否则你通常应该使用 int 表示整型。大小:在 32 位系统下是 32 位,而在 64 位系统下是 64 位。范围:在 32 位系统下是 -2147483648~2147483647,而在 64 位系统是 -9223372036854775808~9223372036854775807。
value of a is 89 and b is 95
在上述程序中,a 是 int 类型,而 b 的类型通过赋值(95)推断得出。上面我们提到,int 类型的大小在 32 位系统下是 32 位,而在 64 位系统下是 64 位。接下来我们会证实这种说法。
在 Printf 方法中,使用 %T 格式说明符(Format Specifier),可以打印出变量的类型。Go 的 unsafe 包提供了一个 Sizeof 函数,该函数接收变量并返回它的字节大小。unsafe 包应该小心使用,因为使用 unsafe 包可能会带来可移植性问题。不过出于本教程的目的,我们是可以使用的。
%T%d
以上程序会输出:
从上面的输出,我们可以推断出 a 和 b 为 int 类型,且大小都是 32 位(4 字节)。如果你在 64 位系统上运行上面的代码,会有不同的输出。在 64 位系统下,a 和 b 会占用 64 位(8 字节)的大小。
无符号整型
uint8:表示 8 位无符号整型大小:8 位范围:0~255
uint16:表示 16 位无符号整型大小:16 位范围:0~65535
uint32:表示 32 位无符号整型大小:32 位范围:0~4294967295
uint64:表示 64 位无符号整型大小:64 位范围:0~18446744073709551615
uint:根据不同的底层平台,表示 32 或 64 位无符号整型。大小:在 32 位系统下是 32 位,而在 64 位系统下是 64 位。范围:在 32 位系统下是 0~4294967295,而在 64 位系统是 0~18446744073709551615。
浮点型
float32:32 位浮点数float64:64 位浮点数
下面一个简单程序演示了整型和浮点型的运用。
a 和 b 的类型根据赋值推断得出。在这里,a 和 b 的类型为 float64(float64 是浮点数的默认类型)。我们把 a 和 b 的和赋值给变量 sum,把 b 和 a 的差赋值给 diff,接下来打印 sum 和 diff。no1 和 no2 也进行了相同的计算。上述程序将会输出:
复数类型
complex64:实部和虚部都是 float32 类型的的复数。complex128:实部和虚部都是 float64 类型的的复数。
内建函数 complex用于创建一个包含实部和虚部的复数。complex 函数的定义如下:
该函数的参数分别是实部和虚部,并返回一个复数类型。实部和虚部应该是相同类型,也就是 float32 或 float64。如果实部和虚部都是 float32 类型,则函数会返回一个 complex64 类型的复数。如果实部和虚部都是 float64 类型,则函数会返回一个 complex128 类型的复数。
其他数字类型
byte 是 uint8 的别名。rune 是 int32 的别名。
在学习字符串的时候,我们会详细讨论 byte 和 rune。
string 类型
在 Golang 中,字符串是字节的集合。如果你现在还不理解这个定义,也没有关系。我们可以暂且认为一个字符串就是由很多字符组成的。我们后面会在一个教程中深入学习字符串。 下面编写一个使用字符串的程序。
My name is Naveen Ramanathan
还有许多应用于字符串上面的操作,我们将会在一个单独的教程里看见它们。
类型转换
Go 有着非常严格的强类型特征。Go 没有自动类型提升或类型转换。我们通过一个例子说明这意味着什么。
main.go:10: invalid operation: i + j (mismatched types int and float64)
要修复这个错误,i 和 j 应该是相同的类型。在这里,我们把 j 转换为 int 类型。把 v 转换为 T 类型的语法是 T(v)。
122
赋值的情况也是如此。把一个变量赋值给另一个不同类型的变量,需要显式的类型转换。下面程序说明了这一点。
在第 9 行,i 转换为 float64 类型,接下来赋值给 j。如果不进行类型转换,当你试图把 i 赋值给 j 时,编译器会抛出错误。
5 常量
定义
5-89I love Go67.89
看看下面的代码:
const50I love Goconst
cannot assign to a.
常量的值会在编译的时候确定。因为函数调用发生在运行时,所以不能将函数的返回值赋值给常量。
amath.Sqrt(4)
bmath.Sqrt(4)const b = math.Sqrt(4)error main.go:11: const initializer math.Sqrt(4) is not a constant)
字符串常量
Hello WorldSam
什么类型的字符串属于常量?答案是他们是无类型的。
Hello World
const hello = "Hello World"
Hello Worldhellohello
Samname
答案是无类型的常量有一个与它们相关联的默认类型,并且当且仅当一行代码需要时才提供它。在声明中 var name = "Sam" , name 需要一个类型,它从字符串常量 Sam 的默认类型中获取。
有没有办法创建一个带类型的常量?答案是可以的。以下代码创建一个有类型常量。
typedhellostring
Go 是一个强类型的语言,在分配过程中混合类型是不允许的。让我们通过以下程序看看这句话是什么意思。
defaultNameSam
myStringstring
myStringcustomNameSamSamcustomNamemyString
stringdefaultNamemyStringcustomNamemyStringstringdefaultNamecustomNamemain.go:7:20: cannot use defaultName (type string) as type myString in assignmen
布尔常量
truefalse
上面的程序是自我解释的。
数字常量
数字常量包含整数、浮点数和复数的常量。数字常量中有一些微妙之处。
让我们看一些例子来说清楚。
a5aa
55.65+6ii's type int, f's type float64, c's type complex128
现在我希望下面的程序能够正确的工作。
a5avar intVar int = aaintintvar complex64Var complex64 = aacomplex64
数字表达式
数字常量可以在表达式中自由混合和匹配,只有当它们被分配给变量或者在需要类型的代码中的任何地方使用时,才需要类型。
5.985.9/80.7375aa's type float64 value 0.7375
6. 函数(Function)
函数是什么?
函数是一块执行特定任务的代码。一个函数是在输入源基础上,通过执行一系列的算法,生成预期的输出。
函数的声明
在 Go 语言中,函数声明通用语法如下:
func functionname(parametername type) returntype {
// 函数体(具体实现的功能)
}
funcfunctionname (函数名)()returntype (返回值类型)(parameter1 type, parameter2 type) 即(参数1 参数1的类型,参数2 参数2的类型){}
函数中的参数列表和返回值并非是必须的,所以下面这个函数的声明也是有效的
func functionname() {
// 译注: 表示这个函数不需要输入参数,且没有返回值
}
示例函数
我们以写一个计算商品价格的函数为例,输入参数是单件商品的价格和商品的个数,两者的乘积为商品总价,作为函数的输出值。
func calculateBill(price int, no int) int {
var totalPrice = price * no // 商品总价 = 商品单价 * 数量
return totalPrice // 返回总价
}
pricenototalPricepriceno
price int, no intprice, no int
func calculateBill(price, no int) int {
var totalPrice = price * no
return totalPrice
}
functionname(parameters)
calculateBill(10, 5)
完成了示例函数声明和调用后,我们就能写出一个完整的程序,并把商品总价打印在控制台上:
package main
import (
"fmt"
)
func calculateBill(price, no int) int {
var totalPrice = price * no
return totalPrice
}
func main() {
price, no := 90, 6 // 定义 price 和 no,默认类型为 int
totalPrice := calculateBill(price, no)
fmt.Println("Total price is", totalPrice) // 打印到控制台上
}
该程序在控制台上打印的结果为
Total price is 540
多返回值
rectProps
面积 = 长 * 宽周长 = 2 * ( 长 + 宽 )
package main
import (
"fmt"
)
func rectProps(length, width float64)(float64, float64) {
var area = length * width
var perimeter = (length + width) * 2
return area, perimeter
}
func main() {
area, perimeter := rectProps(10.8, 5.6)
fmt.Printf("Area %f Perimeter %f", area, perimeter)
}
()func rectProps(length, width float64)(float64, float64)lengthwidth
Area 60.480000 Perimeter 32.800000
命名返回值
从函数中可以返回一个命名值。一旦命名了返回值,可以认为这些值在函数第一行就被声明为变量了。
上面的 rectProps 函数也可用这个方式写成:
func rectProps(length, width float64)(area, perimeter float64) {
area = length * width
perimeter = (length + width) * 2
return // 不需要明确指定返回值,默认返回 area, perimeter 的值
}
请注意, 函数中的 return 语句没有显式返回任何值。由于 area 和 perimeter 在函数声明中指定为返回值, 因此当遇到 return 语句时, 它们将自动从函数返回。
空白符
_ 在 Go 中被用作空白符,可以用作表示任何类型的任何值。
rectProps
rectPropsarea
package main
import (
"fmt"
)
func rectProps(length, width float64) (float64, float64) {
var area = length * width
var perimeter = (length + width) * 2
return area, perimeter
}
func main() {
area, _ := rectProps(10.8, 5.6) // 返回值周长被丢弃
fmt.Printf("Area %f ", area)
}
area, _ := rectProps(10.8, 5.6)_