1、数据定义

(1).函数返回值问题

下面代码是否可以编译通过?

test1.go

  1. package main
  2. /*
  3. 下面代码是否编译通过?
  4. */
  5. func myFunc(x,y int)(sum int,error){
  6. return x+y,nil
  7. }
  8. func main() {
  9. num, err := myFunc(1, 2)
  10. fmt.Println("num = ", num)
  11. }

答案:

编译报错理由:

  1. # command-line-arguments
  2. ./test1.go:6:21: syntax error: mixed named and unnamed function parameters

考点:函数返回值命名

结果:编译出错。

在函数有多个返回值时,只要有一个返回值有指定命名,其他的也必须有命名。 如果返回值有有多个返回值必须加上括号; 如果只有一个返回值并且有命名也需要加上括号; 此处函数第一个返回值有sum名称,第二个未命名,所以错误。

(2).结构体比较问题

下面代码是否可以编译通过?为什么?

test2.go

  1. package main
  2. import "fmt"
  3. func main() {
  4. sn1 := struct {
  5. age int
  6. name string
  7. }{age: 11, name: "qq"}
  8. sn2 := struct {
  9. age int
  10. name string
  11. }{age: 11, name: "qq"}
  12. if sn1 == sn2 {
  13. fmt.Println("sn1 == sn2")
  14. }
  15. sm1 := struct {
  16. age int
  17. m map[string]string
  18. }{age: 11, m: map[string]string{"a": "1"}}
  19. sm2 := struct {
  20. age int
  21. m map[string]string
  22. }{age: 11, m: map[string]string{"a": "1"}}
  23. if sm1 == sm2 {
  24. fmt.Println("sm1 == sm2")
  25. }
  26. }

结果

编译不通过

  1. ./test2.go:31:9: invalid operation: sm1 == sm2 (struct containing map[string]string cannot be compared)

考点:结构体比较

结构体比较规则注意1:只有相同类型的结构体才可以比较,结构体是否相同不但与属性类型个数有关,还与属性顺序相关.

比如:

  1. sn1 := struct {
  2. age int
  3. name string
  4. }{age: 11, name: "qq"}
  5. sn3:= struct {
  6. name string
  7. age int
  8. }{age:11, name:"qq"}

sn3sn1就不是相同的结构体了,不能比较。

结构体比较规则注意2:结构体是相同的,但是结构体属性中有不可以比较的类型,如map,slice,则结构体不能用==比较。

可以使用reflect.DeepEqual进行比较

  1. if reflect.DeepEqual(sm1, sm2) {
  2. fmt.Println("sm1 == sm2")
  3. } else {
  4. fmt.Println("sm1 != sm2")
  5. }

(3).string与nil类型

下面代码是否能够编译通过?为什么?

test3.go

  1. package main
  2. import (
  3. "fmt"
  4. )
  5. func GetValue(m map[int]string, id int) (string, bool) {
  6. if _, exist := m[id]; exist {
  7. return "存在数据", true
  8. }
  9. return nil, false
  10. }
  11. func main() {
  12. intmap:=map[int]string{
  13. 1:"a",
  14. 2:"bb",
  15. 3:"ccc",
  16. }
  17. v,err:=GetValue(intmap,3)
  18. fmt.Println(v,err)
  19. }

考点:函数返回值类型

答案:编译不会通过。

分析:

nil 可以用作 interface、function、pointer、map、slice 和 channel 的“空值”。但是如果不特别指定的话,Go 语言不能识别类型,所以会报错。通常编译的时候不会报错,但是运行是时候会报:cannot use nil as type string in return argument.

所以将GetValue函数改成如下形式就可以了

  1. func GetValue(m map[int]string, id int) (string, bool) {
  2. if _, exist := m[id]; exist {
  3. return "存在数据", true
  4. }
  5. return "不存在数据", false
  6. }

(4) 常量

下面函数有什么问题?

test4.go

  1. package main
  2. const cl = 100
  3. var bl = 123
  4. func main() {
  5. println(&bl,bl)
  6. println(&cl,cl)
  7. }

解析

考点:常量 常量不同于变量的在运行期分配内存,常量通常会被编译器在预处理阶段直接展开,作为指令数据使用,

  1. cannot take the address of cl

内存四区概念:

A.数据类型本质:

​ 固定内存大小的别名

B. 数据类型的作用:

​ 编译器预算对象(变量)分配的内存空间大小。

1、数据定义 - 图1

C. 内存四区

1、数据定义 - 图2

流程说明

1、操作系统把物理硬盘代码load到内存

2、操作系统把c代码分成四个区

3、操作系统找到main函数入口执行

栈区(Stack):

​ 空间较小,要求数据读写性能高,数据存放时间较短暂。由编译器自动分配和释放,存放函数的参数值、函数的调用流程方法地址、局部变量等(局部变量如果产生逃逸现象,可能会挂在在堆区)

堆区(heap):

​ 空间充裕,数据存放时间较久。一般由开发者分配及释放(但是Golang中会根据变量的逃逸现象来选择是否分配到栈上或堆上),启动Golang的GC由GC清除机制自动回收。

全局区-静态全局变量区:

​ 全局变量的开辟是在程序在main之前就已经放在内存中。而且对外完全可见。即作用域在全部代码中,任何同包代码均可随时使用,在变量会搞混淆,而且在局部函数中如果同名称变量使用:=赋值会出现编译错误。

​ 全局变量最终在进程退出时,由操作系统回收。

  1. > 我么在开发的时候,尽量减少使用全局变量的设计
全局区-常量区:

​ 常量区也归属于全局区,常量为存放数值字面值单位,即不可修改。或者说的有的常量是直接挂钩字面值的。

比如:

  1. const cl = 10

cl是字面量10的对等符号。

所以在golang中,常量是无法取出地址的,因为字面量符号并没有地址而言。