Day4 Variable

Background

如同前一章节的import一样,在Go的世界当中是不允许浪费任何资源的,因此只要变数进行了宣告就需要被使用,否则会出现variable declared and not used的错误。

但有一例外,那就是变数名称命名为 _ , 这表示你并不为该变数进行宣告。

程序码解说

变数宣告

首先我们一样创建一个名为variable.go的文件,并在该文件进行解说与范例撰写。

var Name Type = Expression

package main

import "fmt"

func main()  {
  var x int = 8
	var a = 16
	var b int
	var _ = 10
	fmt.Println(x, a, b)
}

运行後可得结果

8 16 0
  1. 如果省略型别Type,会由表达式Expression决定Type
  2. 如果省略表达式Expression,会由型别Type来决定初始值为多少,常见的初始值有int之於0, bool之於false, string之於" "...等
  3. 若需要宣告一个全域变数只能透过var

短宣告

Name := Expression

宣告declare(:=) 跟 指派assign(=)是不同的,一次宣告多个变数,若已宣告过的变数会自动变成assign效果

func main()  {
	var b int = 123
	a, b := 100, 99
	c, b := 0, 1
	fmt.Println(a, b, c)
}

运行後可得结果

100 1 0

短宣告方便,常常使用来宣告初始化大量、生命周期短的区域变数(像是回圈内的i, j变数)。

反之一般宣告则用来宣告长周期且型别明确的变数。

此外,如果看到下面类型的变数短宣告

result, err := ...

result, err都将会是区域变数喔。

常数宣告

无法更动、无法删除的变数,但用法跟变数var一样,const後面可以接任何型别,

因为常数是无法更动的,因此常数名称通常为全大写

const PI = 3.14159
const HELLO = "Hello World"

ITOA

iota希腊字符,在Golang中是关键字之一,用在宣告常数中,

效果为数字递增iota本身数值从0开始,

主要让工程师不用手动打递增数像是0、1、2、3...。

const (
	A = iota       // 0
	B              // 1
	_              // 2 占位符也会被计算
	C              // 3
	D = iota * 0.1 // 0.4 接续前面的 iota
	E              // 0.5
	F              // 0.6
	G              // 0.7
)

起始值也不一定要从0开始

const (
	X = iota + 100 // 100
	Y              // 101
	Z              // 102
)

也常被拿来作 左移右移(Shift Bit) 运算

const (
	b1 = 1 << iota // 1  右侧被塞入0个bit (2^0 二的零次方)
	b2             // 2  右侧被塞入1个bit (2^1 二的一次方)
	b3             // 4  右侧被塞入2个bit
	b4             // 8  
	b5             // 16 
)

变数注意事项

变数是否被overwrite(1)

package main

import "fmt"

var a = "Hello!"

func main()  {
	b := 10
	fmt.Println(&a, a, &b, b)

	a, b := 100, 99
	fmt.Println(&a, a, &b, b)
}

运算後可得结果

0x1157c80 Hello! 0xc000118000 10
0xc000118008 100 0xc000118000 99

只要有对相同变数名称再次进行宣告,代表宣告新的变数名称以及使用新的记忆体空间,

这也意味着原本的全域变数a的地址被覆盖掉了。

变数是否被overwrite(2)

package main

import "fmt"

var i = 100

func main() {
	fmt.Println(&i)

	i = 200
	fmt.Println(&i)

	i := 150
	fmt.Println(&i)

	i, j := 250, 100
	fmt.Println(&i, j)
}
fmt.Println(i, &i)

运算後可得结果

0x1149268
0x1149268
0xc0000ae008
0xc0000ae008 100

并非进行宣告或是短宣告後就会有全新的变数出现并挪用全新的记忆体空间,

Go会去寻找目前最小单位的区块内是否已经有被宣告的变数,没有的话才会宣告新的。

  1. 一开始宣告一个全域变数i为100,并且i的地址为0x1149268
  2. 然後赋予全域变数i值为200,这时候还是对同一个变数进行操作,因此地址依然为0x1149268
  3. 接下来宣告一个区域变数i为150,由於该区域之前并未有其他i变数的存在,因此产生一个新的区域变数i,并赋予新的地址0xc0000ae008,同时也意味着全域变数i的地址被覆盖了
  4. 宣告两个区域变数i与j,但该区域先前已经有了i这个变数的存在,因此直接将i的值变为250即可,所以i的地址依然还是先前的0xc0000ae008

变数全新与否

看到有var会是全新的。

但看到:=却是不一定,短变数宣告可以伴随着未宣告的变数一起出现。

package main

import "fmt"

var x = 123

func main() {
	fmt.Println(&x)

	var x = 123
	fmt.Println(&x)

	x, y := 123, 100
	fmt.Println(&x, &y)

	if true {
		var x, y = 123, 100
		// 可以换成短变数宣告。

		fmt.Println(&x, &y)
	}

	fmt.Println(&x)
}

运行後可得结果

0x1149268
0xc00019a010
0xc00019a010 0xc00019a018
0xc00019a020 0xc00019a028
0xc00019a010
  1. 宣告一全域变数x值为123,并得到x地址为0x1149268
  2. 宣告一区域(main scope)变数x值为123,并得到x地址为0xc00019a010
  3. 短宣告二区域(main scope)变数x, y 值为123, 100,但由於x变数在此区间先前以宣告过故依然使用地址0xc00019a010,y地址则为0xc00019a018
  4. 宣告两区域(true scope)变数x, y值为123, 100,且由於x, y在该区域并未宣告过,因此此时x, y地址分别为 0xc00019a020, 0xc00019a028
  5. 出了true scope并回到main scope後,所得的x地址就会回到main scope的x地址,地址为0xc00019a010

Summary

这章节只替大家带来基本变数的宣告与使用,并透过记忆体位置的范例让大家知道区域与全域变数在Go中的规则与变化,希望大家能避开这些坑。

下个章节则会透过不同型态的变数为各位解说。


<<:  Day 7. 介绍一下VSCode-打code好帮手

>>:  Scala 语言和你 SAY HELLO!!

[Day26] Angular 的四种 Binding

昨天我们的 Component 只有简简单单的一行 “ironman works!” 其他啥都没有。...

占位符文字太多超过显示范围

缘由: 今天一样讲画面布局的部分,开发时常常会使用到让使用者填入资料的textfield,但常常为了...

30天打造品牌特色电商网站 Day.13 导览列基础制作(上)

昨天已经做过了导览列的介绍,那我们今天就学习用 HTML 和 CSS 基本的语法,来试着做一个简单的...

拿 ml5 来练习 如何载入别人的情绪给自己的电脑 (四)

介绍 首先介绍什麽是载入别人的情绪给自己的电脑, 有个人已经将自己读文章时,所产生的情绪,让机器来学...

连续 30 天 玩玩看 ProtoPie - Day 28

Chain 和 Range 的差异 讲者很用心提到这个地方,他用换页的时後底下点点跟着移动作为例子。...