Go基础:下划线“_”、变量和常量、数组、slice

简介: Go基础:下划线“_”、变量和常量、数组、slice

目录

前言:

Go语言的设计初衷

Go语言很特别

Go语言的主要特征

GO概览

Go基础

应用程序入口

Go语言声明

下划线(很特殊)

变量声明

类型转化

类型的预定义值

指针类型

常量声明

数组

数组截取

用 == 比较数组

位运算符--&^ 按位置零

切片Slice

数组 vs. 切片

1 array

2 slice



前言:

Go语言的设计初衷

  • 针对其他语言的痛点进行设计
  • 并加入并发编程
  • 为大数据、微服务、并发而生的通用编程语言


Go语言很特别

  • 没有“对象”,没有继承多态、类等,没有泛型,没有try/catch
  • 有接口,函数式编程,CSP并发模型(goroutine+channel)
  • 自带gc
  • 静态编译,编译好后,扔服务器直接运行
  • 学习Go语言很简单,因为语法简单
  • 用好Go语言不容易,因为要调整三观

 


Go语言的主要特征

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


GO概览

  • 基本语法:变量,选择、循环,指针,数组,容器
  • 面向接口:接口体,duck typing的概念,组合的思想
  • 函数式编程:闭包的概念
  • 工程化:资源管理、错误管理、测试和文档、性能调优
  • 并发编程:理解调度器


Go基础

应用程序入口

应用程序入口

  • 1. 必须是 main 包: package mai
  • 2. 必须是 main 方法: func main()
  • 3.⽂文件名不不⼀一定是 main.go

退出返回值---与其他主要编程语⾔言的差异

  • 1.Go 中 main 函数不不⽀支持任何返回值
  • 2. 通过 os.Exit 来返回状态

获取命令⾏行行参数---与其他主要编程语⾔言的差异

  • 1.main 函数不不⽀支持传⼊入参数

   func main(arg []string)

  • 2.在程序中直接通过 os.Args 获取命令⾏行行参数


Go语言声明

  • var(声明变量)
  • const(声明常量)
  • type(声明类型)
  • func(声明函数)

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

2)声明在函数外部,是对当前包可见(包内所有.go文件都可见)的全局值,类似protect

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


下划线(很特殊)

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

  • 下划线在import中:用【import _ 包路径】只是引用该包,仅仅是为了调用init()函数,所以无法通过包名来调用包中的其他函数
  • 下划线在代码中:忽略这个变量,意思是那个位置本应赋给某个值,但是咱们不需要这个值。所以就把该值赋给下划线,意思是丢掉不要。


变量声明

  • Go语言中的变量需要声明后才能使用,同一作用域内(可以放在函数内,也可以放在包内)不支持重复声明。并且Go语言的变量声明后必须使用。
  • 使用var()集中定义常量
  • 在函数内部,可以使用更简略的 := 方式声明并初始化变量。:=不能使用在函数外
  • 没有char,只有rune: rune类型用来表示utf8字符,一个rune字符由一个或多个byte组成
  • 原生支持复数:complex64  complex128 (实部、虚部)


类型转化

  • Go 语⾔言不允许隐式类型转换
  • 别名和原有类型也不能进行隐式类型转换


类型的预定义值

  • math.MaxInt64
  • math.MaxFloat64
  • math.MaxUint32


指针类型

  1. 不⽀持指针运算
  2. string 是值类型,其默认的初始化值为空字符串,而不是 nil


常量声明

  • 常量的声明和变量声明非常类似,只是把var换成了const,常量在定义的时候必须赋值
  • Go语言的常量不用大写,在go中大小写是有区别的
  • iota(自增值)go语言的常量计数器,只能在常量的表达式中使用。


数组

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

1. 数组:是同一种数据类型的固定长度的序列。

2. 数组定义:var a [len]int,比如:var a [5]int,数组长度必须是常量,且是类型的组成部分。一旦定义,长度不能变。数量写在类型前

3. 长度是数组类型的一部分因此,var a[5] int和var a[10]int是不同的类型

4. 数组可以通过下标进行访问,下标是从0开始,最后一个元素下标是:len-1

for i := 0; i < len(a); i++ {
}
for index, v := range a {
}

5. 访问越界,如果下标在数组合法范围之外,则触发访问越界,会panic

6. 调用func f(arr[10] int)会拷贝数组。数组是值类型,赋值和传参会复制整个数组,而不是指针。因此改变副本的值,不会改变本身的值。

7.支持 "=="、"!=" 操作符,因为内存总是被初始化过的。

8.指针数组 [n]*T,数组指针 *[n]T。


数组截取

a[开始索引(包含), 结束索引(不不包含)]

a := [...]int{1, 2, 3, 4, 5}
a[1:2] //2
a[1:3] //2,3
a[1:len(a)] //2,3,4,5
a[1:] //2,3,4,5
a[:3] //1,2,3

用 == 比较数组

  1. 相同维数且含有相同个数元素的数组才可以⽐比较
  2. 每个元素都相同的才相等

位运算符--&^ 按位置零

1 &^ 0 -- 1
1 &^ 1 -- 0
0 &^ 1 -- 0
0 &^ 0 -- 0

切片Slice

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

Slice本身没有数据,是对底层array的一个view

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

  • 6. 如果 slice == nil,那么 len、cap 结果都等于 0

切⽚片共享存储结构

append超出原 slice.cap 限制,就会重新分配底层数组,即便原数组并未填满

package main
import (
  "fmt"
  "testing"
)
func TestEmptyInterfaceAssertion(t *testing.T) {
  // 10: 0 使用冒号初始化元素--表示第10个位置值为0
  data := [...]int{0, 1, 2, 3, 4, 10: 0}
  // 
  s := data[:2:3]
  fmt.Println(s)
  s = append(s, 100, 200) // 一次 append 两个值,超出 s.cap 限制。
  fmt.Println(s, data)         // 重新分配底层数组,与原数组无关。
  fmt.Println(&s[0], &data[0]) // 比对底层数组起始指针。
}

输出结果:

[0 1]
[0 1 100 200] [0 1 2 3 4 0 0 0 0 0 0]
0xc000086060 0xc000056060

append可能会导致cap不足,需要重新分配内存。此时需要修改slice指向的内存地址,len,cap。

但是由于append没法修改原slice变量的属性,这就出现了矛盾:需要修改原输入参数,但有不能产生副作用。

golang的解决方法是强制规定append的返回值必须赋值给slice。算是解决了忘记赋值的问题,但是太丑陋了。

给slice提供一个append方法不是更简单直接吗?

数组 vs. 切片

  • 容量是否可伸缩
  • 是否可以进⾏比较


1 array

  • 类型相同, 长度固定的数据集合. 长度无法修改
  • 类型为: [len]T (len不能省略)
  • 值是一段连续的内存区域和一些额外属性

属性示例:

  • beg_addr 起始地址. 赋值时固定
  • len 长度. 赋值时固定
  • cap 保存实际长度. 赋值时固定,始终和len相同

要点:

  • 编译时需要确定长度. 需要显式指定长度, 或者使用...由编译器自动推断
  • go中都是值传递(pass by value). 因此赋值会复制数组本身.
  • 引用需要借助pointer


2 slice

  • 可以看作是内存的视图,展示内存的一段区域
  • 类型为: []T
  • 值是一个指向内存的数据结构, 类似指向数组的指针

属性示例:

  • array 底层数组
  • len 长度. 赋值(包括reslice)时设置
  • cap 从起始地址开始,最多可以展示的内存长度. = 底层数组结束地址-起始地址

要点:

  • 由于传递的是指针, 函数内可以修改外部slice指向的底层数组.  
  • 多个slice可以指向同一个底层数组.


目录
相关文章
|
1月前
|
Go 索引
Go 语言中同一 slice 上的切片其底层数组是否是同一个
Go 语言中同一 slice 上的切片其底层数组是否是同一个
24 0
|
1月前
|
存储 安全 编译器
掌握Go语言:探索Go语言中的变量,灵活性与可读性的完美结合(4)
掌握Go语言:探索Go语言中的变量,灵活性与可读性的完美结合(4)
|
12天前
|
Go
【Go语言专栏】Go语言的并发编程进阶:互斥锁与条件变量
【4月更文挑战第30天】本文探讨了Go语言中的互斥锁(Mutex)和条件变量(Condition Variable)在并发编程中的应用。互斥锁用于保护共享资源,防止多goroutine同时访问,通过Lock和Unlock进行控制,需注意避免死锁。条件变量则允许goroutine在条件满足时被唤醒,常与互斥锁结合使用以提高效率。了解和掌握这些同步原语能提升Go并发程序的性能和稳定性。进一步学习可参考Go官方文档和并发模式示例。
|
12天前
|
存储 Go 开发者
【Go语言专栏】Go语言中的变量、常量和数据类型
【4月更文挑战第30天】Go语言以其简洁、高效和并发性备受开发者喜爱。本文聚焦变量、常量和数据类型。变量声明可使用`var`或类型推断,如`var a int = 10`和`b := &quot;hello&quot;`。常量用`const`声明,不可变,如`const pi float64 = 3.1415926`。数据类型包括基本类型(数值、布尔、字符串)和复合类型(数组、切片、结构体、接口)。理解这些基础将助力开发者深入学习Go语言的高级特性。
|
15天前
|
数据可视化
R语言多元(多变量)GARCH :GO-GARCH、BEKK、DCC-GARCH和CCC-GARCH模型和可视化
R语言多元(多变量)GARCH :GO-GARCH、BEKK、DCC-GARCH和CCC-GARCH模型和可视化
|
19天前
|
Go C++ 容器
【Go语言快速上手(三)】数组, 切片与映射
【Go语言快速上手(三)】数组, 切片与映射
|
24天前
R语言多变量广义正交GARCH(GO-GARCH)模型对股市高维波动率时间序列拟合预测
R语言多变量广义正交GARCH(GO-GARCH)模型对股市高维波动率时间序列拟合预测
|
1月前
|
存储 Go 索引
掌握Go语言:深入理解Go语言中的数组和切片,灵活处理数据的利器(16)
掌握Go语言:深入理解Go语言中的数组和切片,灵活处理数据的利器(16)
|
1月前
|
存储 Go 索引
掌握Go语言:深入理解Go语言数组,基本原理与示例解析(15)
掌握Go语言:深入理解Go语言数组,基本原理与示例解析(15)
|
1月前
|
安全 编译器 Serverless
掌握Go语言:深入Go语言常量:代码稳定的关键(10)
掌握Go语言:深入Go语言常量:代码稳定的关键(10)