美文网首页深入浅出golangGoGolang 入门资料+笔记
golang快速入门[8.1]-变量类型、声明赋值、作用域声明周

golang快速入门[8.1]-变量类型、声明赋值、作用域声明周

作者: 唯识相链2 | 来源:发表于2020-03-18 20:32 被阅读0次

前文

题记

  • 在上一篇文章中,我们介绍了吸心大法—go module的技巧来引用第三方代码,但是看过武侠小说的同学都知道,只有内力没有招式那也是花架子。正所谓"巧妇难为无米之炊",我们将在后面几章巩固基本功,介绍go语言的语法、基本概念和性质。

前言

我们将在本文中学习到:

  • 变量的内涵

  • 变量的数据类型

  • 变量的多种声明与赋值

  • 变量的命名

  • 变量的作用域与示例

  • 变量的内存分配方式

变量是什么

  • 在计算机编程中,变量(Variable)是与关联的符号名配对的存储地址(内存地址标识)

  • 变量用于存储要在计算机程序中引用和操作的信息。变量还提供了一种使用描述性名称标记数据的方法,因此读者和开发人员都可以更清楚地理解程序。可以将将变量视为保存信息的空间。

  • 编译器必须用数据的实际地址替换变量的符号名。尽管变量的名称,类型和地址通常保持不变,但存储在地址中的数据可能会在程序执行期间发生更改。

变量的数据类型

go语言是静态类型的语言,需要在运行前明确变量的数据类型以及大小。如下图是静态语言与动态语言的区别。动态语言可以在运行时扩展变量的大小。

image
  • 数据类型是数据的属性,它告诉编译器打算如何使用数据

  • 大多数编程语言都支持基本数据类型,包括整数,浮点数,字符和布尔值等。数据类型定义了可以对数据执行的操作,数据的含义以及该类型值的存储方式

  • Go语言的数值类型包括几种不同大小的整数、浮点数和复数。每种数值类型都决定了对应的大小范围和是否支持正负符号。让我们先从整型数类型开始介绍

  • Go语言同时提供了有符号和无符号类型的整数运算,有int8、int16、int32和int64四种截然不同大小的有符号整型数类型,分别对应8、16、32、64bit大小的有符号整型数,与此对应的是uint8、uint16、uint32和uint64四种无符号整型数类型。

  • 还有两种一般对应特定CPU平台机器字大小的有符号和无符号整数int和uint。其中int是应用最广泛的数值类型。这两种类型都有同样的大小,32或64bit,但是我们不能对此做任何的假设;因为不同的编译器卽使在相同的硬件平台上可能产生不同的大小。

  • Unicode字符rune类型是和int32等价的类型,通常用于表示一个Unicode码点。这两个名称可以互换使用。同样byte也是uint8类型的等价类型,byte类型一般用于强调数值是一个原始的数据而不是一个小的整数。

  • 最后,还有一种无符号的整数类型uintptr,没有指定具体的bit大小但是足以容纳指针。uintptr类型只有在底层编程时才需要,特别是Go语言和C语言函数库或操作系统接口相交互的地方。在介绍指针时,会详细介绍它。

变量的声明与赋值

变量的声明使用var来标识,变量声明的通用格式如下:

var name type = expression
image
  • 函数体外部:变量声明方式1
var i int
  • 函数体外部:变量声明方式2
// 外部连续声明var U, V, W float64
  • 函数体外部:变量声明方式3
// 赋值不带类型,自动推断var k = 0
  • 函数体外部:变量声明方式4
// 外部连续声明+赋值var x, y float32 = -1, -2
  • 函数体外部:变量声明方式5
// 外部var括号内部var (    g       int    u, v, s = 2.0, 3.0, "bar")
  • 函数体内部:变量声明方式6
func main() {    //函数内部的变量声明  声明的变量类型必须使用 否则报错    var x string
  • 函数体内部:变量声明方式7
// 只限函数内部 自动推断类型y := "jonson"

变量的命名

  • 名字的长度没有逻辑限制,但是Go语言的风格是尽量使用短小的名字,对于局部变量尤其是这样;你会经常看到i之类的短名字,而不是冗长的theLoopIndex命名。通常来说,如果一个名字的作用域比较大,生命周期也比较长,那么用长的名字将会更有意义。

  • 在习惯上,Go语言程序员推荐使用 驼峰式 命名,当名字由几个单词组成时优先使用大小写分隔,而不是优先用下划线分隔。因此,在标准库有QuoteRuneToASCII和parseRequestLine这样的函数命名,但是一般不会用quote_rune_to_ASCII和parse_request_line这样的命名。而像ASCII和HTML这样的缩略词则避免使用大小写混合的写法,它们可能被称为htmlEscape、HTMLEscape或escapeHTML,但不会是escapeHtml。

作用域

  • 在程序设计中,一段程序代码中所用到的标识符并不总是有效/可用的,作用域就是标识符有效可用的代码范围。

  • 在go语言中,作用域可以分为

全局作用域 > 包级别作用域 > 文件级别作用域 > 函数作用域 > 内部作用域universe block > package block > file block > function block > inner block

全局作用域

  • 全局作用域主要是go语言预声明的标识符,所有go文件都可以使用。主要包含了如下的标识符
內建类型: int int8 int16 int32 int64          uint uint8 uint16 uint32 uint64 uintptr          float32 float64 complex128 complex64          bool byte rune string error內建常量: true false iota nil內建函數: make len cap new append copy close delete          complex real imag          panic recover

包级别作用域

  • 全局(任何函数之外)声明的常量,类型,变量或函数的标识符是包级别作用域

  • 如下例中的变量x 以及 fmt包中的函数println 就是包级别作用域

package mainimport "fmt"var x int=5func main(){    fmt.Println("mainx:",x)}
  • 调用例子1
// f1.gopackage mainvar x int//-------------------------------------// f2.gopackage mainfunc f() {  fmt.Println(x)}
  • 调用例子2:调用另一个包中的函数和属性:
//testdemo/destdemo.gopackage testdemoimport "fmt"var Birth uint = 23func Haha(){    fmt.Println("lalalal")}//-------------------------------------package main  // main/scope.goimport (    "testdemo"    "fmt")func main(){    testdemo.Haha()    fmt.Println(testdemo.Birth)}
  • 注意:如果要让包中的属性和变量被外部包调用,必须要首字母大写。

文件级别作用域

  • import包的标识符是文件级别作用域的,只能够在本文件中使用

  • 例如下面的代码无效,因为import 是file block,不能跨文件

// f1.gopackage mainimport "fmt"//-------------------------------------// f2.go  无效package mainfunc f() {  fmt.Println("Hello World")}

函数级别作用域

  • 方法接收者(后面介绍),函数参数和结果变量的标识符的范围是函数级别作用域,在函数体外部无效,在内部任何位置可见

  • 例如下面函数中的a,b,c就是函数级别作用域

func  add(a int,b int)(c int) {  fmt.Println("Hello World")  x := 5  fmt.Println(x)}

内部作用域

  • 函数声明的常量和变量是函数内部作用域,其作用域从声明开始,到最近的一个花括号结束。

  • 例子1:注意参数的前后顺序

//下面的代码无效:func main() {  fmt.Println("Hello World")  fmt.Println(x)    x := 5}
  • 例子2:参数不能跨函数使用
//下面的代码无效2:func main() {  fmt.Println("Hello World")  x := 5  fmt.Println(x)}//func test(){    fmt.Println(x)}
  • 例子3:函数内部变量与外部变量重名,使用就近原则
package mainimport "fmt"var x int=5func test(){    var x int = 99;    x = 100;    // 下面的代码输出结果为: 100    fmt.Println("testx",x)}
  • 例子4:内部花括号

  • 变量x的作用域是从scope3到scope5为止

func main() {    fmt.Println("Hello World")  // scope1    {                           // scope2        x := 5                  // scope3        fmt.Println(x)          // scope4    }                           // scope5}

变量的内存分配

我们在前文go语言是如何运行的-内存概述 与 go语言是如何运行的-内存分配 中,详细介绍了在虚拟内存角度其不同的及其功能

image
  • 对于全局变量,其存储在.data.bss段。我们可以用下面的实例来验证
// main.gopackage mainvar aaa int64 = 8var ddd int64func main() {}
  • 在终端中输入如下指令打印汇编代码
$ go tool compile -S main.go..."".aaa SNOPTRDATA size=8        0x0000 08 00 00 00 00 00 00 00"".ddd SNOPTRBSS size=8...
  • 从上面的汇编输出中可以看出, 变量aaa位于 .data段中, 变量ddd位于.bss

  • 对于函数的内部变量,在go语言的编程规范中并没有明确的划分,变量是分配在栈中还是堆中,简单来说,Go语言的逃逸分析(escape analysis)会分析各个变量的使用状况,来决定他要放在stack还是heap段。

  • 一般的变量会在运行时在栈中创建,随着函数的调用而产生,随着函数的结束而消亡。如果编译器无法证明函数返回后未引用该变量,则编译器必须在堆上分配该变量,以避免悬空指针错误。另外,如果局部变量很大,则将其存储在堆而不是堆栈上可能更有意义

  • 有一些初始化的情况会被分配到.data段中,例如长度大于4的数组字面量、字符串 等,如下所示

func main() {    var vvv  = [5]int{1,2,3,4,5}    var bbb string = "hello"}
  • 在终端中输入如下指令打印汇编代码 即可验证其存在于.data段中
$ go tool compile -S main.go...go.string."hello" SRODATA dupok size=5    0x0000 68 65 6c 6c 6f                                   hellotype.[5]int SRODATA dupok size=72"".ddd SNOPTRBSS size=8...

总结

参考资料

  • 项目链接

  • 作者知乎

  • blog

  • Variables

  • stack_or_heap
    喜欢本文的朋友欢迎点赞分享~

image

唯识相链启用微信交流群(Go与区块链技术)

欢迎加微信:ywj2271840211

相关文章

  • golang快速入门[8.1]-变量类型、声明赋值、作用域声明周

    前文 golang快速入门[1]-go语言导论 golang快速入门[2.1]-go语言开发环境配置-window...

  • JavaScript的变量

    命名 声明 先声明,后读写先赋值,后运算 变量类型 作用域

  • 3.变量

    1.变量必须初始化赋值 2.变量的作用域:在类型级别声明的变量看做字段,而在方法中声明的变量看作局部变量

  • vue常用的ES6语法--let和const

    作用:用来声明变量和常量 const声明的变量必须赋值1、作用域只局限于当前代码块 2、使用let和const声明...

  • js的提升

    JavaScript 会将函数声明和变量声明提升到当前作用域的顶部。变量赋值不会提升。在脚本的顶部声明函数和变量,...

  • 变量的查缺补漏

    显示声明和隐式声明 用 var 声明的变量是显示声明,只在当前作用域有效,例如: 直接赋值给一个变量则是隐式声明,...

  • js变量提升

    函数声明 和 var 声明的变量 都会提升到该作用域的顶部。不同的是 var 声明的变量只提升了声明,赋值并没有...

  • 5.Go语言变量的基本用法

    变量的声明与赋值 单个变量的声明与赋值声明格式:var <变量名称> <变量类型>赋值格式:<变量名称> = <表...

  • ES6基础语法整理

    1. 声明变量let和const let声明的变量引入了块级作用域 const声明的常量不允许重新赋值 2. 箭头...

  • ES6新增常用语法

    一、新的变量声明方式 1、let 使用let声明的变量可以重新赋值,但是不能在同一作用域内重新声明,常用来声明一个...

网友评论

    本文标题:golang快速入门[8.1]-变量类型、声明赋值、作用域声明周

    本文链接:https://www.haomeiwen.com/subject/uiacyhtx.html