博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
go语言错题集(坑)【二】
阅读量:4099 次
发布时间:2019-05-25

本文共 5642 字,大约阅读时间需要 18 分钟。

系列相关:

目录

 


Golang中函数被看做是值,函数值不可以比较,也不可以作为map的key

请问以下代码能编译通过吗?

12345678910111213
import (	"fmt")func main(){	array := make(map[int]func ()int)	array[func()int{ return 10}()] = func()int{		return 12	}	fmt.Println(array)}

答案:

1
可以正常编译通过。

稍作改动,改为如下的情况,还能编译通过吗?

1234567891011
import (	"fmt")func main(){	array := make(map[func ()int]int)	array[func()int{return 12}] = 10	fmt.Println(array)}

 

答案:

1
不能编译通过。

在Go语言中,函数被看做是第一类值:(first-class values):函数和其他值一样,可以被赋值,可以传递给函数,可以从函数返回。也可以被当做是一种“函数类型”。例如:有函数func square(n int) int { return n * n },那么就可以赋值f := square,而且还可以fmt.Println(f(3))(将打印出“9”)。

Go语言函数有两点很特别:

  • 函数值类型不能作为map的key
  • 函数值之间不可以比较,函数值只可以和nil作比较,函数类型的零值是nil

匿名函数作用域陷阱

请看下列代码输出什么?

123456789101112131415161718192021
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()	}}

 

答案:

1234
4444

在上述代码中,匿名函数中记录的是循环变量的内存地址,而不是循环变量某一时刻的值。

想要输出1、2、3、4需要改为:

123456789101112131415161718192021
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个,每次循环生成一个。

[3]int 和 [4]int 不算同一个类型

请看一下代码,请问输出true还是false

12345678910
import (    "fmt"    "reflect")func main(){    arrayA := [...]int{1, 2, 3}    arrayB := [...]int{1, 2, 3, 4}    fmt.Println(reflect.TypeOf(arrayA) == reflect.TypeOf(arrayB))}

答案是:

1
false

数组长度是数组类型的一个组成部分,因此[3]int和[4]int是两种不同的数组类型。

数组还可以指定一个索引和对应值的方式来初始化。

例如:

12345678
import (    "fmt")func main(){    arrayA := [...]int{0:1, 2:1, 3:4}    fmt.Println(arrayA)}

会输出:

1
[1 0 1 4]

有点像PHP数组的感觉,但是又不一样:arrayA的长度是多少呢?

12345678
import (    "fmt")func main(){    arrayA := [...]int{0:1, 2:1, 3:4}    fmt.Println(len(arrayA))}

答案是:

1
4

没错,定义了一个数组长度为4的数组,指定索引的数组长度和最后一个索引的数值相关,例如:r := [...]int{99:-1}就定义了一个含有100个元素的数组r,最后一个元素输出化为-1,其他的元素都是用0初始化。

不能对map中的某个元素进行取地址&操作

1
a := &ages["bob"] // compile error: cannot take address of map element

map中的元素不是一个变量,不能对map的元素进行取地址操作,禁止对map进行取地址操作的原因可能是map随着元素的增加map可能会重新分配内存空间,这样会导致原来的地址无效

当map为nil的时候,不能添加值

12345
func main() {    var sampleMap map[string]int    sampleMap["test"] = 1    fmt.Println(sampleMap)}

输出报错:

1
panic: assignment to entry in nil map

必须使用make或者将map初始化之后,才可以添加元素。

以上代码可以改为:

12345678
func main() {    var sampleMap map[string]int    sampleMap = map[string]int {        "test1":1,    }    sampleMap["test"] = 1    fmt.Println(sampleMap)}

可以正确输出:

1
map[test1:1 test:1]

&dilbert.Position(&dilbert).Position是不同的

&dilbert.Position相当于&(dilbert.Position)而非(&dilbert).Position

请看例子:

请问输出什么?

123456789101112131415161718
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)}

输出:

1
0xc42006c220

输出的是内存地址

修改一下,把&dilbert.Position改为(&dilbert).Position

123456789101112131415161718
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)}

输出:

1
123

Go语言中函数返回的是值的时候,不能赋值

请看下面例子:

1234567891011121314151617
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 = 1var a = hello world等号=右边的1Hello world是一个概念,他是不能够被赋值的,只有变量能够被赋值。

修改程序如下:

123456789101112131415161718
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}

这就可以编译通过了

在声明方法时,如果一个类型名称本身就是一个指针的话,不允许出现在方法的接收器中

请看下面的例子,请问会编译通过吗?

123456789101112131415161718192021
import (	"fmt")type littleGirl struct{	Name string	Age int}type girl *littleGirlfunc(this girl) changeName(name string){	this.Name = name}func main(){	littleGirl := girl{Name:"Rose", Age:1}		girl.changeName("yoyo")	fmt.Println(littleGirl)}

答案:

1
不能编译通过,会提示“invalid receiver type girl(girl is a pointer type)”

Go语言中规定,只有类型(Type)和指向他们的指针(*Type)才是可能会出现在接收器声明里的两种接收器,为了避免歧义,明确规定,如果一个类型名本身就是一个指针的话,是不允许出现在接收器中的。

函数允许nil指针作为参数,也允许用nil作为方法的接收器

请看下面的例子,请问能编译通过吗?

123456789101112131415161718192021
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)}

答案:

1
不能编译通过,显示"cannot use nil as type littleGirl in assignment"

Go语言中,允许方法用nil指针作为其接收器,也允许函数将nil指针作为参数。而上述代码中的littleGirl不是指针类型,改为*littleGirl,然后变量little赋值为&littleGirl{Name:"Rose", Age:1}就可以编译通过了。

并且,nil对于对象来说是合法的零值的时候,比如map或者slice,也可以编译通过并正常运行。

Golang的时间格式化

不同于PHP的date("Y-m-d H:i:s", time()),Golang的格式化奇葩的很,不能使用诸如Y-m-d H:i:s的东西,而是使用2006-01-02 15:04:05这个时间的格式,请记住这个时间,据说这是Golang的诞生时间。

123456789
time := time.Now()time.Format("20060102") //相当于Ymdtime.Format("2006-01-02")//相当于Y-m-dtime.Format("2006-01-02 15:04:05")//相当于Y-m-d H:i:stime.Format("2006-01-02 00:00:00")//相当于Y-m-d 00:00:00

 

 

转载地址:http://ezwsi.baihongyu.com/

你可能感兴趣的文章
字符编码:ASCII,Unicode 和 UTF-8
查看>>
QT跨MinGW和MSVC两种编译器的解决办法
查看>>
firewalld的基本使用
查看>>
Linux下SVN客户端使用教程
查看>>
i2c-tools
查看>>
Linux分区方案
查看>>
nc 命令详解
查看>>
如何使用 systemd 中的定时器
查看>>
git命令速查表
查看>>
linux进程监控和自动重启的简单实现
查看>>
OpenFeign学习(三):OpenFeign配置生成代理对象
查看>>
OpenFeign学习(四):OpenFeign的方法同步请求执行
查看>>
OpenFeign学习(五):OpenFeign请求结果处理及重试控制
查看>>
OpenFeign学习(六):OpenFign进行表单提交参数或传输文件
查看>>
OpenFeign学习(七):Spring Cloud OpenFeign的使用
查看>>
Ribbon 学习(二):Spring Cloud Ribbon 加载配置原理
查看>>
Ribbon 学习(三):RestTemplate 请求负载流程解析
查看>>
深入理解HashMap
查看>>
XML生成(一):DOM生成XML
查看>>
XML生成(三):JDOM生成
查看>>