【Go】一、Go语言基础

前言:为了使得文章的整体结构更清晰明了,大致是这样的结构:一个大标题(简要概述本节的主要方向),如果是一级标题就带上🌞,二级标题带上🌟。

文章大都采用:知识在前,例子在后的形式,来辅助大家更好的理解知识点。

因为是第一次学习Go相关知识,如果有写得不好的地方,欢迎大家批评指正。如果写得还不错,也希望大家能一键三连,被认可,是博主最大的写作动力。下面我们就开启Go学习之路!Fighting!

Go前置知识

1、开发环境🌞

​ 这边不做具体介绍,查看配置文件:vim ~/.bash_profile、查看版本:go version、查看配置环境:go env

// 第一个Go程序
package main // 声明 main包,表明当前是一个可执行完程序
import “fmt” // 导入内置fmt
func main(){ // main函数,是程序执行的入口
  fmt.Println("Hello World!") // 在终端打印 Hello World!
}

​ 运行的话:go run xxx.go 等同于 1)go bulid hello.go 2)./hello 区别在于有没有生成可执行文件

2、Go语言的主要特征🌞

1、优点:

​     1)自带gc;2)静态编译,编译好之后,服务器直接运行;3)简单的思想(没有继承、多态、类);4)丰富的库和详细的开发文档;5)语法层支持并发,拥有同步并发的channel类型,并发开发十分简单;6)简洁的语法,提高开发效率;7)超级简单的交叉编译,只需要修改环境变量

2、主要特征:

​     1)自动立即回收;2)丰富的内置类型;3)函数多返回值;4)错误处理;5)匿名函数和闭包;6)类型和接口;7)并发编程;8)反射;9)语言交互性

3、命名规则:

​     1)首字符可以是任意Unicode字符或下划线;2)剩余字符Unicode字符、下划线or数字;3)字符长度不限

2.1、Go语言的数据类型🌟

1、关键字(25个):

break  default  func  interface  select  case  defer  go  map  struct  chan  else  goto 
package  switch  const  fallthrough  if  range  type  continue  for  import  return  var

2、保留字(37个)

1、Constants
	true  false  iota  nil
2、Types
	int int8 int16 int32 int64
	uint uint8 uint16 uint32 uint64 uintptr
	float32  float64  complex128  complex64
	bool  byte  rune  string  error
3、Functions
	make  len  cap  new  append  copy  close  delete
	complex  real  imag  
	panic  recover

3、Go语言基础类型

​     1)布尔型(true|false):var b bool = true

​     2)数字类型:int、float32、float64(Go支持整数和浮点数,支持复数,其中位的运算采用补码

​     3)字符串类型:使用UTF-8编码标识的Unicode文本

​     4)派生类型:Pointer指针类型、数组类型、Struct结构化类型、Channel类型、函数类型、切片类型、Interface接口类型、Map类型

2.2、Go语言基础语法🌟

1、标识符

​     用来命名变量、类型等程序实体( 无效标识符举例:1)以数字开头;2)go中的关键字;3)运算符不被允许 )

2、字符串连接:

​     通过+实现连接 => fmt.Println(“chen” + “zhihui”)

3、格式化字符串

1、fmt.Sprintf 根据格式花参数生成格式化字符串并返回该字符串
package main
import “fmt”
func main() {
  var stockcode = 123
  var enddate = "2022-4-18"
  var url = "Code = %d & endDate = %s"
  var target_url = fmt.Sprintf(url, stockcode, enddate)
  fmt.Println(target_url)
}

2、fmt.printf 根据格式化参数生成的字符串并写入标准输出
package main
import “fmt”
func main() {
  var stockcode = 123
  var enddate = "2022-4-18"
  var url = "Code = %d & endDate = %s"
  var target_url = fmt.Printf(url, stockcode, enddate)
}

3、多行字符串 => 使用 ``反引号字符(期间所有的转义字符会无效,文本将原样输出)

4、字符串常见操作

​     1)len(str) --求长度

​     2)+或fmt.Srpintf --拼接字符串

​     3)strings.Spilt --分割

​     4)strings.Contains --判断是否包含

​     5)strings.HasPrefix --前缀判断

​     6)strings.HasSuffix --后缀判断

​     7)strings.Index() --子串出现的位置

​     8)strings.LastIndex() --最后出现的位置

​     9)strings.join(a[]string, sep string) --join操作

5、修改字符串

​     先转成[]rune 或 []byte,完成后再转换为string(无论哪种转换,都会重新分配内存,并复制字节组)

func changeString() {
  s1 := "hello"
  // 强制类型转换
  byteS1 := []byte(s1)
  byteS1[0] = ‘H’
  fmt.Println(String(byteS1))
  s2 := "博客"
  runeS2 := []rune(s2)
  runeS2[0] = '狗'
  fmt.println(String(runS2))
}

// 其中[]rune针对存在汉字字符

2.3、Go语言变量🌟

1、可见性:

​     1)声明在函数内部,是函数的本地值,类似private

​     2)声明在函数外部,是对当前包可见的全局值,类似protect

​     3)声明在函数外部且首字母大写是所有包可见的全局值,类似public

2、声明(package xxx、import xxx)

​     1)var 声明变量

​     2)const 声明常量

​     3)type 声明类型

​     4)func 声明函数

3、默认零值:

     a)指定变量类型,如果没有初始化,默认位0值

1)数值类型 02)布尔类型:false3)字符串:“”;

4var a *int | var a []int | var a map[string] int | var a chan int | var a func(string) int | var a error => 默认nil

     b)根据值自行判定变量类型

package main
import "fmt"
func main() {
  var d = true
  fmt.Println(d)
}

结果:true

     c)如果已经使用var声明过,再使用:=声明变量,就会产生编译错误

所以声明变量可以直接: xxx := yyy (xx为变量名、yyy为值)

4、多变量声明

// 类型相同多个变量(非全局)
var s1, s2, s3 = v1, v2, v3
s1, s2, s3 := v1, v2, v3
// 全局变量
var (
	vname1 xxx
  vname2 yyy
)

5、值类型和引用类型

​     值类型:变量直接指向存在内存中的值

​     引用类型:如j=i,实际上是内存讲i的值进行拷贝(存的是地址)

6、变量声明之后一定要被使用!!!

7、交换二者的值

​     a, b = b, a

8、空白标识符_(匿名变量)

     _, b = 5, 7 -> 意味着_被抛弃(因为Go中必须使用锁声明的宿友变量,但有时候并不需要使用从一个函数得到的所有值)

2.4、Go语言常量🌟

​     格式: const xxx type = value (type表示类型,可以省略)

1、iota

​     iota是特殊常量,可被编译器修改的常量(const关键字出现时重置为0,每新增一行常量将使得iota计数一次),iota开始意味着计数、否则默认对上面一行进行复制操作

// a = 0, b = 1, c = 2 
const (
  a = iota
  b
  c
)

3、Go内置类型和函数🌞

1、内置类型:值类型 和 引用类型(slice序列数组、map映射、chan管道)

2、内置函数

append	--追加元素到数组,slice中,返回修改后的数组
close  	--主要用来关闭channel
delete	--map中删除key对应的value
panic		--停止使用常规goroutine  (panicrecover用来做错误处理)
recover --允许程序定义goroutine的panic动作
real		--返回complex的实部	(complexrealimag:用来创建和操作复数)
imag		--返回complex的虚部
make		--用来分配内存,返回type本身(应用于slice、map、channel)
new			--用来分配内存,返回分配值类型,比如intstruct
cap			--capacity是容量的意思,用于返回某个类型的最大容量(只能用于切片和mapcopy		--用于复制和连接slice,返回复制的数目
len			--求长度,比如string、array、slice、map、channel
print		--同下
println --底层打印函数,在环境中部署建议使用fmt包

3、内置接口 error

type error interface { // 只要实现Error()函数,返回值为String的都实现err接口
  Error() String
}

4、init函数和main函数🌞

4.1、init函数🌟

​ go语言中 init函数 用于包package的初始化,有如下特征:

​      1)init函数是用于程序执行前做包的初始化函数,比如初始化包里的变量

​      2)每个包可以拥有多个init函数

​      3)包的每个源文件可以拥有多个init函数

​      4)同一个包中的多个init函数的执行中,没有明确的定义(随机)

​      5)不同包的init函数按照包蹈入的依赖关系,决定该初始化函数的执行顺序

​      6)init不能被其他函数调用,而且在main函数执行之前,自动被调用

4.2、main函数🌟

// Go语言程序的默认入口函数 
func main() {
  // 函数体
}

总结

1、init函数和main函数的异同

相同:

​ 两个函数在定义时候,不能有任何的参数和返回值,且Go程序自动调用

不同:

​      1)init函数可以应用与任意包中,且可以重复定义多个;
     2)main函数只能用于main包中,且只能定义一个

2、init函数和main函数的执行顺序

​      1)对于同一个go文件,init的调用顺序是从上往下掉

​      2)对于同一个package中不同文件是按照文件名字符串比较“从小到大”顺序调用各文件中的init()函数

​      3)对于不同package,如果不互相依赖,按照main包中先import的后调用的顺序调用其包中的init();如果存在依赖的话,则先调用最早被依赖的package中的init(),最后调用main

​      4)如果init()函数中使用println或者print,不会按照顺序执行,建议在测试环境中使用

5、命令🌞

go env			--go语言环境信息
go run			--编译并运行源代码文件
go get			--根据要求和实际情况从互联网上下载或更新指定代码包及其依赖包,并进行编译和安装
go build 		--编译指定的源码文件或代码以及它们的依赖包
go install 		--安装并指定的代码及他们的依赖包
go clean		--删除执行其他命令产生的文件和目录
go doc			--可以打印附于Go语言程序实体上的文档
go test 		--对Go语言编写的程序进行测试
go list			--列出指定代码包的信息
go fix			--指定代码包的所有go源代码文件的旧版本修正在新版本代码
go vet			--用于检查go语言源码中静态错误的简单工具
go tool pprof 	--交互式访问概要文件的内容

6、运算符🌞

1、算数运算符

​     +、-、*、/、%(注意:++和–属于单独语句,并不是运算符)

2、关系运算符

​     ==、!=、>、>=、<、<=

3、逻辑运算符

​     &&、||、! (分别代表逻辑and、逻辑or、逻辑not)

4、位运算符

​     &:二进制位相与,二者都相同才为1

​     !:二进制位相或,只要一个为1就为1

​     ^:二进制位相异或,二者不一样才为1

​     <<:左移n位,也就是乘2的n次方

​     >>:右移n位,也就是除2的n次方

5、赋值运算符

​     =、+=、-=、*=、/=、%=、<<=、>>=、&=、!=、^=

7、下划线🌞

     “_”是特殊标识符,用来忽略结果

7.1、下划线在import中🌟

​     import_ 包路径的作用:当导入一个包的时候,该包下的所有文件都会被使用。然而,有些时候我们并不需要把整个包都导入进来,仅仅是希望它执行init()函数而已,这个时候就可以使用import_引用该包(仅仅是为了调用init函数,无法通过包名来调用包中的其他函数)

7.2、下划线在代码中🌟

package main

import (
    "os"
)

func main() {
    buf := make([]byte, 1024)
    f, _ := os.Open("/Users/***/Desktop/text.txt") // 该处本来os.Open是返回*os.file和error,因为不需要错误信息,所以用"_"来接收,表示不需要
    defer f.Close()
    for {
        n, _ := f.Read(buf) // 占位符的意思,函数返回两个值,但是我们只需要一个值,就用"_"来接收,但不使用
        if n == 0 {
            break    

        }
        os.Stdout.Write(buf[:n])
    }
}

Go语言数据类型

1、数组Array🌞

Golang Array和以往认知的数组有很大的不同

1、数组:是同一种数据类型的固定长度的序列
2、数组定义:var a [len]int :数组长度必须是常量,且是必须要有的,一定定义,长度不变
3、长度是数组的一部分,var a[5] intvar b[10] int 是不同的类型
4、数组通过下标访问,下标0开始,最后一个元素是len-1
5、访问越界,会panic
6、数组是值类型,赋值和传参会复制整个数组,而不是指针,改变的是副本的值,而不改变本身
7、支持 ==!=
8、指针数组 [n]*T、数组指针 *[n]T

1.1、数组初始化🌟

1、一维数组
全局:
  var arr0 [5]int = [5]int{1, 2, 3}
  var arr1 = [5]int{1, 2, 3, 4, 5}
  var arr2 = [...]int{1, 2, 3, 4, 5, 6}
  var str = [5]string{3: "hello world", 4: "tom"}
局部:
  a := [3]int{1, 2}           // 未初始化元素值为 0。
  b := [...]int{1, 2, 3, 4}   // 通过初始化值确定数组长度。
  c := [5]int{2: 100, 4: 200} // 使用索引号初始化元素。
  d := [...]struct {
    name string
    age  uint8
  }{
    {"user1", 10}, // 可省略元素类型。
    {"user2", 20}, // 别忘了最后一行的逗号。
  }

2、多维数组
全局
  var arr0 [5][3]int
  var arr1 [2][3]int = [...][3]int{{1, 2, 3}, {7, 8, 9}}
局部:
  a := [2][3]int{{1, 2, 3}, {4, 5, 6}}
  b := [...][2]int{{1, 1}, {2, 2}, {3, 3}} // 第 2 纬度不能用 "..."

3、注意:值拷贝行为会造成性能问题,通常建议使用slice,或数组指针

2、切片Slice🌞

​     slice并不是数组或数组指针,它通过内部指针和相关属性引用数组片段,以实现变长方案。

1、切片:`切片是数组的一个引用,因此切片可以是引用类型,但自身是结构体,值拷贝传递`
2、切片的长度是可以改变的,因此,切片是一个可变的数组
3、切片的遍历和数组一样,可以用len()求长度,表示可用元素长度,读写操作不能超过该限制
4cap可以求出slice最大扩张容量,不能超出数组的限制:0<=len(slice)<=len(array),其中array是slice引用的数组
5、切片的定义:var 变量名 []类型,如: var str []stringvar arr []int
6、如果slice = nil,那么 lencap结果都为0

2.1、切片的创建方式🌟

package main

import (
	"fmt"
)

func main() {
	// 1、声明切片
	var s1 []int
	if s1 == nil {
		fmt.Println("空的")
	} else {
		fmt.Println("不是空的")
	}
	// 2、简约创建
	s2 := []int{}
	// 3、make()
	var  s3 []int = make([]int, 0)
	fmt.Println(s1, s2, s3)
	// 4、初始化赋值
	var s4 []int = make([]int, 0, 0)
	fmt.Println(s4)
	s5 := []int{1,2,3}
	fmt.Println(s5)
	// 5、从数组中切片
	arr := []int{1, 2, 3, 4, 5}
	var s6 []int
	s6 = arr[1:4]
	fmt.Println(s6)
}

2.2、切片初始化🌟

全局:
  var arr = [...]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
  var slice0 []int = arr[start:end] 
  var slice1 []int = arr[:end]        
  var slice2 []int = arr[start:]        
  var slice3 []int = arr[:] 
  var slice4 = arr[:len(arr)-1]      //去掉切片的最后一个元素
局部:
  arr2 := [...]int{9, 8, 7, 6, 5, 4, 3, 2, 1, 0}
  slice5 := arr[start:end]
  slice6 := arr[:end]        
  slice7 := arr[start:]     
  slice8 := arr[:]  
  slice9 := arr[:len(arr)-1] //去掉切片的最后一个元素

2.3、通过make来创建切片🌟

var slice []type = make([]type, len)

1、slice := make([]type, len)
2、slice := make([]type, len, cap)

好处:

​     1、使用make动态创建slice,避免了数组必须用常量做长度的麻烦,还可以用指针直接访问底层数组,退化成普通数组操作

​     2、其中[][]T,是指元素类型为[]T

2.4、用append内置函数操作切片(切片追加)🌟

package main

import "fmt"

func main() {
	var s1 []int = []int{1, 2, 3}
	var s2 []int = []int{4, 5, 6}
	s3 := append(s1, s2...)
  s3 = append(s3, 9)
  s3 = append(s3, 10, 11, 12)
	fmt.Println(s3)
}

// 运行结果:[1 2 3 4 5 6 9 10 11 12]
// 注意s3 := append(s1, s2...),里面的这个...是必要的写法哦!

​     如果超出原slice.cap的限制,就会以2倍大小重新分配底层数组,即使原数组并未填满 => 通常以两倍容量重新分配底层数组,建议一次足够多的空间,以减少内存分配和数据复制的开销

2.5、切片拷贝🌟

​     copy(s1, s2),copy函数在两个slice间复制数据,复制长度以len小的为准,两个slice可以指向同一个底层数组,允许区间重叠。

2.6、字符串和切片🌟

​     string底层就是一个byte数组,因此也可以进行切片操作

str := "hello world"
s1 := str[0:5] => hello
s2 := str[6:] => world

1、如何改变string中的字符(string不可变)

str string := "hello world"
// 1、转换为[]byte
s := []byte(str) //中文字符的话需要[]rune(str)
s[6] = 'G'
s := s[:8]
s = append(s, '!')
=> hello Go!

2、slice[x:y:z] => 切片内容[x:y],切片长度y-x,切片容量z-x

3、Slice的底层实现🌞

​     切片是一种数据结构,使用这种结构可以用来管理数据集合,切片的设计想法是由动态数组概念来的,为了开发者可以更加方便的使用一个数据结构可以自动增加和减少,但是切片本身并不是动态数组或数组指针。切片的常用操作由:reslice、append、copy,同时切片还具有索引、可迭代的优秀性质。

3.1、切片和数组🌟

1、与C数组不同的是,Go数组是值类型,赋值和函数传参操作都会复制整个数组数据(最直观的,赋值之后,数组的首地址是不一样的) => 会导致消耗大量内存 => 所以数组指针出现,就算是传输很大的数据,也只需要在栈上分配一个8个字节的内存给指针就可以 => 弊端原数组指针修改,所有函数指针都跟着更改 => 切片的出现

2、切片的优势:1)即可以达到节约内存的目的;2)又可以合理处理好共享内存的问题;

3.2、切片数据结构🌟

type slice struct {
  array unsafe.Pointer
  len int
  cap int // cap总是大于len的
}

3.3、创建切片🌟

​     空切片和nil切片的区别:1)空切片指向的是地址不是nil,是一个内存地址,没有分配任何内存空间,底层包含0个元素;

3.4、切片扩容策略🌟

​     1)切片容量小于1024,扩容的时候翻倍;2)大于1024,增长因子变为1.25,即每次扩容为原来容量的1/4

4、指针🌞

​     区别于C/C++中的指针,Go语言的指针不能进行偏移和运算,是安全指针(指针地址、指针类型、指针取值)

4.1、Go语言中的指针🌟

​     Go语言中的函数传参都是值拷贝,要修改某个变量的时候,可以创建一个指向该变量地址的指针变量,传递数据时候使用指针,而无需拷贝数据。类型指针不能进行偏移和运算,Go语言中的指针操作十分简单,&取地址、*地址取值

4.2、指针地址和指针类型和指针取值🌟

​     每个变量在运行时候都拥有一个地址,这个地址表示变量在内存中的位置。Go语言中使用&字符放在变量前面对变量进行“取地址”操作,Go语言中的值类型:int、float、bool、string、array、struct都有对应的指针类型:如*int、*****int64等

1、空指针:使用nil判断

4.3、new 和 make🌟

1、new是一个内置的函数 => 不常用,使用new得到一个类型的指针,并且该指针对应的值为该类型的零值

func new(type) *Type

// 1、Type表示类型,new只接受一个参数(类型)
// 2、*Type表示类型指针,使用new函数返回一个指向该类型内存地址的指针

2、make也是属于内存分配的,区别于new,只用于slice、map以及chan的内存创建,返回的类型就是这三类,而不是指针

func make(t Type, size ...IntegerType) Type
1make函数是无可代替的,我们在使用slice、map以及channel的时候,都需要使用make进行初始化,才进行操作

3、区别

​     1)二者都是用来做内存分配的

​     2)make只用于slice、map、channel的初始化,返回的还是这三个引用类型本身

​     3)new用于类型的内存分配,并且内存对应的值为类型的零值,返回的是指向类型的指针

5、Map🌞

​     map是一种无序的,基于key-value的数据结构,Go语言中的map是引用类型,必须初始化才能使用。

5.1、map定义🌟

1、定义:make[KeyType]ValueType
2、初始化:make(map[KeyType]ValueType, [cap]) // cap不是必须的,尽量设置指定一个合适的容量

5.2、map的基本使用🌟

1、情况1
func main() {
  scoreMap := make(map[string]int, 8)
  scoreMap["czh"] = 10
  scoreMap["hyt"] = 100
  fmt.Println(scoreMap)
  fmt.Println(scoreMap["czh"])
}
2、情况2:切记每一行都要使用','
func main() {
  userInfo := map[string]string {
    "username" : "czh",
    "password" : "123456",
  }
}

5.3、基本处理🌟

1、判断某个健是否存在

value, ok := map[key] //如果存在key及其对应的value,那么将值赋值给value,并且此时ok=true,否则value为空,且ok=false

2、map的遍历

for k, v : range scoreMap {
  fmt.Println(k, v)
}

3、delete()删除键值对

delete(map, key)

4、按照指定顺序遍历map

​     这边举例的是,对切片进行排序后,按照排序后的key进行遍历

5、元素为map类型的切片

package main

import "fmt"

func main() {
	var mapSlice = make([]map[string]string, 3)
	for index, value := range mapSlice {
		fmt.Printf("index:%d value: %v\n", index, value)
	}
	fmt.Println("after init")
	// 对切片中的mao进行初始化
	mapSlice[0] = make(map[string]string, 10)
	mapSlice[0]["name"] = "czh"
	mapSlice[0]["password"] = "2425540101@qq.com"
	mapSlice[0]["address"] = "xxx"
	for index, value := range mapSlice {
		fmt.Printf("index:%d value: %v\n", index, value)
	}
}

6、值为切片类型的map

func main() {
    var sliceMap = make(map[string][]string, 3)
    fmt.Println(sliceMap)
    fmt.Println("after init")
    key := "中国"
    value, ok := sliceMap[key]
    if !ok {
        value = make([]string, 0, 2)
    }
    value = append(value, "北京", "上海")
    sliceMap[key] = value
    fmt.Println(sliceMap)
}

6、Map实现原理🌞

​     map是key-value存储的一种方式,即通过key来获取value的值,底层存储方式是数组,在存储时候key不能重复,当key重复的时候,value会进行覆盖(key通过hash运算,然后对数组的长度取余,得到在数组的哪个下标的位置,将key和value组装为一个结构体,放在数组下标的位置)

1、使用方式

// 直接初始化一个map
var mapInit = map[string]string {"xiaoli" : "湖南", "xiaohu" : "天津"}
// 声明一个map类型的变量
// map的key类型是string,value的类型也是string
var mapTemp map[string]string
// 使用make函数初始化这个变量,并指定大小(也可以不指定)
mapTemp = make(map[string]string, 10)
// 存储key value
mapTemp["xiaoming"] = "北京"
mapTemp["xiaowang"] = "河北"
// 根据key获取value
// 如果key存在,则ok为true
// v1用来接收key对应的value,ok是false的时候,v1是nil
v1, ok := mapTemp["xiaoming"]
fmt.Println(ok, v1)
// 当key=xiaohu的时候,打印value
if v2, ok = mapTemp["xiaohu"]; ok {
  fmt.Println(v2)
}
// 遍历map,打印key和value
for k, value := range mapTemp {
  fmt.Println(k, v)
}

7、结构体🌞

类型

​     Go中没有类的概念,也不支持类的继承等面向对象的概念,Go语言在结构体的内嵌再配合接口对比面向对象具有更高的扩展性和灵活性。

1、自定义类型:type MyInt int

2、类型别名:type TypeAlias = Type

3、区别:相当于类型别名是利用原有的类型,而自定义类型是新建的,属于当前文件下的类型

结构体:是一种自定义数据类型,可以封装多个基本数据类型,这种数据类型叫结构体,成为struct

1、定义:(同类型的字段可以写在同一行,以,隔开)

type 类型名 struct {

​ 字段名 字段类型

​ 字段名2 字段类型

}

7.1、结构体实例化🌟

​     只有当结构体实例化时,才会真正的分配内存,也就是必须实例化后才能使用结构体作为字段。结构本身也是一种类型,我们可以像内置类型一样使用var关键字声明结构体类型: var 结构体实例 结构体类型

type person struct {
    name string
    city string
    age  int8
}

func main() {
    var p1 person
    p1.name = "pprof.cn"
    p1.city = "北京"
    p1.age = 18
    fmt.Printf("p1=%v\n", p1)  //p1={pprof.cn 北京 18}
    fmt.Printf("p1=%#v\n", p1) //p1=main.person{name:"pprof.cn", city:"北京", age:18}
}

7.2、匿名结构体🌟

package main

import (
    "fmt"
)

func main() {
    var user struct{Name string; Age int}
    user.Name = "pprof.cn"
    user.Age = 18
    fmt.Printf("%#v\n", user)
}

7.3、使用值的列表初始化🌟

​ 初始化结构体的时候可以简写,初始化的时候不写键,直接写值,需注意:

​      1)必须初始化结构体的所有字段;

​      2)初始值的填充顺序必须与字段在结构体中的声明顺序一致;

​      3)该方式不能和键值初始化方式混用

p5 := person{
    name: "pprof.cn",
    city: "北京",
    age:  18,
}
fmt.Printf("p5=%#v\n", p5) //p5=main.person{name:"pprof.cn", city:"北京", age:18}

总结:这是修改的第三个版本,主要是针对内容进行修缮,对格式进行稍微编排。学到这里大家应该对Go有一个简单的认识,后续的文章中,将带大家一步步深入了解Go,花最少的时间,享受知识的快速掌握!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Coder陈、

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值