---
# System prepended metadata

title: 'Day10 繼續Go-基本組合型別2(map, struct)'

---

# 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繁不及備載}
*/
```
