[TOC]
## 1、數據定義
### (1).函數返回值問題
> 下面代碼是否可以編譯通過?
> test1.go
```go
package main
/*
下面代碼是否編譯通過?
*/
func myFunc(x,y int)(sum int,error){
return x+y,nil
}
func main() {
num, err := myFunc(1, 2)
fmt.Println("num = ", num)
}
```
答案:
編譯報錯理由:
```bash
# command-line-arguments
./test1.go:6:21: syntax error: mixed named and unnamed function parameters
```
> 考點:函數返回值命名
> 結果:編譯出錯。
> 在函數有多個返回值時,只要有一個返回值有指定命名,其他的也必須有命名。 如果返回值有有多個返回值必須加上括號; 如果只有一個返回值并且有命名也需要加上括號; 此處函數第一個返回值有sum名稱,第二個未命名,所以錯誤。
### (2).結構體比較問題
> 下面代碼是否可以編譯通過?為什么?
> test2.go
```go
package main
import "fmt"
func main() {
sn1 := struct {
age int
name string
}{age: 11, name: "qq"}
sn2 := struct {
age int
name string
}{age: 11, name: "qq"}
if sn1 == sn2 {
fmt.Println("sn1 == sn2")
}
sm1 := struct {
age int
m map[string]string
}{age: 11, m: map[string]string{"a": "1"}}
sm2 := struct {
age int
m map[string]string
}{age: 11, m: map[string]string{"a": "1"}}
if sm1 == sm2 {
fmt.Println("sm1 == sm2")
}
}
```
結果
編譯不通過
```bash
./test2.go:31:9: invalid operation: sm1 == sm2 (struct containing map[string]string cannot be compared)
```
考點:**結構體比較**
> **結構體比較規則注意1**:只有相同類型的結構體才可以比較,結構體是否相同不但與屬性類型個數有關,還與屬性順序相關.
比如:
```go
sn1 := struct {
age int
name string
}{age: 11, name: "qq"}
sn3:= struct {
name string
age int
}{age:11, name:"qq"}
```
`sn3`與`sn1`就不是相同的結構體了,不能比較。
> **結構體比較規則注意2**:結構體是相同的,但是結構體屬性中有不可以比較的類型,如`map`,`slice`,則結構體不能用`==`比較。
可以使用reflect.DeepEqual進行比較
```go
if reflect.DeepEqual(sm1, sm2) {
fmt.Println("sm1 == sm2")
} else {
fmt.Println("sm1 != sm2")
}
```
### (3).string與nil類型
> 下面代碼是否能夠編譯通過?為什么?
> test3.go
```go
package main
import (
"fmt"
)
func GetValue(m map[int]string, id int) (string, bool) {
if _, exist := m[id]; exist {
return "存在數據", true
}
return nil, false
}
func main() {
intmap:=map[int]string{
1:"a",
2:"bb",
3:"ccc",
}
v,err:=GetValue(intmap,3)
fmt.Println(v,err)
}
```
考點:**函數返回值類型**
答案:編譯不會通過。
分析:
nil 可以用作 interface、function、pointer、map、slice 和 channel 的“空值”。但是如果不特別指定的話,Go 語言不能識別類型,所以會報錯。通常編譯的時候不會報錯,但是運行是時候會報:`cannot use nil as type string in return argument`.
所以將`GetValue`函數改成如下形式就可以了
```go
func GetValue(m map[int]string, id int) (string, bool) {
if _, exist := m[id]; exist {
return "存在數據", true
}
return "不存在數據", false
}
```
### (4) 常量
> 下面函數有什么問題?
> test4.go
```go
package main
const cl = 100
var bl = 123
func main() {
println(&bl,bl)
println(&cl,cl)
}
```
解析
考點:**常量**
常量不同于變量的在運行期分配內存,常量通常會被編譯器在預處理階段直接展開,作為指令數據使用,
```
cannot take the address of cl
```
內存四區概念:
#### A.數據類型本質:
? 固定內存大小的別名
#### B. 數據類型的作用:
? 編譯器預算對象(變量)分配的內存空間大小。

#### C. 內存四區

流程說明
1、操作系統把物理硬盤代碼load到內存
2、操作系統把c代碼分成四個區
3、操作系統找到main函數入口執行
##### 棧區(Stack):
? 空間較小,要求數據讀寫性能高,數據存放時間較短暫。由編譯器自動分配和釋放,存放函數的參數值、函數的調用流程方法地址、局部變量等(局部變量如果產生逃逸現象,可能會掛在在堆區)
##### 堆區(heap):
? 空間充裕,數據存放時間較久。一般由開發者分配及釋放(但是Golang中會根據變量的逃逸現象來選擇是否分配到棧上或堆上),啟動Golang的GC由GC清除機制自動回收。
##### 全局區-靜態全局變量區:
? 全局變量的開辟是在程序在`main`之前就已經放在內存中。而且對外完全可見。即作用域在全部代碼中,任何同包代碼均可隨時使用,在變量會搞混淆,而且在局部函數中如果同名稱變量使用`:=`賦值會出現編譯錯誤。
? 全局變量最終在進程退出時,由操作系統回收。
> 我么在開發的時候,盡量減少使用全局變量的設計
###### 全局區-常量區:
? 常量區也歸屬于全局區,常量為存放數值字面值單位,即不可修改。或者說的有的常量是直接掛鉤字面值的。
比如:
```go
const cl = 10
```
cl是字面量10的對等符號。
所以在golang中,常量是無法取出地址的,因為字面量符號并沒有地址而言。
---
- 封面
- 第一篇:Golang修養必經之路
- 1、最常用的調試 golang 的 bug 以及性能問題的實踐方法?
- 2、Golang的協程調度器原理及GMP設計思想?
- 3、Golang中逃逸現象, 變量“何時棧?何時堆?”
- 4、Golang中make與new有何區別?
- 5、Golang三色標記+混合寫屏障GC模式全分析
- 6、面向對象的編程思維理解interface
- 7、Golang中的Defer必掌握的7知識點
- 8、精通Golang項目依賴Go modules
- 9、一站式精通Golang內存管理
- 第二篇:Golang面試之路
- 1、數據定義
- 2、數組和切片
- 3、Map
- 4、interface
- 5、channel
- 6、WaitGroup
- 第三篇、Golang編程設計與通用之路
- 1、流?I/O操作?阻塞?epoll?
- 2、分布式從ACID、CAP、BASE的理論推進
- 3、對于操作系統而言進程、線程以及Goroutine協程的區別
- 4、Go是否可以無限go? 如何限定數量?
- 5、單點Server的N種并發模型匯總
- 6、TCP中TIME_WAIT狀態意義詳解
- 7、動態保活Worker工作池設計