go语言学习--1.数据类型

目录

1.go语言的背景

2.go版本的hello world 

3.数据类型

3.1变量声明

3.1.1变量无初始化

3.1.2变量无指定类型

3.1.3 :=符号

3.1.4多个变量声明

3.1.5匿名变量

3.2指针

3.3数组

3.3.1声明数组

3.3.2初始化数组

3.3.3go语言中数组名的意义

3.3.4 数组指针

3.4结构体

3.4.1声明结构体

3.5字符串

3.5.1 字符串定义和初始化

3.6 slice

3.6.1slice定义

3.6.2添加元素


1.go语言的背景

        在具体学习go语言的基础语法之前,我们来了解一下go语言出现的时机及其特点。

        Go语言最初由Google公司的Robert Griesemer、Ken Thompson和Rob Pike三个大牛于2007年开始设计发明,他们最终的目标是设计一种适应网络和多核时代的C语言。所以Go语言很多时候被描述为“类C语言”,或者是“21世纪的C语言”,当然从各种角度看,Go语言确实是从C语言继承了相似的表达式语法、控制流结构、基础数据类型、调用参数传值、指针等诸多编程思想。但是Go语言更是对C语言最彻底的一次扬弃,它舍弃了C语言中灵活但是危险的指针运算,还重新设计了C语言中部分不太合理运算符的优先级,并在很多细微的地方都做了必要的打磨和改变。

2.go版本的hello world 

package main
import "fmt"
func main() {
	// 终端输出hello world
	fmt.Println("Hello world!")
}

和C语言相似,go语言的基本组成有:

  1. 包声明,编写源文件时,必须在非注释的第一行指明这个文件属于哪个包,如package main。
  2. 引入包,其实就是告诉Go 编译器这个程序需要使用的包,如import "fmt"其实就是引入了fmt包。
  3. 函数,和c语言相同,即是一个可以实现某一个功能的函数体,每一个可执行程序中必须拥有一个main函数。
  4. 变量,Go 语言变量名由字母、数字、下划线组成,其中首个字符不能为数字。
  5. 语句/表达式,在 Go 程序中,一行代表一个语句结束。每个语句不需要像 C 家族中的其它语言一样以分号 ; 结尾,因为这些工作都将由 Go 编译器自动完成。
  6. 注释,和c语言中的注释方式相同,可以在任何地方使用以 // 开头的单行注释。以 /* 开头,并以 */ 结尾来进行多行注释,且不可以嵌套使用,多行注释一般用于包的文档描述或注释成块的代码片段。

3.数据类型

在 Go 编程语言中,数据类型用于声明函数和变量。

数据类型的出现是为了把数据分成所需内存大小不同的数据,编程的时候需要用大数据的时候才需要申请大内存,就可以充分利用内存。具体分类如下:

3.1变量声明

声明变量的一般形式是使用 var 关键字,具体格式为:

var name typename

如下的代码中我们定义了一个类型为int的变量。 

package main
import "fmt"
func main() {
	var a int = 27
	fmt.Println(a);
} 

3.1.1变量无初始化

在go语言中定义了一个变量,指定变量类型,如果没有初始化,则变量默认为零值。零值就是变量没有做初始化时系统默认设置的值

3.1.2变量无指定类型

在go语言中如果没有指定变量类型,可以通过变量的初始值来判断变量类型。如下代码

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

3.1.3 :=符号

使用形式:

typename := value
intVal := 1

//var intVal int 
//intVal =1 

3.1.4多个变量声明

可以同时声明多个类型相同的变量(非全局变量),如下图所示:

var x, y int
var c, d int = 1, 2
g, h := 123, "hello"

关于全局变量的声明如下:

var ( vname1 v_type1 vname2 v_type2 )

具体举例如下:

var ( 
    a int
    b bool
)

3.1.5匿名变量

匿名变量的特点是一个下画线_,这本身就是一个特殊的标识符,被称为空白标识符。它可以像其他标识符那样用于变量的声明或赋值(任何类型都可以赋值给它),但任何赋给这个标识符的值都将被抛弃,因此这些值不能在后续的代码中使用,也不可以使用这个标识符作为变量对其它变量进行赋值或运算。

使用匿名变量时,只需要在变量声明的地方使用下画线替换即可。

    func GetData() (int, int) {
        return 10, 20
    }
    func main(){
        a, _ := GetData()
        _, b := GetData()
        fmt.Println(a, b)
    }

3.2指针

与C相同,Go语言让程序员决定何时使用指针。变量其实是一种使用方便的占位符,用于引用计算机内存地址。Go 语言中的的取地址符是&,放到一个变量前使用就会返回相应变量的内存地址。

指针变量其实就是用于存放某一个对象的内存地址。

和基础类型数据相同,在使用指针变量之前我们首先需要申明指针,声明格式如下:var var_name *var-type,其中的var-type 为指针类型,var_name 为指针变量名,* 号用于指定变量是作为一个指针。

var ip *int        /* 指向整型*/
var fp *float32    /* 指向浮点型 */

指针的初始化就是取出相对应的变量地址对指针进行赋值,具体如下:

 var a int= 20   /* 声明实际变量 */
   var ip *int        /* 声明指针变量 */

   ip = &a  /* 指针变量的存储地址 */
//空指针
ip=nil
//nil 相当于NULL

3.3数组

和c语言相同,Go语言也提供了数组类型的数据结构,数组是具有相同唯一类型的一组已编号且长度固定的数据项序列,这种类型可以是任意的原始类型例如整型、字符串或者自定义类型。

3.3.1声明数组

Go 语言数组声明需要指定元素类型及元素个数,语法格式如下:

var variable_name [SIZE] variable_type

var balance [10] float32

3.3.2初始化数组

3.3.3go语言中数组名的意义

        在c语言中我们知道数组名在本质上是数组中第一个元素的地址,而在go语言中,数组名仅仅表示整个数组,是一个完整的值,一个数组变量即是表示整个数组。

        所以在go中一个数组变量被赋值或者被传递的时候实际上就会复制整个数组。如果数组比较大的话,这种复制往往会占有很大的开销。所以为了避免这种开销,往往需要传递一个指向数组的指针,这个数组指针并不是数组。关于数组指针具体在指针的部分深入的了解。

3.3.4 数组指针

通过数组和指针的知识我们就可以定义一个数组指针,代码如下:

var a = [...]int{1, 2, 3} // a 是一个数组
var b = &a                // b 是指向数组的指针

数组指针除了可以防止数组作为参数传递的时候浪费空间,还可以利用其和for range来遍历数组,具体代码如下:

for i, v := range b {     // 通过数组指针迭代数组的元素
    fmt.Println(i, v)
}

3.4结构体

通过上述数组的学习,我们就可以直接定义多个同类型的变量,但这往往也是一种限制,只能存储同一种类型的数据,而我们在结构体中就可以定义多个不同的数据类型。

3.4.1声明结构体

在声明结构体之前我们首先需要定义一个结构体类型,这需要使用type和struct,type用于设定结构体的名称,struct用于定义一个新的数据类型。具体结构如下:

type struct_variable_type struct {
   member definition
   member definition
   ...
   member definition
}

定义好了结构体类型,我们就可以使用该结构体声明这样一个结构体变量,语法如下:

variable_name := structure_variable_type {value1, value2...valuen}

variable_name := structure_variable_type { key1: value1, key2: value2..., keyn: valuen}

 如果要访问结构体成员,需要使用点号 . 操作符,格式为:结构体变量名.成员名。举例代码如下:

package main

import "fmt"

type Books struct {
   title string
   author string
}

func main() {
	var book1 Books
	Book1.title = "Go 语言入门"
	Book1.author = "mars.hao"	
}

3.5字符串

一个字符串是一个不可改变的字节序列,字符串通常是用来包含人类可读的文本数据。和数组不同的是,字符串的元素不可修改,是一个只读的字节数组。每个字符串的长度虽然也是固定的,但是字符串的长度并不是字符串类型的一部分。

3.5.1 字符串定义和初始化

Go语言字符串的底层结构在reflect.StringHeader中定义,具体如下:

type StringHeader struct {
    Data uintptr
    Len  int
}

也就是说字符串结构由两个信息组成:第一个是字符串指向的底层字节数组,第二个是字符串的字节的长度。

字符串其实是一个结构体,因此字符串的赋值操作也就是reflect.StringHeader结构体的复制过程,并不会涉及底层字节数组的复制,所以我们也可以将字符串数组看作一个结构体数组。

字符串和数组类似,内置的len函数返回字符串的长度。

3.6 slice

简单地说,切片就是一种简化版的动态数组。因为动态数组的长度不固定,切片的长度自然也就不能是类型的组成部分了。数组虽然有适用它们的地方,但是数组的类型和操作都不够灵活,而切片则使用得相当广泛。

切片高效操作的要点是要降低内存分配的次数,尽量保证append操作(在后续的插入和删除操作中都涉及到这个函数)不会超出cap的容量,降低触发内存分配的次数和每次分配内存大小。

3.6.1 slice定义

我们先看看切片的结构定义,reflect.SliceHeader:

type SliceHeader struct {
    Data uintptr   // 指向底层的的数组指针
    Len  int	   // 切片长度
    Cap  int	   // 切片最大长度
}

和数组一样,内置的len函数返回切片中有效元素的长度,内置的cap函数返回切片容量大小,容量必须大于或等于切片的长度。

切片可以和nil进行比较,只有当切片底层数据指针为空时切片本身为nil,这时候切片的长度和容量信息将是无效的。如果有切片的底层数据指针为空,但是长度和容量不为0的情况,那么说明切片本身已经被损坏了

只要是切片的底层数据指针、长度和容量没有发生变化的话,对切片的遍历、元素的读取和修改都和数组是一样的。在对切片本身赋值或参数传递时,和数组指针的操作方式类似,只是复制切片头信息(reflect.SliceHeader),并不会复制底层的数据。对于类型,和数组的最大不同是,切片的类型和长度信息无关,只要是相同类型元素构成的切片均对应相同的切片类型。

当我们想定义声明一个切片时可以如下:

在对切片本身赋值或参数传递时,和数组指针的操作方式类似,只是复制切片头信息·(reflect.SliceHeader),并不会复制底层的数据。对于类型,和数组的最大不同是,切片的类型和长度信息无关,只要是相同类型元素构成的切片均对应相同的切片类型。

3.6.2添加元素

append() :内置的泛型函数,可以向切片中增加元素。

  • 在切片尾部追加N个元素
var a []int
a = append(a, 1)               // 追加1个元素
a = append(a, 1, 2, 3)         // 追加多个元素, 手写解包方式
a = append(a, []int{1,2,3}...) // 追加一个切片, 切片需要解包
  • 在切片开头位置添加元素
var a = []int{1,2,3}
a = append([]int{0}, a...)        // 在开头位置添加1个元素
a = append([]int{-3,-2,-1}, a...) // 在开头添加1个切片

 

  • append链式操作
var a []int
a = append(a[:i], append([]int{x}, a[i:]...)...)     // 在第i个位置插入x
a = append(a[:i], append([]int{1,2,3}, a[i:]...)...) // 在第i个位置插入切片
  • append和copy组合
a = append(a, 0)     // 切片扩展1个空间
copy(a[i+1:], a[i:]) // a[i:]向后移动1个位置
a[i] = x             // 设置新添加的元素

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

西柚小萌新

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

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

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

打赏作者

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

抵扣说明:

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

余额充值