热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

【Go】变量与数据类型

文章目录变量变量声明的方式变量使用的注意事项声明全局变量的坑数据类型整型类型的说明整型类型的使用细节浮点类型的说明浮点类型的使用细节字符类型的说明转义字符字符类型的使用细节布尔类型字符串类型的说明字符

文章目录

    • 变量
      • 变量声明的方式
      • 变量使用的注意事项
      • 声明全局变量的坑
    • 数据类型
      • 整型类型的说明
      • 整型类型的使用细节
      • 浮点类型的说明
      • 浮点类型的使用细节
      • 字符类型的说明
      • 转义字符
      • 字符类型的使用细节
      • 布尔类型
      • 字符串类型的说明
      • 字符串类型的使用细节
    • 基本数据类型的默认值
    • 常用格式化动作
    • 类型转换
      • 数字类型之间的相互转换
      • 数字或布尔转字符串
      • 字符串转数字或布尔


变量


变量表示内存中的一个存储区域,该区域有自己的名称(变量名)和类型(数据类型)。


变量声明的方式


  1. 指定变量类型。声明后若不赋值,则使用指定数据类型的默认值

package mainimport "fmt"func main() {var num intfmt.Println("num =", num)
}

结果:num = 0
int数据类型的默认值是0,其他的稍后介绍

  1. 根据初值自行判定变量类型(类型推导)

package mainimport "fmt"func main() {var num = 10.1fmt.Println("num =", num)
}

结果:num = 10.1

  1. 省略var关键字,用:=声明并赋初值

package mainimport "fmt"func main() {num := 10fmt.Println("num =", num)
}

结果:num = 10

  1. 局部多变量声明

package mainimport "fmt"func main() {// 一次声明多个变量var n1, n2, n3 intfmt.Println("n1 =", n1, "n2 =", n2, "n3 =", n3)// 一次声明多个变量并赋初值var a, name, b = 100, "张三", 300fmt.Println("a =", a, "name =", name, "b =", b)// 简写i, j := 10, 20fmt.Println("i =", i, "j =", j)
}

结果:

n1 = 0 n2 = 0 n3 = 0
a = 100 name = 张三 b = 300
i = 10 j = 20

  1. 全局多变量声明

package mainimport "fmt"// 一次声明多个全局变量
var (a = 100b = 200name = "李四"
)func main() {fmt.Println("a =", a, "b =", b, "name =", name)
}

结果:a = 100 b = 200 name = 李四

变量使用的注意事项


  • 变量的值可以在同一类型范围内不断变化
  • 变量在同一作用域内不能重名
  • 变量的三要素:变量名、变量值、数据类型
  • Go中的变量如果没有赋初值,编译器会使用默认值。比如int型默认值为0,string型默认值为空串

声明全局变量的坑


我们可以在函数内部使用变量声明的简写方式,比如a := 10,但这条语句不能写在函数外部,也就是全局,因为这条语句相当于两条语句:var a inta = 10,而在全局中是不允许有赋值语句的。


数据类型


Go的数据类型分为基本数据类型派生/复杂数据类型


  • 基本数据类型:
    • bool
    • string
    • intint8int16int32int64
    • uintuint8uint16uint32uint64uintptr
    • byte(uint8的别名)
    • rune(int32的别名,表示一个Unicode码点)
    • float32float64
    • complex64complex128
  • 派生/复杂数据类型:
    • 指针pointer
    • 数组array
    • 结构体struct
    • 管道channel
    • 函数function
    • 切片slice
    • 接口interface
    • map

整型类型的说明


类型有无符号占用存储空间表示范围备注
int81字节-128 ~ 127
int162字节-215 ~ 215-1
int324字节-231 ~ 231-1
int648字节-263 ~ 263-1
uint81字节0 ~ 255
uint162字节0 ~ 216-1
uint324字节0 ~ 232-1
uint648字节0 ~ 264-1
int32位系统占4个字节,64位系统占8个字节-231 ~ 231-1,-263 ~ 263-1默认
uint32位系统占4个字节,64位系统占8个字节0 ~ 232-1,0 ~ 264-1
runeint32一样-231 ~ 231-1等价int32,表示一个Unicode
byteuint8一样0 ~ 255当要存储字符时选用byte

整型类型的使用细节


  • 整型分为有符号和无符号两种,intuint的大小与系统有关
  • 当我们声明了一个变量且给变量赋了一个数字,但是我们没有确定它的类型,此时这个变量默认为int

package mainimport "fmt"func main() {var a = 200// fmt.Printf用来做格式化输出// %T表示类型fmt.Printf("变量a的类型为%T", a)// 结果:// 变量a的类型为int
}

  • 查看某个变量的数据类型和其所占内存大小

package main// 一次导入多个包
import ("fmt""unsafe"
)func main() {var a = 200fmt.Printf("变量a的类型为%T\n", a)// unsafe.Sizeof用来获取变量所占内存大小,单位:字节fmt.Printf("变量a所占内存大小为%d个字节", unsafe.Sizeof(a))// 结果:// 变量a的类型为int// 变量a所占内存大小为8个字节
}

  • 在定义整型变量时,遵循保小不保大的原则,即:在保证程序正确运行的情况下,尽量使用占用空间小的数据类型,比如【年龄】

package mainimport "fmt"func main() {// byte表示范围:0~255var age byte = 20fmt.Printf("年龄是%d岁", age)// 年龄是20岁
}

浮点类型的说明


类型占用存储空间表示范围备注
float324字节-3.403E38 ~ 3.403E38
float648字节-1.798E308 ~ 1.798E308默认

浮点类型的使用细节


  • 浮点型有固定的范围和字段长度,不受操作系统的影响
  • 浮点型默认声明为float64
  • 浮点型常量有两种表示形式:十进制数表示、科学计数法表示

package mainimport "fmt"func main() {// 十进制数表示var a = 0.1var b = .2 // 小数点不能少// 科学计数法表示var c = 0.0314e2var d = 314e-2fmt.Println(a) // 0.1fmt.Println(b) // 0.2fmt.Println(c) // 3.14fmt.Println(d) // 3.14
}

  • 浮点数在机器中的存放形式:浮点数=符号位+指数位+尾数位,这说明浮点数都是有符号的
  • 尾数部分可能丢失,从而造成精度损失

package mainimport "fmt"func main() {var a float32 = -1.00000019var b float64 = -1.00000019 //这里的'float64'应该省略,因为它是默认的fmt.Println(a)//-1.0000002fmt.Println(b)//-1.00000019
}

  • 通常情况下,我们应该使用float64,因为它比float32更精确

字符类型的说明


Go语言中没有专门的字符类型,如果要存储单个字符(字母),一般使用byte来保存。

案例演示:

package mainimport "fmt"func main() {var c1 = '我' // 相当于 var c1 rune = '我',这里最好省略'rune'var c2 = '爱' // 相当于 var c2 int32 = '爱',这里最好省略'int32'var c3 = '你'fmt.Printf("%c%c%c", c1, c2, c3) // 我爱你fmt.Println(c1, c2, c3) // 25105 29233 20320fmt.Printf("%T", c1) // int32
}

对上述代码的说明:

  • 如果我们保存的字符在ASCII表中,则可以直接用byte类型来保存
  • 如果我们保存的字符对应的UTF-8码值大于255,这时我们可以考虑使用rune类型来保存
  • 如果我们想按照字符的方式输出,则需要用到格式化输出fmt.Printf("%c", c)

转义字符


转义字符说明
\t制表符
\n换行符(光标换到下一行)
\\表示一个\
\"表示一个"
\r回车符(光标回到本行行首)

字符类型的使用细节


  • 字符常量是用单引号''引起来的单个字符
  • Go中允许使用转义字符\?来将其后的字符转变成特殊的字符常量
  • Go语言的字符使用的是UTF-8编码,在UTF-8编码中,英文字母占1字节,汉字占3字节
  • 在Go中,字符的本质是一个整数,直接输出时,输出的是该字符对应的UTF-8编码的码值
  • 可以直接给某个变量赋一个数字,然后用%c按格式化输出,就会输出该数字对应的Unicode字符

package mainimport "fmt"func main() {var c1 = 20013var c2 = 22269fmt.Printf("%c%c", c1, c2) // 中国
}

  • 字符类型是可以进行运算的,相当于整数的运算

package mainimport "fmt"func main() {var c1 = '中'var c2 = '国'fmt.Println(c1 + c2) // 42282
}

  • Go语言的编码都统一成了UTF-8,非常地方便,再也没有乱码的困扰了

布尔类型


  • 布尔类型也叫bool类型,布尔类型的数据只能取truefalse
  • bool类型占1个字节
  • bool类型适用于逻辑运算,一般用于程序流程控制

案例演示:

package mainimport ("fmt""unsafe"
)func main() {var bo = truefmt.Println("变量bo占", unsafe.Sizeof(bo), "字节")// 变量bo占 1 字节
}

字符串类型的说明


字符串就是一串固定长度的字符连接起来的字符序列。Go的字符串是由单个字节连接起来的,也就是说对于传统的字符串是由字符组成的,而Go的字符串不同,它是由字节组成的。Go的字符串的字节使用UTF-8编码表示Unicode文本。

案例演示:

package mainimport ("fmt""unsafe"
)func main() {var str string = "你好,世界" // string类型可以省略fmt.Println(str)fmt.Printf("string类型占%d个字节", unsafe.Sizeof(str))/*结果:你好,世界string类型占16个字节*/
}

字符串类型的使用细节


  • 不可以通过下标来修改字符串中的某一个字符,但可以通过下标来读取单个字节,读取中文时结果为乱码,因为一个汉字在UTF-8编码中占3个字节
  • string类型占16个字节
  • 字符串有两种表示形式:双引号""(会识别转义字符)、反引号``(以字符串的原生形式输出,包括特殊字符,可以实现防止攻击、输出源代码等效果)

package mainimport "fmt"func main() {var str = `
func main() {var str = "你好,世界"fmt.Println(str)
}`
fmt.Println(str)
}

结果:

func main() { var str = "你好,世界"fmt.Println(str)
}

  • 字符串拼接时,如果字符串太长,而我们想换行再拼接,此时需要注意拼接的+号必须在上面,原因是Go会为每一行结尾处加上分号,遇到+号就不会给它加分号

package mainimport "fmt"func main() {var str = "你好呀," + "今天过的" + "怎么样," + "有没有学习呢?\n" +"今天过的不错," + "学习也搞了。"fmt.Println(str)
}

结果:

你好呀,今天过的怎么样,有没有学习呢?
今天过的不错,学习也搞了。

基本数据类型的默认值


数据类型默认值
整型0
浮点型0
字符串“”
布尔型false

package mainimport "fmt"func main() {var n int // 整型var c byte // 整型var num float64var bo boolvar str string// %v表示按照变量的原值输出fmt.Printf("n=%v,c=%v,num=%v,bo=%v,str=%v", n, c, num, bo, str)// n=0,c=0,num=0,bo=false,str=
}

常用格式化动作

package fmt

类型转换


数字类型之间的相互转换


Go和Java/C不同,Go在不同类型的变量之间赋值时需要强制类型转换,Go没有自动类型转换。


  • 基本语法type(variable)type表示类型;variable表示变量
  • 功能:将指定变量的转换为指定类型

package mainimport "fmt"func main() {var n1 int32 = 10var n2 = int8(n1)fmt.Printf("n2的类型为%T", n2)// n2的类型为int8
}

  • 在类型转换时,既可以将表示范围小的数据转换为表示范围大的,也可以将大的转换为小的
  • 被转换的是变量存储的值,而不是转换变量本身的数据类型
  • 当我们将范围大的数据转换为小的时,编译不会报错,只是转换的结果按溢出处理,转换后会直接去除溢出的位数,只保留指定类型的位数

package mainimport "fmt"func main() {var n1 int32 = 258 // 二进制表示:1 0000 0010var n2 = int8(n1) // 转换后:0000 0010fmt.Println(n2) // 2
}

  • Go不允许给变量[赋值或运算的值]大于变量数据类型本身的范围,否则编译器会报错

package mainimport "fmt"func main() {var n1 int32 = 10var n2, n3 int8n2 = int8(n1) + 127 // 编译能通过n3 = int8(n1) + 128 // 报错:无法将常量 128 转换为类型 int8fmt.Println(n2, n3)
}

数字或布尔转字符串


  • 方式一:func Sprintf(format string, a ...interface{}) string
    Sprintf根据format参数生成格式化的字符串并返回该字符串

package mainimport "fmt"func main() {num1 := 10num2 := 10.5c := 'G'b := truevar str stringstr = fmt.Sprintf("%d", num1)fmt.Printf("str的值为字符串%q\n", str)str = fmt.Sprintf("%f", num2)fmt.Printf("str的值为字符串%q\n", str)str = fmt.Sprintf("%c", c)fmt.Printf("str的值为字符串%q\n", str)str = fmt.Sprintf("%t", b)fmt.Printf("str的值为字符串%q\n", str)
}/*结果:
str的值为字符串"10"
str的值为字符串"10.500000"
str的值为字符串"G"
str的值为字符串"true"
*/

  • 方式二:使用strconv包的函数

package mainimport ("fmt""strconv"
)func main() {num1 := 10num2 := 10.5b := truevar str stringstr = strconv.FormatInt(int64(num1), 10)fmt.Printf("str的值为字符串%q\n", str)// 'f'格式6:表示小数位保留6位// 64:表示这个小数是float64str = strconv.FormatFloat(num2, 'f', 6, 64)fmt.Printf("str的值为字符串%q\n", str)str = strconv.FormatBool(b)fmt.Printf("str的值为字符串%q\n", str)
}/*结果:
str的值为字符串"10"
str的值为字符串"10.500000"
str的值为字符串"true"
*/

  • 补充:func Itoa(i int) string,Itoa是FormatInt(i, 10) 的简写

package mainimport ("fmt""strconv"
)func main() {num := 100var str stringstr = strconv.Itoa(num)fmt.Printf("str的值为字符串%q", str)// str的值为字符串"100"
}

字符串转数字或布尔


  • 使用strconv包的函数

package mainimport ("fmt""strconv"
)func main() {str1 := "10"var num1 int64// ParseInt函数返回两个值(i int64, err error)// 第一个值才是我们想要的,但它是int64,所以我们声明num时只能指定类型为int64// 下面这种写法表示num接受第一个返回值,然后用'_'忽略第二个返回值num1, _ = strconv.ParseInt(str1, 10, 64)fmt.Printf("num1的值为%v\n", num1) // num1的值为10// ParseFloat函数返回两个值(f float64, err error)str2 := "10.5"var num2 float64num2, _ = strconv.ParseFloat(str2, 64)fmt.Printf("num2的值为%v\n", num2) // num2的值为10.5// ParseBool函数返回两个值(value bool, err error)str3 := "true"var bo boolbo, _ = strconv.ParseBool(str3)fmt.Printf("bo的值为%v\n", bo) // bo的值为true
}

  • 字符串转数字或布尔时需要注意:要确保字符串的值转换后依然是有效的数据,比如我们可以把字符串"123"转换成一个整数,但是我们不能把字符串"hello"转换成整数,如果硬是要转,Go会直接将其转换成目标类型的默认值

package mainimport ("fmt""strconv"
)func main() {str := "hello"var num int64 = 100num, _ = strconv.ParseInt(str, 10, 64)fmt.Printf("num的值为%v\n", num) // num的值为0var bo = truebo, _ = strconv.ParseBool(str)fmt.Printf("bo的值为%v\n", bo) // bo的值为false
}


推荐阅读
  • 先看官方文档TheJavaTutorialshavebeenwrittenforJDK8.Examplesandpracticesdescribedinthispagedontta ... [详细]
  • c语言\n不换行,c语言printf不换行
    本文目录一览:1、C语言不换行输入2、c语言的 ... [详细]
  • C++字符字符串处理及字符集编码方案
    本文介绍了C++中字符字符串处理的问题,并详细解释了字符集编码方案,包括UNICODE、Windows apps采用的UTF-16编码、ASCII、SBCS和DBCS编码方案。同时说明了ANSI C标准和Windows中的字符/字符串数据类型实现。文章还提到了在编译时需要定义UNICODE宏以支持unicode编码,否则将使用windows code page编译。最后,给出了相关的头文件和数据类型定义。 ... [详细]
  • Java中包装类的设计原因以及操作方法
    本文主要介绍了Java中设计包装类的原因以及操作方法。在Java中,除了对象类型,还有八大基本类型,为了将基本类型转换成对象,Java引入了包装类。文章通过介绍包装类的定义和实现,解答了为什么需要包装类的问题,并提供了简单易用的操作方法。通过本文的学习,读者可以更好地理解和应用Java中的包装类。 ... [详细]
  • Java SE从入门到放弃(三)的逻辑运算符详解
    本文详细介绍了Java SE中的逻辑运算符,包括逻辑运算符的操作和运算结果,以及与运算符的不同之处。通过代码演示,展示了逻辑运算符的使用方法和注意事项。文章以Java SE从入门到放弃(三)为背景,对逻辑运算符进行了深入的解析。 ... [详细]
  • 本文整理了315道Python基础题目及答案,帮助读者检验学习成果。文章介绍了学习Python的途径、Python与其他编程语言的对比、解释型和编译型编程语言的简述、Python解释器的种类和特点、位和字节的关系、以及至少5个PEP8规范。对于想要检验自己学习成果的读者,这些题目将是一个不错的选择。请注意,答案在视频中,本文不提供答案。 ... [详细]
  • 本文介绍了在go语言中利用(*interface{})(nil)传递参数类型的原理及应用。通过分析Martini框架中的injector类型的声明,解释了values映射表的作用以及parent Injector的含义。同时,讨论了该技术在实际开发中的应用场景。 ... [详细]
  • 深入理解Java虚拟机的并发编程与性能优化
    本文主要介绍了Java内存模型与线程的相关概念,探讨了并发编程在服务端应用中的重要性。同时,介绍了Java语言和虚拟机提供的工具,帮助开发人员处理并发方面的问题,提高程序的并发能力和性能优化。文章指出,充分利用计算机处理器的能力和协调线程之间的并发操作是提高服务端程序性能的关键。 ... [详细]
  • 本文介绍了使用kotlin实现动画效果的方法,包括上下移动、放大缩小、旋转等功能。通过代码示例演示了如何使用ObjectAnimator和AnimatorSet来实现动画效果,并提供了实现抖动效果的代码。同时还介绍了如何使用translationY和translationX来实现上下和左右移动的效果。最后还提供了一个anim_small.xml文件的代码示例,可以用来实现放大缩小的效果。 ... [详细]
  • 本文讨论了clone的fork与pthread_create创建线程的不同之处。进程是一个指令执行流及其执行环境,其执行环境是一个系统资源的集合。在调用系统调用fork创建一个进程时,子进程只是完全复制父进程的资源,这样得到的子进程独立于父进程,具有良好的并发性。但是二者之间的通讯需要通过专门的通讯机制,另外通过fork创建子进程系统开销很大。因此,在某些情况下,使用clone或pthread_create创建线程可能更加高效。 ... [详细]
  • MATLAB函数重名问题解决方法及数据导入导出操作详解
    本文介绍了解决MATLAB函数重名的方法,并详细讲解了数据导入和导出的操作。包括使用菜单导入数据、在工作区直接新建变量、粘贴数据到.m文件或.txt文件并用load命令调用、使用save命令导出数据等方法。同时还介绍了使用dlmread函数调用数据的方法。通过本文的内容,读者可以更好地处理MATLAB中的函数重名问题,并掌握数据导入导出的各种操作。 ... [详细]
  • 超级简单加解密工具的方案和功能
    本文介绍了一个超级简单的加解密工具的方案和功能。该工具可以读取文件头,并根据特定长度进行加密,加密后将加密部分写入源文件。同时,该工具也支持解密操作。加密和解密过程是可逆的。本文还提到了一些相关的功能和使用方法,并给出了Python代码示例。 ... [详细]
  • 使用C++编写程序实现增加或删除桌面的右键列表项
    本文介绍了使用C++编写程序实现增加或删除桌面的右键列表项的方法。首先通过操作注册表来实现增加或删除右键列表项的目的,然后使用管理注册表的函数来编写程序。文章详细介绍了使用的五种函数:RegCreateKey、RegSetValueEx、RegOpenKeyEx、RegDeleteKey和RegCloseKey,并给出了增加一项的函数写法。通过本文的方法,可以方便地自定义桌面的右键列表项。 ... [详细]
  • 本文介绍了在C#中SByte类型的GetHashCode方法,该方法用于获取当前SByte实例的HashCode。给出了该方法的语法和返回值,并提供了一个示例程序演示了该方法的使用。 ... [详细]
  • 本文介绍了如何使用go语言实现一个一对一的聊天服务器和客户端,包括服务器开启、等待客户端连接、关闭连接等操作。同时提供了一个相关的多人聊天的链接供参考。 ... [详细]
author-avatar
cfn7831325
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有