作用域为已声明标识符所表示的常量、类型、变量、函数或包在源代码中的作用范围。
Go 语言中变量可以在三个地方声明:
• 函数内定义的变量称为局部变量
• 函数外定义的变量称为全局变量
• 函数定义中的变量称为形式参数
接下来让我们具体了解局部变量、全局变量和形式参数。
在函数体内声明的变量称之为局部变量,它们的作用域只在函数体内,参数和返回值变量也是局部变量。
在函数体外声明的变量称之为全局变量,全局变量可以在整个包甚至外部包(被导出后)使用。
注:Go 语言程序中全局变量与局部变量名称可以相同,但是函数内的局部变量会被优先考虑。
形式参数会作为函数的局部变量来使用。实例如下:
package main
import "fmt"
/* 声明全局变量 */
var a int = 20;
func main() { /* main 函数中声明局部变量 */
var a int = 10
var b int = 20
var c int = 0
fmt.Printf("main()函数中 a = %d\n", a);
c = sum( a, b);
fmt.Printf("main()函数中 c = %d\n", c);
}
/* 函数定义-两数相加 */
func sum(a, b int) int {
fmt.Printf("sum() 函数中 a = %d\n", a);
fmt.Printf("sum() 函数中 b = %d\n", b);
return a + b;
}
以上代码的执行结果为:
main()函数中 a = 10
sum() 函数中 a = 10
sum() 函数中 b = 20
main()函数中 c = 30
初始化局部和全局变量
Go 语言提供了数组类型的数据结构。 数组是具有相同唯一类型的一组已编号且长度固定的数据项序列,这种类型可以是任意的原始类型例如整形、字符串或者自定义类型。 相对于去声明 number0,number1,...,andnumber99 的变量,使用数组形式 numbers[0], numbers[1] ..., numbers[99]更加方便且易于扩展。 数组元素可以通过索引(位置)来读取(或者修改),索引从 0 开始,第一个元素索引为 0,第二个索引为 1,以此类推。
var variable_name [SIZE] variable_type
以上为一维数组的定义方式。数组长度必须是整数且大于 0。
例如以下定义了数组 balance 长度为 10 类型为 float32:
var balance [10] float32
如下演示了数组的初始化:
var balance = [5]float32{1000.0, 2.0, 3.4, 7.0, 50.0}
初始化数组中 {} 中的元素个数不能大于 [] 中的数字。 如果忽略 [] 中的数字不设置数组大小,Go 语言会根据元素的个数来设置数组的大小。
数组元素可以通过索引(位置)来读取。格式为数组名后加中括号,中括号中为索引的值。例如:
float32 salary = balance[9]
以上实例读取了数组 balance 第 10 个元素的值。 以下演示了数组完整操作(声明、赋值、访问)的实例:
package main
import "fmt"
func main() {
var n [10]int /* n 是一个长度为 10 的数组 */
var i,j int
/* 为数组 n 初始化元素 */
for i = 0; i < 10; i++ {
n[i] = i + 100 /* 设置元素为 i + 100 */
}
/* 输出每个数组元素的值 */
for j = 0; j < 10; j++ {
fmt.Printf("Element[%d] = %d\n", j, n[j] )
}
}
以上代码执行结果为:
Element[0] = 100
Element[1] = 101
Element[2] = 102
Element[3] = 103
Element[4] = 104
Element[5] = 105
Element[6] = 106
Element[7] = 107
Element[8] = 108
Element[9] = 109
如果想传递一个一维数组作为参数到一个函数中,必须声明函数形式参数以下面两 种方式的其中一种,两个声明方法都产生类似的结果,因为每个方式都告诉编译器 要接收一个整数数组。类似的方式,可以传递多维数组作为形式参数。
方法-1 形式参数作为一个已知大小数组如下:
void myFunction(param [10]int)
{
}
方法二
形式参数作为一个为指导大小的数组如下:
void myFunction(param []int)
{
}
现在,考虑下面的函数,它将数组作为参数和另一个指定数组大小的参数,并基于 传递的参数,计算数组传递的数组中每个元素的平均值返回,如下:
func getAverage(arr []int, int size) float32
{
var i int
var avg, sum float32
for i = 0; i < size; ++i {
sum += arr[i]
}
avg = sum / size
return avg;
}
主函数调用:
package main
import "fmt"
func main() {
/* an int array with 5 elements */
var balance = []int {1000, 2, 3, 17, 50}
var avg float32
/* pass array as an argument */
avg = getAverage( balance, 5 ) ;
/* output the returned value */
fmt.Printf( "Average value is: %f ", avg );
}
func getAverage(arr []int, size int) float32 {
var i,sum int
var avg float32
for i = 0; i < size;i++ {
sum += arr[i]
}
avg = float32(sum / size)
return avg;
}
结果为:
Average value is: 214.400000
Go 语言中指针是很容易学习的,Go 语言中使用指针可以更简单的执行一些任务。 我们都知道,变量是一种使用方便的占位符,用于引用计算机内存地址。 Go 语言的取地址符是 &,放到一个变量前使用就会返回相应变量的内存地址。
指针是一个变量,其值是另一个变量的地址,即存储器位置的直接地址。类似变量或常量一样,必须要先声明一个指针,然后才能使用它来存储任何变量地址。指针变量声明的一般形式是 类似于变量和常量,在使用指针前你需要声明指针。指针声明格式为:
var var_name *var-type
指针使用流程:
在指针类型前面加上 * 号(前缀)来获取指针所指向的内容。
package main
import "fmt"
func main() {
var a int= 20 /* 声明实际变量 */
var ip *int /* 声明指针变量 */
ip = &a /* 指针变量的存储地址 */
fmt.Printf("a 变量的地址是: %x\n", &a )
/* 指针变量的存储地址 */
fmt.Printf("ip 变量储存的指针地址: %x\n", ip )
/* 使用指针访问值 */
fmt.Printf("*ip 变量的值: %d\n", *ip )
}
以上实例执行输出结果为:
a 变量的地址是: 20818a220
ip 变量储存的指针地址: 20818a220
*ip 变量的值: 20
当一个指针被定义后没有分配到任何变量时,它的值为 nil。 nil 指针也称为空指针。 nil 在概念上和其它语言的 null、None、nil、NULL 一样,都指代零值或空值。 一个指针变量通常缩写为 ptr。
package main
import "fmt"
func main() {
var ptr *int
fmt.Printf("ptr 的值为 : %x\n", ptr )
}
结果为:
ptr 的值为 : 0
package main
import "fmt"
const MAX int = 3
func main() {
a := []int{10,100,200}
var i int
for i = 0; i < MAX; i++ {
fmt.Printf("Value of a[%d] = %d\n", i, a[i] )
}
}
结果为:
Value of a[0] = 10
Value of a[1] = 100
Value of a[2] = 200
可能有一种情况,当想要维护一个数组,它可以存储指向 int 或字符串或任何其 他可用的数据类型的指针。下面是一个指向整数的指针数组的声明:
var ptr [MAX]*int;
这里将 ptr 声明为一个 MAX 整数的指针数组。 因此,ptr 中的每个元素现在保存 一个指向 int 值的指针。以下示例使用三个整数,它们将存储在指针数组中,如 下所示:
package main
import "fmt"
const MAX int = 3
func main() {
a := []int{10,100,200}
var i int
var ptr [MAX]*int;
for i = 0; i < MAX; i++ {
ptr[i] = &a[i] /* assign the address of integer. */
}
for i = 0; i < MAX; i++ {
fmt.Printf("Value of a[%d] = %d\n", i,*ptr[i] )
}
}
结果为:
Value of a[0] = 10
Value of a[1] = 100
Value of a[2] = 200
指向指针的指针是多重间接的形式或指针链。通常,指针包含变量的地址。当定义 指向指针的指针时,第一个指针包含第二个指针的地址,它指向包含实际值的位 置,如下所示。
作为指向指针的指针的变量必须如此声明。这是通过在其名称前面添加一个星号 (*)来实现的。 例如,以下是一个指向 int 类型的指针的声明
var ptr **int;
当目标值由指向指针的指针间接指向时,访问该值需要应用两个星号(**)运算符
package main
import "fmt"
func main() {
var a int
var ptr *int
var pptr **int
a = 3000
/* take the address of var */
ptr = &a
/* take the address of ptr using address of operator & */
pptr = &ptr
/* take the value using pptr */
fmt.Printf("Value of a = %d\n", a )
fmt.Printf("Value available at *ptr = %d\n", *ptr )
fmt.Printf("Value available at **pptr = %d\n", **pptr)
}
结果为:
Value of var = 3000
Value available at *ptr = 3000
Value available at **pptr = 3000
Go 编程语言允许传递一个指针到函数中。 为此,只需将函数的参数声明为指针类 型。 看看下面一个简单的例子,传递了两个指针给一个函数,并在函数里面改变它们的 值,这个值反映在调用函数中:
package main
import "fmt"
func main() {
/* local variable definition */
var a int = 100
var b int= 200
fmt.Printf("Before swap, value of a : %d\n", a )
fmt.Printf("Before swap, value of b : %d\n", b )
/* calling a function to swap the values.
* &a indicates pointer to a ie. address of variable a and
* &b indicates pointer to b ie. address of variable b.
*/
swap(&a, &b);
fmt.Printf("After swap, value of a : %d\n", a )
fmt.Printf("After swap, value of b : %d\n", b )
}
func swap(x *int, y *int) {
var temp int
temp = *x /* save the value at address x */
*x = *y /* put y into x */
*y = temp /* put temp into y */
}
结果为:
Before swap, value of a :100
Before swap, value of b :200
After swap, value of a :200
After swap, value of b :100