# Day10 繼續Go-基本組合型別2(map, struct)
## 映射 Map
#### 【map】
`map`有很多種翻譯,名詞叫作`地圖`,動詞有`映射`、`對應`、`對照`的意思 ,在一些程式語言中則有`Key-Value`一個關鍵字對應一個值的用法。
> **var Variable = map[Type]Type{}**
>> var a = map[int]string{}
https://play.golang.org/p/dAgwOEXq6sN
可以像這樣`bool`對應到任何`string`
```go
var Male = map[bool]string{
true: "公",
false: "母",
}
```
或是設定`string`對應到`int`
```go
var Number = map[string]int{
"零": 0,
"壹": 1,
"貳": 2,
}
Number["參"] = 3
```
`string`對應到`string`也可以,
```go
var Size = map[string]string{
"big": "大",
"medium": "中",
"small": "小",
}
```
只要任兩種型態設定好、對應好之後就能用哩,
`string`的前後要加雙引號`" "`,來試試效果吧!
#### 取map
```go
fmt.Print(Male[true],Number["參"])
/* result:
公3
*/
```
### 【for 迭代遍歷】
透過`for range`關鍵字,遍歷造訪結構內的每個元素
```go
for key, value := range Size {
fmt.Println(key, value)
}
/* result:
big 大
medium 中
small 小
*/
```
## 結構 Struct
#### 【struct】
結構裡面可以放多個變數(`int`、`string`、`slice`、`map`等等)、物件、甚至是結構。
宣告結構`Struct`的幾種方式:
https://play.golang.org/p/lEeUmceDsjh
```go
package main
import "fmt"
type Res struct {
Status string
Msg string
}
func main() {
res1 := new(Res)
var res2 = new(Res)
var res3 *Res
res4 := &Res{
Status: "failed",
}
fmt.Println(res1, res2, res3, res4)
fmt.Printf("%+v %+v %+v %+v", res1, res2, res3, res4)
}
/* result:
&{ } &{ } <nil> &{failed }
&{Status: Msg:} &{Status: Msg:} <nil> &{Status:failed Msg:}
*/
```
#### 【Nested Structure】巢狀結構
`結構中的結構的結構`、大腸包小腸再包小小腸
https://play.golang.org/p/Bd85fmF10Uo
```go
type Wallet struct {
Blue1000 int // 藍色小朋友
Red100 int // 紅色國父
Card string
}
type PencilBox struct {
Pencil string
Pen string
}
type Bag struct {
Wallet // 直接放入結構就好
PencilBox // 直接放入結構就好
Books string
}
type Person struct {
Bag
Name string
}
func main() {
var bag = Bag{
Wallet{Card: "世華泰國信用無底洞卡", Red100: 5},
PencilBox{Pen: "Cross", Pencil: "Pentel"},
"Go繁不及備載", // Books
}
var Tommy = Person{}
Tommy.Name = "Tommy"
Tommy.Bag = bag
fmt.Printf("%+v", Tommy)
}
/* result:
{Bag:{Wallet:{Blue1000:0 Red100:5 Card:世華泰國信用無底洞卡} PencilBox:{Pencil:Pentel Pen:Cross} Books:Go繁不及備載} Name:Tommy}
*/
```
藝涔 益晨 翊誠~ 的剝開我的Struct...
---
## 【指標、結構、位址】
這裡將上面的例子取一部分出來修改,
如果將`main()`裡的`var Bag`敘述改成 `&Bag`:
```go
type Person struct {
Bag // 放Bag這個物件
Name string
}
func main() {
var bag = &Bag{
Wallet{Card: "世華泰國信用無底洞卡", Red100: 5},
PencilBox{Pen: "Cross", Pencil: "Pentel"},
"Go繁不及備載",
}
var Tommy = Person{}
Tommy.Name = "Tommy"
Tommy.Bag = *bag // 透過`取值`來取出bag位址裡面的東西
fmt.Printf("%+v", Tommy)
}
/* result:
{Bag:{Wallet:{Blue1000:0 Red100:5 Card:世華泰國信用無底洞卡} PencilBox:{Pencil:Pentel Pen:Cross} Books:Go繁不及備載} Name:Tommy}
*/
```
印出bag 就要透過`*`來取值
---
如果將`Person`裡的`Bag`改成 `*Bag`:
```go
type Person struct {
*Bag // 放指標
Name string
}
func main() {
var bag = &Bag{ // 指到位址
Wallet{Card: "世華泰國信用無底洞卡", Red100: 5},
PencilBox{Pen: "Cross", Pencil: "Pentel"},
"Go繁不及備載",
}
var Tommy = Person{}
Tommy.Name = "Tommy"
Tommy.Bag = bag // 這裡就印出bag位址
fmt.Printf("%+v", Tommy)
}
/* result:
{Bag:0xc000048050 Name:Tommy}
*/
```
這樣子就會印出`bag`的位址
---
雖然有點**違反物理法則及常識**,但
#### 【小坑】如果Bag裡面有PencilBox,PencilBox裡面又有Bag
會怎麼樣呢?
答案是出現 `invalid recursive type` 的錯誤。
https://play.golang.org/p/KS5IvIgF1BQ
```go
type PencilBox struct {
Pencil string
Pen string
Bag // 你中有我 我中有你
}
type Bag struct {
Wallet
PencilBox
Books string
}
```
雖然放物件會出現錯誤,但是 `放指針`不會
https://play.golang.org/p/mXbp60WDXtR
```go
type PencilBox struct {
Pencil string
Pen string
*Bag // 你中有針
}
type Bag struct {
Wallet
PencilBox
Books string
}
func main() {
var bag = Bag{
Wallet{Card: "世華泰國信用無底洞卡", Red100: 5},
PencilBox{Pen: "Cross", Pencil: "Pentel"},
"Go繁不及備載",
}
bag.PencilBox.Bag = &bag // 包包裡放針
fmt.Printf("%+v", *bag.PencilBox.Bag)
}
/* result:
{Wallet:{Blue1000:0 Red100:5 Card:世華泰國信用無底洞卡} PencilBox:{Pencil:Pentel Pen:Cross Bag:0xc000046060} Books:Go繁不及備載}
*/
```