initial: 10
value: 10
pointer: 0
Address: 0xc0000140b8
initial: 10
value: 10
pointer: 0
Address: 0xc0000140b8
```
package main
import "fmt"
func fact(n int) {
if n == 0 {
return 1
}
return n * fact(n - 1)
}
func main() {
fmt.Println(fact(7))
var fib(n int) int
fib = func(n int) int {
if n < 2 {
return n
}
return fib(n-1) + fib(n-2)
}
fmt.Println(fib(7))
}
```
遞迴的寫法就照正常樣子 如上面的 fact()
但網頁中寫 fib() 的描述如下
Closures can also be recursive, but this requires the closure to be declared with a typed
varexplicitly before it’s defined.
但我看不出來 fib 是 closure
所以... 以後如果有看出來再補充
執行結果:
5040
13
```
package main
import "fmt"
func intSeq() func() int {
i := 0
return func() int {
i++
return i
}
}
func main() {
nextInt := intSeq()
fmt.Println(nextInt())
fmt.Println(nextInt())
fmt.Println(nextInt())
nextInt2 := intSeq()
fmt.Println(nextInt2())
}
```
Closure 的概念我也是第一次學到 查了一些資料
我的理解是 把變數包進 anonymous function 裡面使用的話
The anonymous function close over the variable
等於會延長該變數的生命週期(lifetime) 直到 anonymous function 生命週期結束
然後特殊的是每個 anonymous function 裡面包的變數是獨立的
例如上面的 nextInt 跟 nextInt2 兩個裡面的 i 是不同的
執行結果:
1
2
3
1
```
package main
import "fmt"
func sum(nums ...int) {
fmt.Print(nums, " ")
total := 0
for _, num := range nums {
total += num
}
fmt.Println(total)
}
func main() {
sum(1, 2)
sum(1, 2, 3)
nums := []int{1, 2, 3, 4}
sum(nums...)
}
```
Go 也可以接受不定長度的參數
用法如上
如果要傳遞不定長度參數給function 而不是傳 array 本身要在呼叫的時候加上 "..."
執行結果:
[1 2] 3
[1 2 3] 6
[1 2 3 4] 10
因為發現身邊不少人有在使用幣安
卻不知道幣安裡面有類似活存的理財工具
於是決定來寫一篇教學
本文的資料為寫文章的當下看到的利率(7%) 幣安的利率蠻常會調整的
首先打開手機版幣安 切換到專業版介面
簡潔版長這樣
(如果已經是專業版頁面就跳到下面專業版介面)
點選左上角紅色圈起來的地方
然後點選上面紅色圈的地方會開啟專業版頁面
專業版頁面會長的像下面這張圖
點右下角的資金 會看到下面的頁面
點選上方圈起來的"理財"
點最中間黃色的"申購幣安理財產品"
點了之後會看到下面的頁面
這次我選用 USDT 當範例來操作一次
點選紅圈的 USDT
注意下面有小字寫著幣安保活期 幣安寶活期可以當成銀行存款一樣 要使用可以隨時取消領出之類的
點下之後到申購頁面會長像下面那樣
往下滑按下確認後可以看到下面的樣子
有一個特別的點是 下面紅色圈起來的地方可以考慮打開
打開的話會每天自動把你收到的利息再做申購 就可以有複利的效果
另外其他虛擬貨幣也有活存 例如下面附上當下 ETH 跟 BTC 的
如果確定自己不常動用那些幣的話可以放活存賺一點利息
如果覺得此篇文章有幫助 想註冊幣安的話歡迎使用我的推薦連結
https://accounts.binance.me/zh-TW/register?ref=U2AOEWOC
或是使用我的推薦碼註冊: U2AOEWOC
```
package main
import "fmt"
func vals() (int, int) {
return 3, 7
}
func main() {
a, b := vals()
fmt.Println(a)
fmt.Println(b)
_, c := vals()
fmt.Println(c)
}
```
Go 支援回傳多個值 寫法就如上面所述
執行結果:
3
7
7
```
package main
import "fmt"
func plus(a int, b int) int {
return a + b
}
func plusPlus(a, b, c int) int {
return a + b + c
}
func main() {
res := plus(1, 2)
fmt.Println("1+2=", res)
res = plusPlus(1, 2, 3)
fmt.Println("1+2+3=", res)
}
```
Function 的寫法比較特別的就是 return type 在最後面
其他沒什麼比較特別的東西
執行結果:
1+2= 3
1+2+3= 6
```
package main
import "fmt"
func main() {
nums := []int{2, 3, 4}
sum := 0
for idx, num := range nums {
sum += num
fmt.Println("idx, val: ", idx, num)
}
fmt.Println("sum: ", sum)
kvs := map[string]string{"a": "apple", "b": "banana"}
for k,v := range kvs {
fmt.Println("%s -> %s", k, v)
}
for k := range kvs {
fmt.Println("key: ", k)
}
for i, c := range "go" {
fmt.Println(i, c)
}
}
```
Go 裡面 Range 的用法跟 Python 的 enumerate 有點像
如果是普通的 array 會一個一個列舉而且有 index
如果是 str 的話 value 會是 unicode
執行結果:
idx, val: 0 2
idx, val: 1 3
idx, val: 2 4
sum: 9
%s -> %s a apple
%s -> %s b banana
key: a
key: b
0 103
1 111
```
package main
import "fmt"
func main() {
m := make(map[string]int)
m["k1"] = 7
m["k2"] = 12
fmt.Println("map: ", m)
v1 := m["k1"]
fmt.Println("v1: ", v1)
fmt.Println("len: ", len(m))
delete(m, "k2")
fmt.Println("map: ", m)
_, present := m["k2"]
fmt.Println("present: ", present)
n := map[string]int{"foo": 1, "bar": 2}
fmt.Println("map n: ", n)
}
```
Map 的用法跟 Python 的 dict 差不多
只是寫法不太一樣
比較特別的是 拿值的時候有第二個回傳值
可以用來判斷 key 有沒有在map裡面
執行結果:
map: map[k1:7 k2:12]
v1: 7
len: 2
map: map[k1:7]
present: false
map n: map[bar:2 foo:1]
```
package main
import "fmt"
func main() {
s := make([]string, 3)
s[0] = "a"
s[1] = "b"
s[2] = "c"
fmt.Println("set: ", s)
fmt.Println("get: ", s[2])
fmt.Println("len: ", len(s))
s = append(s, "d")
s = append(s, "e", "f")
fmt.Println("apd: ", s)
c := make([]string, len(s))
copy(c, s)
fmt.Println("copy: ", c)
l := s[2:5]
fmt.Println("slic1: ", l)
l = s[:5]
fmt.Println("slic2: ", l)
l = s[2:]
fmt.Println("slic3: ", l)
twoD := make([][]int, 3)
for i := 0; i < 3; i++ {
innerLen := i + 1
twoD[i] = make([]int, innerLen)
for j := 0; j < innerLen; j++ {
twoD[i][j] = i + j
}
}
fmt.Println("2D: ", twoD)
}
```
Slice 的操作跟 Python 的用法很相似
比較特別的是用 make 先產生固定長度的 array (有點像是 C++ 的 new 但不需要delete )
然後在二維陣列(2D array)的 make 第二個參數指定的只有第一層的長度
內層 array 的長度可以不一樣
執行結果:
set: [a b c]
get: c
len: 3
apd: [a b c d e f]
copy: [a b c d e f]
slic1: [c d e]
slic2: [a b c d e]
slic3: [c d e f]
2D: [[0] [1 2] [2 3 4]]
```
package main
import "fmt"
func main() {
var a [5]int
fmt.Println(a)
a[4] = 100
fmt.Println("set: ", a)
fmt.Println("get: ", a[4])
fmt.Println("len: ", len(a))
b := [5]int{1, 2, 3, 4, 5}
fmt.Println("decl: ",b )
var twoD [2][3]int
fmt.Println("2D arr: ", twoD)
for i := 0; i < 2; i++ {
for j := 0; j < 3; j++ {
twoD[i][j] = i + j
}
}
fmt.Println("2D arr: ", twoD)
}
```
Array 的語法跟 C 不一樣的地方是把 維度放在型別前面
而 C 是放在 identifier 後面
執行結果:
[0 0 0 0 0]
set: [0 0 0 0 100]
get: 100
len: 5
decl: [1 2 3 4 5]
2D arr: [[0 0 0] [0 0 0]]
2D arr: [[0 1 2] [1 2 3]]
```
package main
import (
"fmt"
"time"
)
func main() {
i := 2
switch i {
case 1:
fmt.Println("one")
case 2:
fmt.Println("two")
case 3:
fmt.Println("three")
}
switch time.Now().Weekday() {
case time.Saturday, time.Sunday:
fmt.Println("It's weekend.")
default:
fmt.Println("It's weekday.")
}
t := time.Now()
switch {
case t.Hour() < 12:
fmt.Println("It's before noon")
default:
fmt.Println("It's after noon")
}
whatAmI := func(i interface{}) {
switch t := i.(type) {
case bool:
fmt.Println("It's bool type")
case int:
fmt.Println("It's int type")
default:
fmt.Printf("Don't unknown type %T\n", t)
}
}
whatAmI(true)
whatAmI(6)
whatAmI("hey")
}
```
Switch 的用法跟 C 也是差不多
只是範例中多了 i.(type) 的用法來得到變數(可能也有常數)的型別(type)
執行結果:
two
It's weekday.
It's after noon
It's bool type
It's int type
Don't unknown type string
這篇是練習 If-else 的用法
```
package main
import "fmt"
func main() {
if 7 % 2 == 0 {
fmt.Println("7 is even")
} else {
fmt.Println("7 is odd")
}
if 8 % 4 == 0 {
fmt.Println("8 is even")
} else {
fmt.Println("8 is odd")
}
if n := 9; n > 0 {
fmt.Println("n is positive")
} else if n < 0 {
fmt.Println("n is negative")
} else {
fmt.Println("n is zero")
}
}
```
比較特別的是可以用分號斷行
而且在condition statement (條件判斷式) 宣告的變數
可以在同一個If else裡面繼續使用
執行結果:
7 is odd
8 is even
n is positive
練習基本的 for loop
```
package main
import "fmt"
func main() {
i := 1
for i < 3 {
fmt.Println(i)
i++
}
for j := 7; j < 10; j++ {
fmt.Println(j)
}
for {
fmt.Println("Infinitely loop")
break
}
for n := 0; n < 5; n++ {
if n % 2 == 0 {
continue
}
fmt.Println(n)
}
}
```
Go lang 裡面的 for loop 不用小括號
但中間的分號用法是一樣的
輸出結果:
1
2
7
8
9
Infinitely loop
1
3
接下來要練習使用常數 (constant)
程式碼如下
```
package main
import (
"fmt"
"math"
)
const s string = "constant"
func main() {
fmt.Println(s)
const n = 500000000
const d = 3e20 / n
fmt.Println(d)
fmt.Println(int64(d))
fmt.Println(math.Sin(n))
}
```
用法就是把 var 改成 const 其他沒什麼太大的差別
另外可以看到 go lang 的 type casting 語法跟 Python 比較相似
e.g. int64(d)
輸出結果:
constant
6e+11
600000000000
-0.28470407323754404
接下來是練習變數的宣告及初始化
程式碼:
```
package main
import "fmt"
func main() {
var a = "initial"
fmt.Println(a)
var b, c int = 1, 2
fmt.Println(b, c)
var d = true
fmt.Println(d)
var e int
fmt.Println(e)
f := "string type"
fmt.Println(f)
}
```
原始的寫法應該是
var <identifier list> <type> [ = <value list> ]
但是變數的初始化可以不給 type
compiler 會自行判斷
比較特別的是
f := "string type"
這行相等於
var f string = "string type"
一種同時宣告及初始化的簡便寫法
執行結果:
initial
1 2
true
0
string type
第二個例子是基本的數值運算
程式碼如下:
```
package main
import "fmt"
func main() {
fmt.Println("go" + "lang")
fmt.Println("1+1 = ", 1+1)
fmt.Println("7.0/3.0 = ", 7.0/3.0)
fmt.Println(true && true)
fmt.Println(false || true)
fmt.Println(true)
}
```
String 的加法跟Python有點像
但語法跟 C 很類似
執行結果:
golang
1+1 = 2
7.0/3.0 = 2.3333333333333335
true
true
true
由於在網路上發現了 Go by Example 這個網站
所以短期目標就是讀完這些 Example
第一個 Example 就是經典的 Hello World
然後因為我懶惰切換成 Linux 所以就直接在 https://go.dev/play/ 上練習了
Hello World 寫法如下
```
package main
import "fmt"
func main() {
fmt.Println("Hello World")
}
```
第一行是宣告當前檔案為 main 的 package
Go lang 的 entry function 跟 C/C++ 一樣都是main
fmt.Println 目前理解起來像是 printf之類的 或是 cout
執行結果:
Hello, World
首先從安裝開始
參考官方的文件 https://go.dev/doc/install
下載最新Release的壓縮檔後執行以下指令
$ tar -C /usr/local -xzf go1.17.6.linux-amd64.tar.gz $ export PATH=$PATH:/usr/local/go/bin
第二行指令會設定 go lang 的安裝路徑到 PATH 變數裡面
但這只會有當下的 terminal 有效 下次重開又要執行上面的 export 一次才能使用
所以建議打開 ~/.profile 檔案
在最底下加上
PATH=/usr/local/go/bin:$PATH
安裝好以後
執行
$ go version
go version go1.17.6 linux/amd64
會有上述的執行結果
一樣是寫程式 怎麼能不寫個Hello world呢?
所以接下來就是印個Hello world在螢幕上
BIOS 裡有提供簡單的 interrupt 可以完成這件事情
然後詳細的內容 可以翻閱 wikipedia
簡單的說就是要設定 ax register 裡面的值
分為 ah (高位址)和 al (低位址)
ah 設定成 0x0e 代表 Teletype output 會顯示 al 裡面存的ASCII code
--<boot.asm>---------------------------------------------------------------------
mov ah 0x0e
mov al, 'H'
int 0x10
mov al, 'e'
int 0x10
mov al, 'l'
int 0x10
mov al, 'l'
int 0x10
mov al, 'o'
int 0x10
mov al, ' '
int 0x10
mov al, 'w'
int 0x10
mov al, 'o'
int 0x10
mov al, 'r'
int 0x10
mov al, 'l'
int 0x10
mov al, 'd'
int 0x10
jmp $
times 510-($-$$) db 0x00
dw 0xaa55
-----------------------------------------------------------------------------------
簡單的說就是一個字一個字的填上去
然後 interrupt 讓字顯示上去
因為 ah 都一樣所以就不用動
填完之後 一樣一個 infinite loop
最後填上 0 跟 0xaa55就好了~
``` package main import "fmt" func zeroval(n int) { n = 0 } func zeroptr(n *int) { *n = 0 } func main() { ...