iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 2
3
自我挑戰組

Golang魔法使 ─ 30天從零開始學習Go語言 | 比Python還簡單 | 理科生一定學得會 | 文科生不好說系列 第 2

#2 零與壹的魔法世界 ── 宣告數字型態的變數 | Golang魔法使

  • 分享至 

  • xImage
  •  

#2 零與壹的魔法世界 ── 宣告數字型態的變數 | Golang魔法使

前言

昨天小櫻戰鬥的事被好友「大道寺知世」用 V8 偷拍的一清二礎,你在偷偷搜集 Golang 牌的事,已經被發現了,知世也想要變強,他想要得到石鬼面變成不死之身 如今只能把知世加入戰隊一起奮鬥了

如何表達整數?

以「電腦科學」的角度來出發,電腦是怎麼表達數字的,大家都知道魔仗(電腦)內部是由 0 和 1 來運作的,那怎麼表示整數呢?

  • 0 0 0 0 0 0 0 0
  • 0 0 0 0 0 0 0 1
  • 0 0 0 0 0 0 1 0
  • 0 0 0 0 0 0 1 1
  • 0 0 0 0 0 1 0 0
  • ...

其中一個存取 0 或 1 的單元我們稱作「位元」(bit),而每個例子中都有 8bits,根據高一下數學課教的排列組合計數原理,這 8bits,一共可以有 256 排列


10000000 (-128)
10000001 (-127)
10000010 (-126)
...
11111111 (-1)
00000000 (0)
00000001 (1)
00000010 (2)
...
01111110 (126)
01111111 (127)

在 Golang 牌中我們稱這個叫int8,可以用來表示(-128~127)

我們有時並不會用到負號,這時我們記作 uint8 可以表示(0~255)

00000000 (0)
00000001 (1)
00000010 (2)
...
10000000 (128)
10000001 (129)
...
11111111 (255)

uint 只能是正數,int 可以有負數

int 表示負數的存法在電腦科學中稱為「二補數」

Golang上宣告整數變數

其中 int 即為英文的 integeruint 則為 unsigned integer 表示是「無符號的」整數,可能有點難記為什麼不乾脆用 i8u8 呢?這問題很好,Rust 就是這麼認為的,因此 Rust 採用 i8, u8 來表示

package main
import "fmt"
func main(){
    var num int8
    num = 127
    fmt.Print(num)
}

執行結果:
127

首先我們先來看第 4 行 var num int8var 是宣告變數的起手示,全稱為 variable,什麼是宣告變數呢?就是告訴編譯器,我需要使用一個變數叫作 num 而他是一個 int8 的型態

而這個num的名字由各位魔法使自己決定,變數名稱由數字、英文字母及下劃線組合而成,其中要注意不可以用數字當變數名稱開頭,相信資深工具人一定覺得理所當然,另外,並不是所有單字的可以當變數,有些名字是不能當成變數名稱的,比如若用var當變數名稱,想就知道會出事吧?

第 5 行 num = 127 則是告訴編譯器 num 是 127。請注意,這裡的等號是一種給予的表現,並不是數學上的等於,給予的方向是左邊接收右邊給予

第 6 行 fmt.Print(num) 則是告訴魔仗要他印出 num,若改使用 fmt.Println(num) 則魔仗則會在印出 num 後再印出換行符號(ln 代表 line) 很多語言也有採類似用法如 java, rust

然而 int8 實在是太短了,如果不小心給到 128 魔仗還會當場給我噴錯,氣氣氣氣氣,這種情況我們稱為 overflow 又稱為溢位

關於溢位

Golang牌在整數上一共給了以下這些型態

int8, uint8
int16, uint16
int32, uint32
int64, uint64
int , uint (大部分情況視為 int64, uint64)

另外大家可能會發現怎麼都是 8 的倍數,因為電腦會以 8 個 bits 做操作,所以又稱 8bits 為 1byte (1個位元組)

更簡短地宣告整數變數

然而,每次都要打 var ooo int ooo = xxx 時在太麻煩了所以又出現了幾種簡單的打法

package main
import "fmt"
func main(){
    var num1 int = 10
    num2 := 20
    fmt.Println(num1)
    fmt.Println(num2)
}

執行結果:
10
20

其中要注第5行 num2所採用的方法是由魔仗自行判定型態,在這裡會直接把 num2 視為 int

注意,若使用 fmt.Print() 則會印出 1020 因為魔仗在用 fmt.Print() 時不會自動在10後面換一行

補充:
Short Variable Declaration Operator(:=) in Go

Golang上宣告浮點數變數(小數)

你一定會很好奇魔仗要怎麼處理小數,現在的魔法基本上都是按照 IEEE754 來處理浮點數的,這部分比較複雜,簡單來說就是將一串浮點數拆成科學記號來表示,當然實際上沒有那麼簡單所以在此就不細講了。我們只要知道怎麼用就行了,在 Golang 中一共有兩種小數的宣告方法,分別為

  • float32
  • float64

因為對電腦來說,考慮到效能,無法完美處理小數,所以有兩種提供選擇。其中float64 花了2倍的空間所以存的比 float32 還要精準,通常我們會稱 float64 為雙精度浮點數

雙精度符點數
補充:有些語言會以 float 代表 float32, double 代表 float64,但是如果是採用 32, 64 這種表示法,就可以很清礎的了解該變數到底占用了多少空間,而且少背一個單字,真的很不錯

整數的運算

加減乘除

通常加減乘除是一定要有的,我們以整數來舉例

package main
import "fmt"
func main(){
    n := 10
    m := 20
    fmt.Println(n + m)
    fmt.Println(n - m)
    fmt.Println(n * m)
    fmt.Println(m / n)
    fmt.Println(n / m)
}

執行結果
30
-10
200
2
0

在絕大多數的語言中,整數對整數運算出來的都是整數,即使是除法也不例外,n / m10/20 在數學中應為 0.5 但在電腦科學中,會直接當作 0

那麼如果有負數呢?比如 -3/2 = -1.5 會變 -2 還是 -1 呢?其實不用像數學什麼 高斯符號 那麼麻煩,只要把小數位去掉就行了,所以會是 -1

package main
import "fmt"
func main(){
    fmt.Println(-3/2)
}

執行結果
-1

取餘

另外,在電腦科學中,有一種計算方式叫作「取餘數」,用「%」當做記號,這裡的「%」跟一般數學、物理、化學在用的「百分比」不一樣,他是一種「取餘數的」計算方式,舉個例子:

30 % 2 會是 0 因為 30/2 = 15...0
29 % 3 會是 2 因為 29/3 = 9...2
23 % 5 會是 3 因為 23/5 = 4...3

package main
import "fmt"
func main(){
    fmt.Println(30 % 2)
    fmt.Println(29 % 3)
    fmt.Println(23 % 5)
}

執行結果
0
2
3

如果是有負數的情況倒是比較少見,但也一樣試用

package main
import "fmt"
func main(){
    fmt.Println(-24 % 7)
    fmt.Println(24 % -7)
    fmt.Println(-24 % -7)
}

執行結果
-3
3
-3

-24 / 7 = -3...-3
(照理說應該也可以 -4...4)
24 / -7 = -3...3
(照理說應該也可以 -4...-4)
-24 / -7 = 3...-3
(照理說應該也可以 4...4)

經過以上觀察,能發現規律,當有負號參與時,取餘的值的正負號會等於被除數,也就是 % 的左側為正則出來的值也為正或零,% 左側為負則出來的值為負或零

  1. Modulo of negative integers in Go
  2. 模除

四則運算

在幾乎所有的語言中,都遵守先乘除後加減的四則運算,當你不確定運算優先序時 () 就直接給他加下去就對了

浮點數的運算

浮點數的運算基本上和整數差不多,但要注意一下,浮點數可以和直接整數(單純數字) 做運算,但不能和 整數變數(英文) 做運算。因為和純數字時Golang魔仗會直接幫你轉成浮點數。另一方面在Golang中取餘並不適用於浮點數。

package main
import "fmt"
func main(){
    m := 2.5
    m = m / 2
    fmt.Println(m)
}

執行結果
1.25

package main
import "fmt"
func main(){
    m := 2.5
    n := 2
    m = m / n
    fmt.Println(m)
}

那麼如果我真的這麼想要計算要怎麼辦?那麼就轉換型別吧!把浮點數轉成整數,或著把整數轉成浮點數

型別轉換

如果想把 int 轉成 float64 那麼就在要轉換的變數外加上 float64() 就可以了

package main
import "fmt"
func main(){
    m := 2.5
    n := 2
    m = m / float64(n)
    fmt.Println(m)
}

執行結果
1.25

這樣一來被套上 float64()的 n 就會以 float64的型態跟 m 做計算,要注意的事 n 仍然是 int 只有在套上時會變 float64(),也就是說「在宣告變數後」該變數只能就是這個型態了,型態並不能轉變。(有些語言並不這麼認為,比如php, javascript)

註解

幾乎所有的語言都有註解功能,加上註解,能幫助後續的維護,註解有相關的格式,但這邊先不做討論

在Golang牌中,用兩條斜線//來寫單行註解 ,// 後到換行前的所有字都會被忽略

package main
import "fmt"
func main(){
    m := 2.5    // m is float64
    n := 2      // f is int
    m = m / float64(n)
    fmt.Println(m)
}

如果要寫能換行的註解則是將你的註解包在 /**/

package main
import "fmt"
func main(){
    /* 
        這是一個
        可以跨行
        的註解
    */
    m := 2.5
    n := 2
    m = m / float64(n)
    fmt.Println(m)
}

大部份的語言都是採用 // 搭配 /**/ 的型式
python 因為把 // 拿去當做整數除法使用,所以是用 # 來做註解
Coffeescript 也是是 # 來做註解
NASM 則是以 ; 來當做註解

今日重點

  • 學習Golang牌中整數與浮點數的宣告及運算
  • 了解 uint 與 int 差別
  • 整數與浮點數間型別轉換
  • 變數的內容值可以變,但是型態不能變
  • 註解的使用

補充

宣告複數型態

如果是有讀過高中的朋友應該還記得什麼是複數吧!什麼?不記得了,標題就說文組不好說了,一般我們所使用的都是實數域的數,如果實數搭配虛數使用則稱複數,一般會用 a+bi 表示, a 為實部 b 為虛部,在Golang中用complex64complex128來表示, 64 指的是 float32 的實部加上 float32 的虛部, 128 指的是 float64 的實部加上 float64 的虛部

package main
import "fmt"
func main(){
    var m complex64 = 1 + 2i
    var n complex64 = 3 + 4i
    var k complex128 = 5 + 10i

    fmt.Println(m + n)
    // fmt.Println(m + k) 報錯(型態不同)
    fmt.Println(k)
}

執行結果:
(4+6i)
(5+10i)

圖片來源(Go官網):The Go Programming Language Specification

附錄──不能當變數名稱

這些字用來保持Golang牌的運作,不能當變數名稱

後記

看來 2020 那時寫的幹話有點多,所以 2021 更新又刪減了一些

本文大多數圖片來自:庫洛魔法使第一季第二集


上一篇
#1 Golang魔法使──安裝與建置環境 | Golang魔法使
下一篇
#3 字串 ─ 知世:反正我們是屬於正義的一方 | Golang魔法使
系列文
Golang魔法使 ─ 30天從零開始學習Go語言 | 比Python還簡單 | 理科生一定學得會 | 文科生不好說30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言