go语言元素的引用,go引用类型有哪些,为什么?

讲讲go语言的结构体

作为C语言家族的一员,go和c一样也支持结构体。可以类比于java的一个POJO。

灞桥网站制作公司哪家好,找创新互联!从网页设计、网站建设、微信开发、APP开发、响应式网站建设等网站项目制作,到程序开发,运营维护。创新互联成立与2013年到现在10年的时间,我们拥有了丰富的建站经验和运维经验,来保证我们的工作的顺利进行。专注于网站建设就选创新互联。

在学习定义结构体之前,先学习下定义一个新类型。

新类型 T1 是基于 Go 原生类型 int 定义的新自定义类型,而新类型 T2 则是 基于刚刚定义的类型 T1,定义的新类型。

这里要引入一个底层类型的概念。

如果一个新类型是基于某个 Go 原生类型定义的, 那么我们就叫 Go 原生类型为新类型的底层类型

在上面的例子中,int就是T1的底层类型。

但是T1不是T2的底层类型,只有原生类型才可以作为底层类型,所以T2的底层类型还是int

底层类型是很重要的,因为对两个变量进行显式的类型转换,只有底层类型相同的变量间才能相互转换。底层类型是判断两个类型本质上是否相同的根本。

这种类型定义方式通常用在 项目的渐进式重构,还有对已有包的二次封装方面

类型别名表示新类型和原类型完全等价,实际上就是同一种类型。只不过名字不同而已。

一般我们都是定义一个有名的结构体。

字段名的大小写决定了字段是否包外可用。只有大写的字段可以被包外引用。

还有一个点提一下

如果换行来写

Age: 66,后面这个都好不能省略

还有一个点,观察e3的赋值

new返回的是一个指针。然后指针可以直接点号赋值。这说明go默认进行了取值操作

e3.Age 等价于 (*e3).Age

如上定义了一个空的结构体Empty。打印了元素e的内存大小是0。

有什么用呢?

基于空结构体类型内存零开销这样的特性,我们在日常 Go 开发中会经常使用空 结构体类型元素,作为一种“事件”信息进行 Goroutine 之间的通信

这种以空结构体为元素类建立的 channel,是目前能实现的、内存占用最小的 Goroutine 间通信方式。

这种形式需要说的是几个语法糖。

语法糖1:

对于结构体字段,可以省略字段名,只写结构体名。默认字段名就是结构体名

这种方式称为 嵌入字段

语法糖2:

如果是以嵌入字段形式写的结构体

可以省略嵌入的Reader字段,而直接访问ReaderName

此时book是一个各个属性全是对应类型零值的一个实例。不是nil。这种情况在Go中称为零值可用。不像java会导致npe

结构体定义时可以在字段后面追加标签说明。

tag的格式为反单引号

tag的作用是可以使用[反射]来检视字段的标签信息。

具体的作用还要看使用的场景。

比如这里的tag是为了帮助 encoding/json 标准包在解析对象时可以利用的规则。比如omitempty表示该字段没有值就不打印出来。

Go语言基础语法(一)

本文介绍一些Go语言的基础语法。

先来看一个简单的go语言代码:

go语言的注释方法:

代码执行结果:

下面来进一步介绍go的基础语法。

go语言中格式化输出可以使用 fmt 和 log 这两个标准库,

常用方法:

示例代码:

执行结果:

更多格式化方法可以访问中的fmt包。

log包实现了简单的日志服务,也提供了一些格式化输出的方法。

执行结果:

下面来介绍一下go的数据类型

下表列出了go语言的数据类型:

int、float、bool、string、数组和struct属于值类型,这些类型的变量直接指向存在内存中的值;slice、map、chan、pointer等是引用类型,存储的是一个地址,这个地址存储最终的值。

常量是在程序编译时就确定下来的值,程序运行时无法改变。

执行结果:

执行结果:

Go 语言的运算符主要包括算术运算符、关系运算符、逻辑运算符、位运算符、赋值运算符以及指针相关运算符。

算术运算符:

关系运算符:

逻辑运算符:

位运算符:

赋值运算符:

指针相关运算符:

下面介绍一下go语言中的if语句和switch语句。另外还有一种控制语句叫select语句,通常与通道联用,这里不做介绍。

if语法格式如下:

if ... else :

else if:

示例代码:

语法格式:

另外,添加 fallthrough 会强制执行后面的 case 语句,不管下一条case语句是否为true。

示例代码:

执行结果:

下面介绍几种循环语句:

执行结果:

执行结果:

也可以通过标记退出循环:

--THE END--

go语言数组,切片和字典的区别和联系

、数组 

与其他大多数语言类似,Go语言的数组也是一个元素类型相同的定长的序列。

(1)数组的创建。

数组有3种创建方式:[length]Type 、[N]Type{value1, value2, ... , valueN}、[...]Type{value1, value2, ... , valueN} 如下:

复制代码代码如下:

func test5() {

var iarray1 [5]int32

var iarray2 [5]int32 = [5]int32{1, 2, 3, 4, 5}

iarray3 := [5]int32{1, 2, 3, 4, 5}

iarray4 := [5]int32{6, 7, 8, 9, 10}

iarray5 := [...]int32{11, 12, 13, 14, 15}

iarray6 := [4][4]int32{{1}, {1, 2}, {1, 2, 3}}

fmt.Println(iarray1)

fmt.Println(iarray2)

fmt.Println(iarray3)

fmt.Println(iarray4)

fmt.Println(iarray5)

fmt.Println(iarray6)

}

结果:

[0 0 0 0 0]

[1 2 3 4 5]

[1 2 3 4 5]

[6 7 8 9 10]

[11 12 13 14 15]

[[1 0 0 0] [1 2 0 0] [1 2 3 0] [0 0 0 0]]

我们看数组 iarray1,只声明,并未赋值,Go语言帮我们自动赋值为0。再看 iarray2 和 iarray3 ,我们可以看到,Go语言的声明,可以表明类型,也可以不表明类型,var iarray3 = [5]int32{1, 2, 3, 4, 5} 也是完全没问题的。

(2)数组的容量和长度是一样的。cap() 函数和 len() 函数均输出数组的容量(即长度)。如:

复制代码代码如下:

func test6() {

iarray4 := [5]int32{6, 7, 8, 9, 10}

fmt.Println(len(iarray4))

fmt.Println(cap(iarray4))

}

输出都是5。

(3)使用:

复制代码代码如下:

func test7() {

iarray7 := [5]string{"aaa", `bb`, "可以啦", "叫我说什么好", "()"}

fmt.Println(iarray7)

for i := range iarray7 {

fmt.Println(iarray7[i])

}

}

二、切片

Go语言中,切片是长度可变、容量固定的相同的元素序列。Go语言的切片本质是一个数组。容量固定是因为数组的长度是固定的,切片的容量即隐藏数组的长度。长度可变指的是在数组长度的范围内可变。

(1)切片的创建。

切片的创建有4种方式:

1)make ( []Type ,length, capacity )

2) make ( []Type, length)

3) []Type{}

4) []Type{value1 , value2 , ... , valueN }

从3)、4)可见,创建切片跟创建数组唯一的区别在于 Type 前的“ [] ”中是否有数字,为空,则代表切片,否则则代表数组。因为切片是长度可变的。如下是创建切片的示例:

复制代码代码如下:

func test8() {

slice1 := make([]int32, 5, 8)

slice2 := make([]int32, 9)

slice3 := []int32{}

slice4 := []int32{1, 2, 3, 4, 5}

fmt.Println(slice1)

fmt.Println(slice2)

fmt.Println(slice3)

fmt.Println(slice4)

}

输出为:

[0 0 0 0 0]

[0 0 0 0 0 0 0 0 0]

[]

[1 2 3 4 5]

如上,创造了4个切片,3个空切片,一个有值的切片。

(2)切片与隐藏数组:

一个切片是一个隐藏数组的引用,并且对于该切片的切片也引用同一个数组。如下示例,创建了一个切片slice0,并根据这个切片创建了2个切片 slice1 和 slice2:

复制代码代码如下:

func test9() {

slice0 := []string{"a", "b", "c", "d", "e"}

slice1 := slice0[2 : len(slice0)-1]

slice2 := slice0[:3]

fmt.Println(slice0, slice1, slice2)

slice2[2] = "8"

fmt.Println(slice0, slice1, slice2)

}

输出为:

[a b c d e] [c d] [a b c]

[a b 8 d e] [8 d] [a b 8]

可见,切片slice0 、 slice1 和 slice2是同一个底层数组的引用,所以slice2改变了,其他两个都会变。

(3)遍历、修改切片:

复制代码代码如下:

func test10() {

slice0 := []string{"a", "b", "c", "d", "e"}

fmt.Println("\n~~~~~~元素遍历~~~~~~")

for _, ele := range slice0 {

fmt.Print(ele, " ")

ele = "7"

}

fmt.Println("\n~~~~~~索引遍历~~~~~~")

for index := range slice0 {

fmt.Print(slice0[index], " ")

}

fmt.Println("\n~~~~~~元素索引共同使用~~~~~~")

for index, ele := range slice0 {

fmt.Print(ele, slice0[index], " ")

}

fmt.Println("\n~~~~~~修改~~~~~~")

for index := range slice0 {

slice0[index] = "9"

}

fmt.Println(slice0)

}

如上,前三种循环使用了不同的for range循环,当for后面,range前面有2个元素时,第一个元素代表索引,第二个元素代表元素值,使用 “_” 则表示忽略,因为go语言中,未使用的值会导致编译错误。

只有一个元素时,该元素代表索引。

只有用索引才能修改元素。如在第一个遍历中,赋值ele为7,结果没有作用。因为在元素遍历中,ele是值传递,ele是该切片元素的副本,修改它不会影响原本值,而在第四个遍历——索引遍历中,修改的是该切片元素引用的值,所以可以修改。

结果为:

~~~~~~元素遍历~~~~~~

a b c d e

~~~~~~索引遍历~~~~~~

a b c d e

~~~~~~元素索引共同使用~~~~~~

aa bb cc dd ee

~~~~~~修改~~~~~~

[9 9 9 9 9]

(4)、追加、复制切片:

复制代码代码如下:

func test11() {

slice := []int32{}

fmt.Printf("slice的长度为:%d,slice为:%v\n", len(slice), slice)

slice = append(slice, 12, 11, 10, 9)

fmt.Printf("追加后,slice的长度为:%d,slice为:%v\n", len(slice), slice)

slicecp := make([]int32, (len(slice)))

fmt.Printf("slicecp的长度为:%d,slicecp为:%v\n", len(slicecp), slicecp)

copy(slicecp, slice)

fmt.Printf("复制赋值后,slicecp的长度为:%d,slicecp为:%v\n", len(slicecp), slicecp)

}

追加、复制切片,用的是内置函数append和copy,copy函数返回的是最后所复制的元素的数量。

(5)、内置函数append

内置函数append可以向一个切片后追加一个或多个同类型的其他值。如果追加的元素数量超过了原切片容量,那么最后返回的是一个全新数组中的全新切片。如果没有超过,那么最后返回的是原数组中的全新切片。无论如何,append对原切片无任何影响。如下示例:

复制代码代码如下:

func test12() {

slice := []int32{1, 2, 3, 4, 5, 6}

slice2 := slice[:2]

_ = append(slice2, 50, 60, 70, 80, 90)

fmt.Printf("slice为:%v\n", slice)

fmt.Printf("操作的切片:%v\n", slice2)

_ = append(slice2, 50, 60)

fmt.Printf("slice为:%v\n", slice)

fmt.Printf("操作的切片:%v\n", slice2)

}

如上,append方法用了2次,结果返回的结果完全不同,原因是第二次append方法追加的元素数量没有超过 slice 的容量。而无论怎样,原切片slice2都无影响。结果:

slice为:[1 2 3 4 5 6]

操作的切片:[1 2]

slice为:[1 2 50 60 5 6]

操作的切片:[1 2]

go语言中实现切片(slice)的三种方式

定义一个切片,然后让切片去引用一个已经创建好的数组。基本语法如下:

索引1:切片引用的起始元素位

索引2:切片只引用该元素位之前的元素

例程如下:

在该方法中,我们未指定容量cap,这里的值为5是系统定义的。

在方法一中,可以用arr数组名来操控数组中的元素,也可以通过slice切片来操控数组中的元素。切片是直接引用数组,数组是事先存在的,程序员是可见的。

通过 make 来创建切片,基本语法如下:

make函数第三个参数cap即容量是可选的,如果一定要自己注明的话,要注意保证cap≥len。

用该方法可以 指定切片的大小(len)和容量(cap)

例程如下:

由于未赋值系统默认将元素值置为0,即:

数值类型数组:    默认值为 0

字符串数组:       默认值为 ""

bool数组:           默认值为 false

在方法二中,通过make方式创建的切片对应的数组是由make底层维护,对外不可见,即只能通过slice去访问各个元素。

定义一个切片,直接就指定具体数组,使用原理类似于make的方式。

例程如下:

go语言可以做什么

1、服务器编程:以前你如果使用C或者C++做的那些事情,用Go来做很合适,例如处理日志、数据打包、虚拟机处理、文件系统等。

2、分布式系统、数据库代理器、中间件:例如Etcd。

3、网络编程:这一块目前应用最广,包括Web应用、API应用、下载应用,而且Go内置的net/http包基本上把我们平常用到的网络功能都实现了。

4、开发云平台:目前国外很多云平台在采用Go开发,我们所熟知的七牛云、华为云等等都有使用Go进行开发并且开源的成型的产品。

5、区块链:目前有一种说法,技术从业人员把Go语言称作为区块链行业的开发语言。如果大家学习区块链技术的话,就会发现现在有很多很多的区块链的系统和应用都是采用Go进行开发的,比如ehtereum是目前知名度最大的公链,再比如fabric是目前最知名的联盟链,两者都有go语言的版本,且go-ehtereum还是以太坊官方推荐的版本。

自1.0版发布以来,go语言引起了众多开发者的关注,并得到了广泛的应用。go语言简单、高效、并发的特点吸引了许多传统的语言开发人员,其数量也在不断增加。

使用 Go 语言开发的开源项目非常多。早期的 Go 语言开源项目只是通过 Go 语言与传统项目进行C语言库绑定实现,例如 Qt、Sqlite 等。

后期的很多项目都使用 Go 语言进行重新原生实现,这个过程相对于其他语言要简单一些,这也促成了大量使用 Go 语言原生开发项目的出现。

go语言中数组使用的注意事项和细节

1、数组是多个 相同类型 的数据的组合,一个数组一旦声明/定义了,其 长度是固定的,不能动态变化 。

2、var arr []int    这时arr就是一个slice 切片 。

3、数组中的元素可以是任何数据类型,包括值类型和引用类型,但是 不能混用 。

4、数组创建后,如果没有赋值,有默认值如下:

    数值类型数组:    默认值为 0

    字符串数组:       默认值为 ""

    bool数组:           默认值为 false

5、使用数组的步骤:

    (1)声明数组并开辟空间

    (3)给数组各个元素赋值

    (3)使用数组

6、数组的下标是从0开始的。

7、数组下标必须在指定范围内使用,否则报panic:数组越界,比如var arr [5]int的有效下标为0~4.

8、Go的数组属于 值类型 ,在默认情况下是 值传递 ,因此会进行值拷贝。 数组间不会相互影响。

9、如想在其他函数中去修改原来的数组,可以使用 引用传递 (指针方式)。

10、长度是数组类型的一部分,在传递函数参数时,需要考虑数组的长度,看以下案例:

题1:编译错误,因为不能把[3]int类型传递给[]int类型,前者是数组,后者是切片;

题2:编译错误,因为不能把[3]int类型传递给[4]int类型;

题3:编译正确,因为[3]int类型传给[3]int类型合法。


分享标题:go语言元素的引用,go引用类型有哪些,为什么?
地址分享:http://scjbc.cn/article/dscsiii.html

其他资讯