本文即Go語言的那些坑二。git
請問如下代碼能編譯經過嗎?github
import (
"fmt"
)
func main(){
array := make(map[int]func ()int) array[func()int{ return 10}()] = func()int{
return 12
}
fmt.Println(array)
}``` **答案:** 複製代碼
能夠正常編譯經過。數組
稍做改動,改成以下的狀況,還能編譯經過嗎?
```Go
import (
"fmt"
)
func main(){
array := make(map[func ()int]int)
array[func()int{return 12}] = 10
fmt.Println(array)
}```
**答案:**
複製代碼
不能編譯經過。bash
在Go語言中,函數被看作是第一類值:(first-class values):函數和其餘值同樣,能夠被賦值,能夠傳遞給函數,能夠從函數返回。也能夠被當作是一種「函數類型」。例如:有函數``func square(n int) int { return n * n }``,那麼就能夠賦值``f := square``,並且還能夠``fmt.Println(f(3))``(將打印出「9」)。
Go語言函數有兩點很特別:
+ 函數值類型不能做爲map的key
+ 函數值之間不能夠比較,函數值只能夠和nil做比較,函數類型的零值是``nil``
# 匿名函數做用域陷阱
請看下列代碼輸出什麼?
```Go
import (
"fmt"
)
func main(){
var msgs []func()
array := []string{
"1", "2", "3", "4",
}
for _, e := range array{
msgs = append(msgs, func(){
fmt.Println(e)
})
}
for _, v := range msgs{
v()
}
}
複製代碼
答案:微信
4
4
4
4
複製代碼
在上述代碼中,匿名函數中記錄的是循環變量的內存地址,而不是循環變量某一時刻的值。app
想要輸出一、二、三、4須要改成:函數
import (
"fmt"
)
func main(){
var msgs []func() array := []string{
"1", "2", "3", "4",
}
for _, e := range array{
elem := e
msgs = append(msgs, func(){
fmt.Println(elem)
})
}
for _, v := range msgs{
v()
}
}
複製代碼
其實就加了條elem := e
看似多餘,其實不,這樣一來,每次循環後每一個匿名函數中保存的就都是當時局部變量elem
的值,這樣的局部變量定義了4個,每次循環生成一個。ui
[3]int
和 [4]int
不算同一個類型請看一下代碼,請問輸出true
仍是false
this
import (
"fmt"
"reflect"
)
func main(){
arrayA := [...]int{1, 2, 3}
arrayB := [...]int{1, 2, 3, 4}
fmt.Println(reflect.TypeOf(arrayA) == reflect.TypeOf(arrayB))
}
複製代碼
答案是:spa
false
複製代碼
數組長度是數組類型的一個組成部分,所以[3]int和[4]int是兩種不一樣的數組類型。
例如:
import (
"fmt"
)
func main(){
arrayA := [...]int{0:1, 2:1, 3:4}
fmt.Println(arrayA)
}
複製代碼
會輸出:
[1 0 1 4]
複製代碼
有點像PHP
數組的感受,可是又不同:arrayA
的長度是多少呢?
import (
"fmt"
)
func main(){
arrayA := [...]int{0:1, 2:1, 3:4}
fmt.Println(len(arrayA))
}
複製代碼
答案是:
4
複製代碼
沒錯,定義了一個數組長度爲4的數組,指定索引的數組長度和最後一個索引的數值相關,例如:r := [...]int{99:-1}
就定義了一個含有100個元素的數組r
,最後一個元素輸出化爲-1,其餘的元素都是用0初始化。
&
操做a := &ages["bob"] // compile error: cannot take address of map element
複製代碼
map中的元素不是一個變量,不能對map的元素進行取地址操做,禁止對map進行取地址操做的緣由多是map隨着元素的增長map可能會從新分配內存空間,這樣會致使原來的地址無效
func main() {
var sampleMap map[string]int
sampleMap["test"] = 1
fmt.Println(sampleMap)
}
複製代碼
輸出報錯:
panic: assignment to entry in nil map
複製代碼
必須使用make或者將map初始化以後,才能夠添加元素。
以上代碼能夠改成:
func main() {
var sampleMap map[string]int
sampleMap = map[string]int {
"test1":1,
}
sampleMap["test"] = 1
fmt.Println(sampleMap)
}
複製代碼
能夠正確輸出:
map[test1:1 test:1]
複製代碼
&dilbert.Position
和(&dilbert).Position
是不一樣的&dilbert.Position
至關於&(dilbert.Position)
而非(&dilbert).Position
請看例子:
請問輸出什麼?
func main(){
type Employee struct {
ID int
Name string
Address string
DoB time.Time
Position string
Salary int
ManagerID int
}
var dilbert Employee
dilbert.Position = "123"
position := &dilbert.Position
fmt.Println(position)
}
複製代碼
輸出:
0xc42006c220
複製代碼
輸出的是內存地址
修改一下,把&dilbert.Position
改成(&dilbert).Position
func main(){
type Employee struct {
ID int
Name string
Address string
DoB time.Time
Position string
Salary int
ManagerID int
}
var dilbert Employee
dilbert.Position = "123"
position := &dilbert.Position
fmt.Println(position)
}
複製代碼
輸出:
123
複製代碼
請看下面例子:
type Employee struct {
ID int
Name string
Address string
DoB time.Time
Position string
Salary int
ManagerID int
}
func EmployeeByID(id int) Employee {
return Employee{ID:id}
}
func main(){
EmployeeByID(1).Salary = 0
}
複製代碼
請問能編譯經過嗎?
運行,輸出報錯:cannot assign to EmployeeByID(1).Salary
在本例子中,函數EmployeeById(id int)
返回的是值類型的,它的取值EmployeeByID(1).Salary
也是一個值類型;值類型是什麼概念?值類型就是和賦值語句var a = 1
或var a = hello world
等號=
右邊的1
、Hello world
是一個概念,他是不可以被賦值的,只有變量可以被賦值。
修改程序以下:
type Employee struct {
ID int
Name string
Address string
DoB time.Time
Position string
Salary int
ManagerID int
}
func EmployeeByID(id int) Employee {
return Employee{ID:id}
}
func main(){
var a = EmployeeByID(1)
a.Salary = 0
}
複製代碼
這就能夠編譯經過了
請看下面的例子,請問會編譯經過嗎?
import (
"fmt"
)
type littleGirl struct{
Name string
Age int
}
type girl *littleGirl
func(this girl) changeName(name string){
this.Name = name
}
func main(){
littleGirl := girl{Name:"Rose", Age:1}
girl.changeName("yoyo")
fmt.Println(littleGirl)
}
複製代碼
答案:
不能編譯經過,會提示「invalid receiver type girl(girl is a pointer type)」
複製代碼
Go語言中規定,只有類型(Type)和指向他們的指針(*Type)纔是可能會出如今接收器聲明裏的兩種接收器,爲了不歧義,明確規定,若是一個類型名自己就是一個指針的話,是不容許出如今接收器中的。
請看下面的例子,請問能編譯經過嗎?
import (
"fmt"
)
type littleGirl struct{
Name string
Age int
}
func(this littleGirl) changeName(name string){
fmt.Println(name)
}
func main(){
little := littleGirl{Name:"Rose", Age:1}
little = nil
little.changeName("yoyo")
fmt.Println(little)
}
複製代碼
答案:
不能編譯經過,顯示"cannot use nil as type littleGirl in assignment"
複製代碼
Go語言中,容許方法用nil指針做爲其接收器,也容許函數將nil指針做爲參數。而上述代碼中的littleGirl
不是指針類型,改成*littleGirl
,而後變量little
賦值爲&littleGirl{Name:"Rose", Age:1}
就能夠編譯經過了。 而且,nil對於對象來講是合法的零值的時候,好比map或者slice,也能夠編譯經過並正常運行。
不一樣於PHP的date("Y-m-d H:i:s", time())
,Golang的格式化奇葩的很,不能使用諸如Y-m-d H:i:s
的東西,而是使用2006-01-02 15:04:05
這個時間的格式,請記住這個時間,聽說這是Golang的誕生時間。
time := time.Now()
time.Format("20060102") //至關於Ymd
time.Format("2006-01-02")//至關於Y-m-d
time.Format("2006-01-02 15:04:05")//至關於Y-m-d H:i:s
time.Format("2006-01-02 00:00:00")//至關於Y-m-d 00:00:00
複製代碼
互聯網技術窩
或者加微信共同探討交流: