【Golang 1.18】Go! Go! Go! - 可愛又迷人的反派角色
依稀記得Golang剛推出的時候,深深被它的外表所吸引?不不不,筆者不是外貌協會的,其實它已經出現在地球上有很長一段時間了,當初Google在設計它的時候,就是想要語法簡潔且高效能,筆者覺得它是取代Node.js - modules 無底洞 / Python - 執行速度 / Java - JVM跨平臺的利器。 最近感同深受,原本我的網誌是使用hexo - Nodejs去製作的,但因為佈景主題不合新版,所以就跳來使用hugo - Golang,雖然hugo的文章大多都是英文的,比起hexo有強大中文資訊來說,的確是筆者的痛點,但是…Build的速度至少差10倍吧。
作業環境
項目 | 版本 |
---|---|
CPU | Apple M1 |
macOS | Big Sur 12.3 arm64 |
Golang | 1.18 arm64 |
Visual Studio Code | 1.66 arm64 |
MySQL | 8.0.28 arm64 |
安裝
安裝Golang / MySQL
- 首先,當然是先安裝Golang跟MySQL,這裡筆者是使用Homebrew安裝的,有關MySQL的相關設定可以參考舊文。
brew install go
brew install mysql
安裝VSCode套件
語法Go! Go! Go!
HelloWorld
- 不免俗的,當然還是要來個HelloWorld啦…
- 新增一個叫"GoGoGo"的資訊夾,裡面新增一個叫"main.go"的檔案…
- 是不是覺得它的語法很像C語言呢?
package main
import (
"fmt"
)
func main() {
var message string = "Hello, World !!!" // 變數message,是個字串,值為"Hello, World !!!"
fmt.Println(message) // 套件fmt => format工具
}
go run main.go // 執行main.go
go build main.go // 編譯main.go成執行檔
go fmt main.go // 排版程式碼
go env // 列出環境變數
常數
package main
import (
"fmt"
)
func main() {
constant()
}
/// 常數 => 不能改變的數
func constant() {
const ip string = "127.0.0.1" // 常數 <名稱: ip> <類型: string> = <值: "127.0.0.1">
const height = 194.87 // const height float = 194.87 (自動判斷類型)
const ( // 也可以這樣合在一起處理
Male int = 1
Female = 2
)
fmt.Printf("ip = %s, height = %.2f, Male = %d\n", ip, height, Male)
// ip = 127.0.0.1, height = 194.87, Male = 1
}
變數
package main
import (
"fmt"
)
func main() {
variable()
}
/// 變數 => 可以改變的數
func variable() {
var number int
var text string
message := "自動判斷類型"
text = "測試中"
// num1, num2 := 1, 2
// var (
// a = 1
// b = 2
// )
fmt.Printf("number = %d, text = %v, message = %s\n", number, text, message)
}
基本結構
Array - 陣列
- 在Golang裡面,它的容量大小是不能變動的
- 順便介紹for迴圈 => while()
package main
import (
"fmt"
"reflect"
)
func main() {
arrayTest()
}
// Array => 在Golang裡面,它的容量大小是不能變動的
func arrayTest() {
var myArray [3]int = [3]int{1, 20, 3}
locations := [...]string{"North", "East", "South", "West"}
numbers := [5]int{}
_index := 0
myArray[1] = 100
numbers[3] = 20
result := fmt.Sprintf("myArray(%d) => %d\tnumbers(%d) = %x", len(myArray), myArray, len(numbers), numbers)
fmt.Println(result)
for _index < len(locations) {
location := locations[_index]
fmt.Printf("%s(type => %s)\t", location, reflect.TypeOf(location).Kind())
_index++
}
}
Slice - 切片
- 就是可變動大小的Array,很常用…
- 順便介紹for迴圈 => for-loop
package main
import (
"fmt"
"reflect"
)
func main() {
sliceTest()
}
// Slice => 就是可變動大小的Array
func sliceTest() {
people1 := []string{"Aaron", "Jim", "Bob", "Ken"} // 有值 (使用:4 / 容量:4)
var people2 []string // 空的 (使用:0 / 容量:0) => nil
people3 := make([]string, 4) // 空的 (使用:4 / 容量:4)
people4 := make([]string, 0, 5) // 空的 (使用:0 / 容量:5)
PrintSlice(people1[1:])
PrintSlice(people2)
PrintSlice(people3)
PrintSlice(people4)
fmt.Println(people1 == nil)
// people1[4] = "William"
people1 = append(people1, "William") // 增加(擴展)跟people1一樣的空間大小
PrintSlice(people1)
copyCount := copy(people3, people1[:len(people1)-2]) // 如果Copy不完整,沒有Copy到的會自動是初始值
people1 = revomeSliceAtIndex(people1, 2)
PrintSlice(people1)
PrintSlice(people3)
fmt.Println(copyCount)
}
// 列出slice的(長度/容量)
func PrintSlice(slice []string) {
fmt.Printf("%v: (len=%d, cap=%d)\n", slice, len(slice), cap(slice))
}
// 移除特定位置的Slice => 切開再合起來
func revomeSliceAtIndex(source []string, index int) []string {
sliceBeforeIndex := source[0:index]
sliceAfterIndex := source[index+1 : len(source)+0]
for i := 0; i < len(sliceAfterIndex); i++ {
sliceBeforeIndex = append(sliceBeforeIndex, sliceAfterIndex[i])
}
return sliceBeforeIndex
}
Map - (key, value)
- 就是Swift的Dictionary,Key-Value pair的組合
package main
import (
"fmt"
"reflect"
)
func main() {
mapTest()
}
// Map => Key-Value pair
func mapTest() {
var addresses map[string]string
ages := make(map[string]int, 10)
ages["alice"] = 31
ages["charlie"] = 34
colors := map[string]string{
"red": "#ff0000",
"green": "#4bf745",
}
PrintMap(colors)
fmt.Printf("addresses => %v(type => %v)\n", addresses, reflect.TypeOf(addresses).Kind())
fmt.Printf("ages => %v(type => %v)\n", ages, reflect.TypeOf(ages).Kind())
delete(colors, "red")
PrintMap(colors)
}
// 列出Map的值 => 因為 map 是 reference type,所以不用使用 pointer
func PrintMap(aMap map[string]string) {
for color, hex := range aMap {
fmt.Printf("%v: %v\n", color, hex)
}
}
package main
import (
"fmt"
"reflect"
)
func main() {
pointerTest()
}
// Pointer => 記憶體位置 / 指標
func pointerTest() {
var intPoint *int // *int指的是 => intPoint是記憶體位置,該位置放的值是int數字 / *intPoint才是數字
number := 100
intPoint = &number // &number => 指的是number的記憶體位置
fmt.Println(*intPoint) // *intPoint是數字
increment(&number)
fmt.Println(number)
total, ans := add(36, 57)
fmt.Println(total, ans)
}
// 數字+1
func increment(number *int) {
*number++ // *number是數字,數字++才是對的,但因為number是記憶體位置,所以就直接被改了,不用回傳
}
// 兩數字的加法 => 回傳兩個值
func add(a int, b int) (int, string) {
num := a + b
return num, "isSuccess" // 因為是傳數值(✖記憶體位置),所以是Copy一份來做加法,要return回去結果才行…
}
Struct - 結構
- 有多個屬性要包在一起時使用
- 介紹Switch的用法
package main
import (
"fmt"
)
type Person struct {
name string
age int
gender string
}
func main() {
structTest()
}
// Struct => 有多個屬性要包在一起時使用
func structTest() {
p0 := Person{}
p1 := Person{name: "William-1", age: 30, gender: "Male"}
p2 := Person{"William-2", 3, "Female"}
People := []Person{p0, p1, p2}
fmt.Println(People)
for index := 0; index < len(People); index++ {
person := People[index]
switch person.gender {
case "Male":
fmt.Println("♂")
case "Female":
fmt.Println("♀")
default:
fmt.Println("未填寫")
}
}
}