GoLang之数据定义

文章目录

  • GoLang之数据定义
    • 1.函数返回值问题
    • 2.结构体比较问题
    • 3.string与nil类型
    • 4.常量
    • 5.内存四区概念
      • A.数据类型本质:
      • B. 数据类型的作用:
      • C. 内存四区
        • 栈区(Stack):
        • 堆区(heap):
        • 全局区-静态全局变量区:
        • 全局区-常量区:

GoLang之数据定义

1.函数返回值问题

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

test1.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)
}

答案:

编译报错理由:

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

考点:函数返回值命名

结果:编译出错。

1.在函数有多个返回值时,只要有一个返回值有指定命名,其他的也必须有命名;

2.如果有多个返回值必须加上括号;

2.如果只有一个返回值并且有命名也需要加上括号;

此处函数第一个返回值有sum名称,第二个未命名,所以错误。

2.结构体比较问题

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

test2.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")
	}
}

结果

编译不通过

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

考点:结构体比较

结构体比较规则注意1

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

比如如下:

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

sn1 := struct {
	age  int
	name string
}{age: 11, name: "qq"}

sn3:= struct {
    name string
    age  int
}{age:11, name:"qq"}

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

可以使用reflect.DeepEqual进行比较

func main() {

	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 reflect.DeepEqual(sm1, sm2) {
		fmt.Println("sm1 == sm2") //输出sm1 == sm2
	} else {
		fmt.Println("sm1 != sm2")
	}
}

字段赋值的时候,没按顺序是可以比较的

func main() {
   sn1 := struct {
      age  int
      name string
   }{name: "qq", age: 11}

   sn3 := struct {
      age  int
      name string
   }{age: 11, name: "qq"}
   fmt.Println(sn1 == sn3) //true
}

附:

func main() {
   sn1 := struct {
      age  int
      name string
   }{age: 11, name: "qq"}

   sn3 := struct {
      age  int
      name string
   }{age: 11, name: "qq"}
   fmt.Println(sn1 == sn3)//true
}

3.string与nil类型

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

test3.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函数改成如下形式就可以了

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

4.常量

下面函数有什么问题?

test4.go

package main

const cl = 100

var bl = 123

func main()  {
    println(&bl,bl)
    println(&cl,cl)
}

解析

考点:常量

Go 语言的常量是一种在源码编译期间被创建的语法元素。这是在说这个元素的值可以像变量那样被初始化,但它的初始化表达式必须是在编译期间可以求出值来的。而且,Go 常量一旦声明并被初始化后,它的值在整个程序的生命周期内便保持不变。这样,我们在并发设计时就不用考虑常量访问的同步,并且被创建并初始化后的常量还可以作为其他常量的初始表达式的一部分。但Go 语言规范规定,Go 常量的类型只局限于 Go 基本数据类型,包括数值类型、字符串类型,以及只有两个取值(true 和 false)的布尔类型。

为什么常量不能取值?:

常量不同于变量的在运行期分配内存,常量通常会被编译器在预处理阶段直接展开,作为指令数据使用,所以常量是无法取地址的;

cannot take the address of cl

5.内存四区概念

A.数据类型本质:

​ 固定内存大小的别名

B. 数据类型的作用:

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

GoLang之数据定义_第1张图片

C. 内存四区

流程说明

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

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

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

GoLang之数据定义_第2张图片

栈区(Stack):

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

堆区(heap):

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

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

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

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

在开发的时候,尽量减少使用全局变量的设计

全局变量是可以取地址的

package main

import "fmt"

var a int = 4

func main() {
	fmt.Println(&a, a)
}

全局区-常量区:

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

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

比如,cl是字面量10的对等符号。:

const cl = 10

你可能感兴趣的:(GoLang底层,golang,开发语言,后端)