admin管理员组文章数量:1794759
[GO语言基础] 三.变量声明、数据类型、标识符及编程练习12题
作为网络安全初学者,会遇到采用Go语言开发的恶意样本。因此从今天开始从零讲解Golang编程语言,一方面是督促自己不断前行且学习新知识;另一方面是分享与读者,希望大家一起进步。前文介绍了Go的编译运行、语法规范、注释转义及API标准库知识;这篇文章将介绍Golang的变量、数据类型和标识符知识,并通过12道编程练习进行提升。 这系列文章入门部分将参考“尚硅谷”韩顺平老师的视频和书籍《GO高级编程》,详见参考文献,并结合作者多年的编程经验进行学习和丰富,且看且珍惜吧!后续会结合网络安全进行GO语言实战深入,加油~
这些年我学过各种编程语言,从最早的C语言到C++,再到C#、PHP、JAVA,再到IOS开发、Python,到最新的GO语言,学得是真的杂。有时候觉得编程语言恰恰是最简单的,而通过一门编程语言能够解决实际问题或深入底层才是其价值所在,并且当我们学好一门编程语言后,其他编程语言都非常类似,殊途同归,学起来也很迅速。
源码下载地址:
- github/eastmountyxz/Go-learning
前文参考:
- [GO语言基础] 一.为什么我要学习Golang以及GO语言入门普及
- [GO语言基础] 二.编译运行、语法规范、注释转义及API标准库知识普及
- [GO语言基础] 三.变量声明、数据类型、标识符及编程练习12题
- 一.变量
- 1.什么是变量
- 2.变量的声明
- 3.变量的注意事项
- 二.数据类型
- 1.整型
- 2.浮点型
- 3.字符类型
- 4.布尔型
- 5.字符串类型
- 6.基本数据类型的默认值
- 7.基本数据类型转换
- 8.基本数据类型和string转换
- 三.指针
- 1.基本介绍
- 2.指针类型
- 3.获取指针类型所指向的值
- 4.指针修改值
- 5.值类型和引用类型
- 四.标识符和关键字
- 1.标识符
- 2.关键字
- 五.GO编程练习
- 1.题目
- 2.解答
- 六.总结
一.变量 1.什么是变量
为什么需要变量呢? 一个程序就是一个世界,不论使用哪种高级程序语言编写代码,变量都是其程序的基本组成单位。如下图所示的sum和sub都是变量。
变量的定义: 变量相当于内存中一个数据存储空间的表示,可以将变量看作是一个房间的门牌号,通过门牌号能找到房间;通过变量名可以访问到变量的值。变量使用的常见三个步骤:
- 声明变量或定义变量
- 变量赋值
- 变量使用
变量入门示例: 变量表示内存中的一个存储区域,该区域有自己的变量名和数据类型。下面是一个简单案例:
package main import "fmt" func main() { //定义变量 var n int //赋值变量 n = 10 //使用变量 fmt.Println("n =", n) }2.变量的声明
Go语言变量使用的三种方式:
- (1) 指定变量类型,声明后若不复制,使用默认值,如int的默认值是0; var i int fmt.Println(“i =”, i)
- (2) 根据值自行判定变量类型(类型推导); var num = 3.14 fmt.Println(“num =”, num)
- (3) 省略var,=是赋值, :=是声明变量并赋值。注意 :=左侧变量不应该是已经声明过的,否则会编译错误 name := “eastmount” fmt.Println(“name =”, name) 等价于 var name string name = “eastmount”
输出结果如下图所示:
多变量声明: 在编程中,通常会遇到一次性声明多个变量的情况。Golang同样提供了对应的功能,如下所示:
- var n1, n2, n3 int
- var n1, name, n3 = 100, “csdn”, 3.14
- n1, name, n3 := 100, “csdn”, 3.14
代码如下,注意不要重复定义变量,否则会报错。
package main import "fmt" func main() { //方法一:指定变量类型 int默认值为0 var n1, n2, n3 int fmt.Println("n1 =", n1, "n2 =", n2, "n3 =", n3) //方法二:根据值自行判定变量类型 var m1, name, m3 = 100, "csdn", 3.14 fmt.Println("m1 =", m1, "name =", name, "m3 =", m3) //方法三:省略var :=声明变量并赋值 k1, k2, k3 := 100, "yxz", 3.14 fmt.Println("k1 =", k1, "k2 =", k2, "k3 =", k3) }输出结果如下图所示:
那么,如何一次性声明多个全局变量呢?
- 在Go中函数外部定义的变量就是全局变量
- 全局变量如果只定义不使用,不会报错
- 一次性声明
3.变量的注意事项
注意事项:
- 变量在某个区域的数据值可以在同一类型范围内不断变化,但不能改变数据类型(强类型转换)
- 变量在同一作用域(在一个函数或代码块)内不能重名
-
变量=变量名+值+数据类型,这一点大家需要注意,变量的三要素
-
Golang的变量如果没有赋初值, 编译器会使用默认值,比如int为0,string为空串等
变量知识总结:
- 声明变量 基本语法:var 变量名 数据类型 比如“var n int”表示声明一个变量,变量名为n;“var num float32”表示声明一个单精度小数类型的变量
- 初始化变量 在声明变量时赋初值,比如“var n int = 12”,如果声明时就直接赋值,可省略数据类型,比如“var m = 30”
- 变量赋值 先声明变量“var num int”,此时默认值为0,再给变量赋值“num=78”
加号用法:
- 当左右两边都是数值型是,做加法运算
- 当左右两边都是字符串,做字符串拼接
二.数据类型
每一种数据都定义了明确的数据类型,并在内存中分配不同大小的内存空间。常用的数据类型分为基本数据类型和派生/复杂数据类型。
- 基本数据类型 数值型(整型、浮点型)、字符型(单个字符)、布尔型、字符串(Go中归属为基本数据类型)、复数类型(complex64、complex128)、rune
- 派生/复杂数据类型 指针、数组、结构体、管道、函数、切片、接口、map
整数类型就是用于存放整数值,比如0、-2、23等。
(1) 整形的各个类型 注意,一个字节为8位(bit),计算机采用二进制(0或1),即2^8表数范围。
- 有符号的int8表示为-128 ~ 127。下图bit7为符号位,最大值为bit0至bit6均为1,故为 2 7 − 1 2^7-1 27−1,即127;由于存在+0和-0,因此将 -0位赋值给负数,因此最小值为-128。
- 无符号uint8表示为0 ~ 255。无符号最大值为bit0至bit7均为1,故为 2 8 − 1 2^8-1 28−1,即255。
int8 | 有 | 1字节 | − 128 ∼ 127 -128 \\sim 127 −128∼127 |
int16 | 有 | 2字节 | − 2 15 ∼ 2 15 − 1 - 2^{15} \\sim 2^{15}-1 −215∼215−1 |
int32 | 有 | 4字节 | − 2 31 ∼ 2 31 − 1 - 2^{31} \\sim 2^{31}-1 −231∼231−1 |
int64 | 有 | 8字节 | − 2 63 ∼ 2 63 − 1 - 2^{63} \\sim 2^{63}-1 −263∼263−1 |
案例如下:
package main import "fmt" func main() { var i int = 1 fmt.Println("i =", i) var j int8 = 127 fmt.Println("j =", j) }输出结果如下图所示:
(2) 无符号整形
uint8 | 无 | 1字节 | 0 ∼ 255 0 \\sim 255 0∼255 |
uint16 | 无 | 2字节 | 0 ∼ 2 16 − 1 0 \\sim 2^{16}-1 0∼216−1 |
uint32 | 无 | 4字节 | 0 ∼ 2 32 − 1 0 \\sim 2^{32}-1 0∼232−1 |
uint64 | 无 | 8字节 | 0 ∼ 2 64 − 1 0 \\sim 2^{64}-1 0∼264−1 |
案例如下,如果uint8赋值为256则会提示边界溢出“.\\type03_01.go:14:6: constant 256 overflows uint8”。
(3) 其他int类型
int | 有 | 32位系统4个字节64位系统8个字节 | − 2 31 ∼ 2 31 − 1 − 2 63 ∼ 2 63 − 1 - 2^{31} \\sim 2^{31}-1 \\\\ - 2^{63} \\sim 2^{63}-1 −231∼231−1−263∼263−1 |
uint | 无 | 32位系统4个字节64位系统8个字节 | 0 ∼ 2 32 − 1 0 ∼ 2 64 − 1 0 \\sim 2^{32}-1 \\\\ 0 \\sim 2^{64}-1 0∼232−10∼264−1 |
rune | 有 | 与int32等价,表示一个unicode码,常用处理中文 | − 2 31 ∼ 2 31 − 1 - 2^{31} \\sim 2^{31}-1 −231∼231−1 |
byte | 无 | 与uint8等价,存储字符选用 | 0 ∼ 255 0 \\sim 255 0∼255 |
案例如下:
package main import "fmt" func main() { var i int = -20 fmt.Println("i =", i) var j uint = 127 fmt.Println("j =", j) var k rune = 1024 fmt.Println("k =", k) var m byte = 255 fmt.Println("m =", m) }输出结果如下:
(4) 整形的注意事项
- Golang各证书类型分为有符号和无符号,int、uint的大小和系统有关
- Golang的整型默认声明为int型
- 查看某个变量的字节大小(unsafe.Sizeof)和数据类型(fmt.Printf->%T)
- Golang程序中整型变量使用时,遵守保小不保大的原则,即:在保证程序正确运行下,尽量使用占用空间小的数据类型,比如年龄
- bit是计算机中最小存储单位,byte是计算机中基本存储单元(1 byte=8 bit)
输出结果如下图所示:
2.浮点型
浮点型用于存放小数,比如3.14、-1.9等,两种类型如下(没有double类型)。
- 单精度float32:4字节
- 双精度float64:8字节
浮点数都是有符号的,浮点数在机器中存放形式为:
- 浮点数=符号位+指数位+尾数位
浮点数的尾数部分可能丢失,造成精度损失。
- float64的精度要比float32准确,如果我们要保存一个高精度数据,则应该选用float64;软件开发中也推荐使用float64
输出结果如下图所示,可以看到float32精度损失。
浮点数的注意事项
- Golang浮点类型包括float32和float64两种,不存在double类型
- Golang浮点类型有固定的范围和字段长度,不受具体操作系统的影响
- Golang的浮点型默认声明为float64类型
- 浮点型常量有两种表示 – 十进制数形式,如:3.14、.1234,必须有小数点 – 科学技术法形式,如:5.1234e2=5.12*10的2次方,5.12E-2=5.12/10的2次方
- 通常情况推荐使用float64,它比float32更精确
输出结果如下图所示:
3.字符类型
Golang中没有专门的字符类型,如果要存储单个字符(字母),一般使用 byte 来保存(ASCII码表)。注意,是单个字母,而汉字是3个字节。
字符串是一串固定长度的字符连接起来的字符序列。Go的字符串是由单个字节连接起来的,也就是说传统的字符串是由字符组成的,而Go的字符串不同,它是由字节组成的。
举个简单示例:
- 如果保存的字符在ASCII表中,比如 [0-9, a-z, A-Z, …] 直接可以保存到byte
- 如果保存的字符对应码值大于255,这是可以考虑使用int类型保存
- 如果需要按照字符的方式输出,这是需要格式化输出,即fmt.Printf("%c", num)
输出结果如下图所示,比如“杨”对应Unicode编码10进制为“26472”。由于ASCII码只能存储127个字符,英文字母和字符可以,但是中文字符或其他国家字符很多,故衍生出UTF-8其他编码方式。
字符型的注意事项
- 字符常量是用单引号(’)括起来的单个字符,例如var c1 byte=‘a’,var c2 int=‘中’
- Go中允许使用转义字符 \\’ 来讲其后的字符转变为特殊字符型常量,比如var c3 char = ‘\\n’,表示换行符
- Go语言的字符使用UTF-8编码,英文字母1个字节,汉字3个字节。如果想查询字对应的utf8编码,使用网址: – www.mytju/classcode/tools/encode_utf8.asp
- 在Go中,字符的本质是一个整数,直接输出时,是该符对应的UTF-8编码的码字
- 可以直接给某个变量赋一个数字,然后按格式化输出%c,会输出该数字对应的unicode字符
- 字符类型可以进行运算,相当于一个整数,因为它都对应有Unicode编码
输出结果如下图所示:
字符类型本质探讨
- 字符型存储到计算机中,需要将字符对应的码值(整数)找出来 – 存储:字符 -> 对应码值 -> 二进制 -> 存储 – 读取:二进制 -> 码值 -> 字符 -> 读取
- 字符和码值的对应关系是通过字符编码表决定的,事先规定好的
- Go语言的编码都统一成utf-8,从而解决各种乱码问题
4.布尔型
布尔(bool)类型数据只允许取值true和false,用于表示真和假。它仅占1个字节,常用于逻辑运算,适用于程序流程控制(后续详细介绍)。
- if条件控制语句
- for循环控制语句
下面举个简单的案例:
package main import "fmt" import "unsafe" func main() { //定义数据类型 var num = false fmt.Println("num =", num) //注意bool类型占用1个字节 只能取true或false fmt.Println("占用空间 =", unsafe.Sizeof(num)) }输出结果如下:
注意:Go语言中bool类型不可以使用0或非0的整数替代false或true,这和C语言不同。
5.字符串类型
字符串是一串固定长度的字符连接起来的字符序列。Go字符串是由单个字节连接起来的。Go语言的字符串的字节使用UTF-8编码标识Unicode文本。
package main import "fmt" func main() { //定义字符串类型 var name string = "我的名字叫Eastmount!" fmt.Println(name) }输出结果如下图所示:
字符串的注意事项
- Go语言字符串的字符使用UTF-8编码标识Unicode文本,这样Golang统一使用UTF-8编码,中文乱码问题不在困扰我们。编码问题一直是C语言、Java、Python2常见问题
- 字符串一旦被复制,字符串就不能修改,即Go中字符串是不可变的(原子性)
字符串两种表示形式
- 双引号:会识别转移字符
- 反引号:以字符串的原生形式输出,包括换行和特殊字符,可以实现防止攻击、输出源代码等效果
输出结果如下图所示:
字符串拼接
- var str = “hello” + “world”
- str += “yangxiuzhang”
当一行字符串太长时,需要使用到多行字符串,可以进行如下处理:
6.基本数据类型的默认值
在Golang中,数据类型都有一个默认值,当程序员没有赋初值时,它就会保留默认值(或零值)。常见默认值如下图所示:
举例如下:
7.基本数据类型转换
Golang和Java、C不同,Go在不同类型的变量之间赋值时需要显示转换。换句话说,Golang中数据类型不能自动转换。
强制转换基本语法
- 表达式 T(v) 将值 v 转换为类型 T
- T:数据类型,比如int32、int64、float64等
- v:需要转换的变量
输出结果如下图所示:
注意事项
- Go中数据类型的转换可以从表示范围小到表示范围大,也可以从范围大到范围小
- 被转换的是变量存储的数据(即值),变量本身的数据类型并没有变化
- 在转换中,比如将 int64 转换成 int8(-128到127),编译时不会报错,只是转换的结果按溢出处理,和期待的结果不一样。因此在转换时,需要考虑范围
- 数据类型不一致的运算错误,建议转换成相同的数据类型。
由于n3是int8类型,赋值语句含128所以编译不通过;而n4也是int8类型,但编译能通过,结果溢出处理。
8.基本数据类型和string转换
在程序开发中,经常将基本数据类型转换成string或将string转换成基本数据类型。
(1) 基本数据类型转换成string
- 方法1:fmt.Sprintf("%参数", 表达式) Sprintf根据format参数生成格式化的字符串并返回该字符串,参数需要和表达式的数据类型匹配。
代码如下:
package main import "fmt" func main() { //变量定义 var num1 int = 99 var num2 float64 = 3.14 var b bool = true var char byte = 'h' var str string //fmt.Sprintf转换 str = fmt.Sprintf("%d", num1) fmt.Printf("str type %T str=%q\\n", str, str) str = fmt.Sprintf("%f", num2) fmt.Printf("str type %T str=%q\\n", str, str) str = fmt.Sprintf("%t", b) fmt.Printf("str type %T str=%q\\n", str, str) str = fmt.Sprintf("%c", char) fmt.Printf("str type %T str=%q\\n", str, str) }输出结果如下图所示:
- 方法2:使用strconv包的函数 – func FormatBool(b bool) string – func FormatFloat(f float64, fmt byte, prec, bitSize int) string – func FormatInt(i int64, base int) string – func FormatUint(i uint64, base int) string – func Itoa(int(num))
输出结果如下图所示:
(2) string类型转基本数据类型 使用strconv包的函数:
- func ParseBool(str string) (value bool, err error)
- func ParseFloat(s string, bitSize int) (f float64, err error)
- func ParseInt(s string, base int, bitSize int) (i int64, err error)
- func ParseUint(s string, b int, bitSize int) (n uint64, err error)
需要说明,因为返回的是int64或float64,如希望得到int32、float32,则需要调用 int32(num)处理。
注意:在将String类型转换成基本数据类型时,要确保String类型能够转成有效的数据。比如把“123”转成一个整数,但不能把“hello”转成一个整数;如果这样Go直接将其转成0,其他类型也是同样的道理,float转成0、bool转成false。
三.指针 1.基本介绍
由于后续很多内容(如引用)都会涉及到指针,C语言中它也是一个难点,因此这里我们先介绍指针的基础知识,更好地帮助我们学习Golang。
对于基本数据类型来说,变量存的就是值,也叫值类型。获取变量的地址使用“&”,比如:
- var num int
- 获取num的地址是&num
输出结果:
i的地址= 0xc0000100a0 i的值= 102.指针类型
指针变量存的是一个地址,这个地址指向的空间存的才是值,比如:
- var ptr *int = &num
举例说明指针在内存的布局。
package main import "fmt" func main() { //基本数据类型在内存布局 var i int = 10 //i的地址 &i fmt.Println("i的地址=", &i) fmt.Println("i的值=", i) /* var ptr *int = &i 1.ptr是一个指针变量 2.ptr的类型是*int 3.ptr本身的值是&i */ var ptr *int = &i fmt.Printf("ptr=%v\\n", ptr) }输出结果如下图所示:
3.获取指针类型所指向的值
使用 * 实现,比如 var ptr int,使用ptr获取ptr指向的值。
package main import "fmt" func main() { //基本数据类型在内存布局 var i int = 10 //i的地址 &i fmt.Println("i的地址=", &i) fmt.Println("i的值=", i) /* var ptr *int = &i 1.ptr是一个指针变量 2.ptr的类型是*int 3.ptr本身的值是&i */ var ptr *int = &i fmt.Printf("ptr=%v\\n", ptr) //获取指针类型指向的值 fmt.Printf("ptr的地址=%v\\n", &ptr) fmt.Printf("ptr指向的值=%v\\n", *ptr) }输出结果如下所示:
- i的地址= 0xc0000100a0
- i的值= 10
- ptr=0xc0000100a0
- ptr的地址=0xc000006030
- ptr指向的值=10
举例说明:
4.指针修改值
编写一个程序,获取一个int变量num的地址并显示终端;再将num的地址赋值给指针ptr,通过ptr去修改num的值。
package main import "fmt" func main() { //基本数据类型 var num int = 10 fmt.Printf("num的地址=%v 原始值=%v\\n", &num, num) //指针 var ptr *int ptr = &num fmt.Printf("ptr的地址=%v 指向的值为=%v 自身=%v\\n", &ptr, *ptr, ptr) //修改值 *ptr = 666 fmt.Printf("num修改后的值=%v\\n", num) }输出结果如下图所示:
下面这三个练习也推荐大家尝试。
5.值类型和引用类型
(1) 值类型
- 值类型:有对应的指针类型,形式为“ *数据类型 ”,比如int对应的指针就是“*int”,float32对应的指针类型就是“*float32”,以此类推
- 值类型的基本数据类型包括:int、float、bool、string、数组和结构体struct
- 值类型:变量直接存储值,内存通常在栈中分配
(2) 引用类型
- 变量存储的一个地址,这个地址对应的空间才是真正存储数据(值),内存通常在堆上分配,当没有任何变量引用这个地址时,该地址对应的数据空间就成为一个垃圾空间,由GC来回收。 - 引用类型的基本数据类型包括:指针、slice切片、map、管道、interface等
内存的栈区和堆区示意图如下:
四.标识符和关键字 1.标识符
Golang对各种变量、方法和函数等命名时使用的字符序列称为标识符。凡是自己可以起名字的地方也都叫标识符。其命名规则如下:
- 由26个英文字母大小写、0-9、下划线(_)组成
- 数字不可以开头,比如正确的“var num int”、错误的“var 3num int”
- Golang中严格区分大小写,Name和name是两个不同的变量
- 标识符不能包含空格
- 下划线(_)本身在Go中是一个特殊的标识符,称为空标识符。可以代表任何其它的标识符,但是它对应的值会被忽略,所以仅能作为占位符使用,不能作为标识符使用
- 不能以系统保留关键字作为标识符(一共有25个),比如break、if等
标识符命名注意事项:
- 包名:保持package的名字和目录尽量保持一致,建议采取有意义的包名,不要和标准库冲突(大家可以去Go开源代码学习下包名)。
-
变量名、函数名、常量名建议采用驼峰法命名 比如:var stuName string = “csdn”,形如xxxYyyyZzzz…
-
如果变量名、函数名、常量名首字母大写,则可以被其他的包访问;如果首字母小写,则只能在本包中使用( 首字母大写是公开的,首字母小写是私有的 ),在Golang中没有public、private等关键字,这也是Go与其他语言的区别
举例说明,首先在utils.go中定义一个变量;然后在main.go中使用该变量。
untils.go
package model //定义一个变量 var HeroName string = "武松"main.go
package main import ( "fmt" //导入utils.go文件的变量或函数 引入该model包 "go_code/chapter03/datatype/model" ) func main() { //该区域的数据可以在同一类型范围内变化 var n int = 10 n = 30 n = 50 fmt.Println("n=", n) //使用utils.go的HeroName变量 包名.标志符 fmt.Println(model.HeroName) }输出结果如下图所示:
如果变量名定义时是小写“heroNam”则会报错
2.关键字
在Go中,为简化代码编译过程中对代码的解析,系统仅保留25个关键字,如下表所示:
除了保留关键字外,Go还提供了36个预定的标志符,包括基础数据类型和系统内嵌函数。
五.GO编程练习 1.题目
(1) 分别定义常见的数据类型(整型、浮点型、字符型、布尔型、字符串型)变量,输出对应结果并查看变量的空间大小、数据类型。
变量名称 数据类型 占用空间 对应的值 num1 int 8 -12 num2 uint8 1 127 num3 int64 8 12345 num4 float32 4 3.14 num5 float64 8 314.15 num6 int 8 26472 num7 bool 1 false num8 string 16 Eastmount(2) 判断数字9的奇偶性输出它是奇数或偶数。
num = 9 这是一个奇数(3) 有人用温度计测量出华氏法表示的温度(如69°F),先要求把它转换为以摄氏法表示的温度(如20°C),输入值为69。
华氏度 f= 69 摄氏度 c= 20.555555555555557 摄氏度取整 c= 20(4) 通过两种方法(调用函数和循环)实现计算字符串“Eastmount”长度。
The length of "Eastmount" is 9. E a s t m o u n t The length of "Eastmount" is 9.(5) 循环依次输出“East 秀璋”字符串的所有字符。
Unicode遍历字符串 Unicode: E 69 Unicode: a 97 Unicode: s 115 Unicode: t 116 Unicode: 32 Unicode: 秀 31168 Unicode: 璋 29835 utf-8遍历字符串 Unicode: E 69 Unicode: a 97 Unicode: s 115 Unicode: t 116 Unicode: 32 Unicode: ç 231 Unicode: § 167 Unicode: € 128 Unicode: ç 231 Unicode: ’ 146 Unicode: ‹ 139(6) 实现字符串循环拼接,将变量str拼接成“a”到“z”并输出。
abcdefghijklmnopqrstuvwxyz(7) 从键盘上输入整数、浮点数和字符,然后赋值给变量并输出结果。
Eastmount 28 60.2 我的名字是: Eastmount 我的年龄是: 28 我的体重是: 60.2(8) 任意输入一个字母,实现大小写自动转换输出。
请输入任意字母: A 对应的ASCII码值: 65 A => a 请输入任意字母: h 对应的ASCII码值: 104 h => H(9) 实现多种数据类型转换(int和float转换、float和string转换)。
a=100 int32, b=100 float32 c=3.14 float32, d=3 int32 e=3.14 float64, f=3.140000 string e=123.456 string, f=123.456 float64(10) 指针基本概念,定义变量i,然后指针ptr指向该值,输出对应值及地址。
i的地址= 0xc0000100a0 i的值= 10 ptr=0xc0000100a0 ptr的地址=0xc000006030 ptr指向的值=10(11) 编写一个程序,获取一个int变量num的地址并显示终端;再将num的地址赋值给指针ptr,通过ptr去修改num的值。
666 num的地址= 0xc0000100a0 num的值= 54 ptr的地址=0xc000006030 ptr指向的值=54 修改值后: num=512 0xc0000100a0 修改值后: ptr=512 0xc000006030(12) 输入a和b两个整数,调用指针按从大到小的顺序输出a和b。
20 88 a=88, b=20 max=88, min=20 //p1和p22.解答
注意:程序实现的方法由千万种,作者更多是提供一个场景让你独立思考,独立解决问题。希望你喜欢这些题目,不要觉得枯燥,很多题目后续都会结合实际项目及经验进行介绍。
(1) 分别定义常见的数据类型(整型、浮点型、字符型、布尔型、字符串型)变量,输出对应结果并查看变量的空间大小、数据类型。
- 查看某个变量的字节大小(unsafe.Sizeof)和数据类型(fmt.Printf->%T)
输出结果如下图所示:
(2) 判断数字9的奇偶性输出它是奇数或偶数。
package main import "fmt" func main() { var num int = 9 fmt.Println("num =", num) //判断奇偶性 if num % 2 == 0 { fmt.Println("这是一个偶数") } else { fmt.Println("这是一个奇数") } }输出结果如下图所示:
(3) 有人用温度计测量出华氏法表示的温度(如69°F),先要求把它转换为以摄氏法表示的温度(如20°C),输入值为69。
package main import "fmt" func main() { var f float64 var c float64 //温度转换 f = 69.0 c = (5.0 / 9) * (f - 32) fmt.Println("华氏度 f=", f) fmt.Println("摄氏度 c=", c) fmt.Println("摄氏度整数 c=", int64(c)) }输出结果如下图所示:
(4) 通过两种方法(调用函数和循环)实现计算字符串“Eastmount”长度。
package main import "fmt" func main() { var str string str = "Eastmount" //计算字符串长度 fmt.Printf("The length of \\"%s\\" is %d. \\n", str, len(str)) //循环计算字符串长度 var num int = 0 for _, s := range str { fmt.Printf("%c ", s) num += 1 } fmt.Printf("\\nThe length of \\"%s\\" is %d. \\n", str, num) }输出结果如下图所示:
注意,当字符串中包含多字节字符时,要用到标准库utf8中的RuneCountInString函数来获取字符串的长度。代码如下:
package main import ( "fmt" "unicode/utf8" ) func main() { //多字节字符 test := "Hello, 世界" fmt.Println("bytes =", len(test)) //bytes = 13 fmt.Println("runes =", utf8.RuneCountInString(test)) //runes = 9 }(5) 循环依次输出“East 秀璋”字符串的所有字符。
package main import "fmt" func main() { str := "East 秀璋" //方法1:Unicode遍历字符串 fmt.Printf("Unicode遍历字符串\\n") for _, s := range str { fmt.Printf("Unicode: %c %d\\n", s, s) } //方法2:utf-8遍历字符串 fmt.Printf("utf-8遍历字符串\\n") for i := 0; i < len(str); i++ { ch := str[i] fmt.Printf("Unicode: %c %d\\n", ch, ch) } }输出结果如下图所示:
(6) 实现字符串循环拼接,将变量str拼接成“a”到“z”并输出。
package main import "fmt" func main() { var str string var tt string var ch byte = 'a' for i := 0; i < 26; i++ { tt = fmt.Sprintf("%c", ch) str += tt ch += 1 } fmt.Println(str) }上述代码注意类型转换,输出结果如下图所示:
(7) 从键盘上输入整数、浮点数和字符,然后赋值给变量并输出结果。
- 第一种: fmt.Scan(地址列表) 参数传入地址列表。输入变量之间可以采用空格或者换行
- 第二种: fmt.Scanln(地址列表) 与Scan不同在于自带换行,因此输入变量间不能采用换行
- 第三种:fmt.Scanf(“格式化字符串”, 地址列表)格式化输入 限制固定的输入格式
输出结果如下图所示:
(8) 任意输入一个字母,实现大小写自动转换输出。
- A的ASCII码值为65,a的ASCII码值为97
输出结果如下图所示:
(9) 实现多种数据类型转换(int和float转换、float和string转换)。
package main import "fmt" import "strconv" func main() { //整型->浮点型 var a int32 = 100 var b float32 = float32(a) fmt.Printf("a=%v %T, b=%v %T\\n", a, a, b, b) //浮点型->整型 var c float32 = 3.14 var d int32 = int32(c) fmt.Printf("c=%v %T, d=%v %T\\n", c, c, d, d) //其他类型->string var e float64 = 3.14 var f string f = fmt.Sprintf("%f", e) fmt.Printf("e=%v %T, f=%v %T\\n", e, e, f, f) //string->其他类型 var g string = "123.456" var h float64 h, _ = strconv.ParseFloat(g, 64) fmt.Printf("e=%v %T, f=%v %T\\n", g, g, h, h) }输出结果如下图所示:
(10) 指针基本概念,定义变量i,然后指针ptr指向该值,输出对应值及地址。
package main import "fmt" func main() { //基本数据类型在内存布局 var i int = 10 //i的地址 &i fmt.Println("i的地址=", &i) fmt.Println("i的值=", i) /* var ptr *int = &i 1.ptr是一个指针变量 2.ptr的类型是*int 3.ptr本身的值是&i */ var ptr *int = &i fmt.Printf("ptr=%v\\n", ptr) //获取指针类型指向的值 fmt.Printf("ptr的地址=%v\\n", &ptr) fmt.Printf("ptr指向的值=%v\\n", *ptr) }输出结果如下图所示:
(11) 编写一个程序,获取一个int变量num的地址并显示终端;再将num的地址赋值给指针ptr,通过ptr去修改num的值。
package main import "fmt" func main() { //获取一个int变量num的地址并显示终端 var num int fmt.Scanf("%c", &num) fmt.Println("num的地址=", &num) fmt.Println("num的值=", num) //定义ptr指针变量 var ptr *int = &num fmt.Printf("ptr的地址=%v\\n", &ptr) fmt.Printf("ptr指向的值=%v\\n", *ptr) //通过ptr去修改num的值 *ptr = 512 fmt.Printf("修改值后: num=%d %v\\n", num, &num) fmt.Printf("修改值后: ptr=%d %v\\n", *ptr, &ptr) }输出结果如下图所示:
(12) 输入a和b两个整数,调用指针按从大到小的顺序输出a和b。
- 解题:用指针方法来处理,不交换整型变量的值,而是交换两个指针变量的值
输出结果如下图所示,但遗憾的是a和b值并没有交换,而p1确实指向较大值,p2指向较小值。
这与C语言也存在一些差异,C语言代码如下,请大家下来思考具体原因。
六.总结
写到这里,这篇基础性Golang文章介绍完毕,希望您喜欢!
- 一.变量 1.什么是变量 2.变量的声明 3.变量的注意事项
- 二.数据类型 1.整型 2.浮点型 3.字符类型 4.布尔型 5.字符串类型 6.基本数据类型的默认值 7.基本数据类型转换 8.基本数据类型和string转换
- 三.指针 1.基本介绍 2.指针类型 3.获取指针类型所指向的值 4.指针修改值 5.值类型和引用类型
- 四.标识符和关键字 1.标识符 2.关键字
- 五.GO编程练习 1.题目 2.解答
Go基本概念和数据类型了解后,后面的文章将详细介绍Go语言的运算、条件语句和循环语句知识,并结合案例进行普及。希望这篇基础性文章对您有帮助,写得不好的地方还请海涵。同时非常感谢参考文献中的大佬们的文章分享,尤其是韩顺平老师,深知自己很菜,得努力前行。也希望自己能深入下去,未来四年好好研究Go编程语言,做更多实际工程,写更好的文章,共勉!
源代码下载地址:
- github/eastmountyxz/Go-learning
2020年8月18新开的“娜璋AI安全之家”,主要围绕Python大数据分析、网络空间安全、人工智能、Web渗透及攻防技术进行讲解,同时分享论文的算法实现。娜璋之家会更加系统,并重构作者的所有文章,从零讲解Python和安全,写了近十年文章,真心想把自己所学所感所做分享出来,还请各位多多指教,真诚邀请您的关注!谢谢。
(By:娜璋AI之家 Eastmount 2021-01-31 星期天 夜于贵阳 blog.csdn/Eastmount)
参考文献:
- Go官网:golang/
- 韩老师视频:www.bilibili/video/BV1pt41127FZ
- www.runoob/go/go-tutorial.html
- Go中文网在线标准库文档:studygolang/pkgdoc
版权声明:本文标题:[GO语言基础] 三.变量声明、数据类型、标识符及编程练习12题 内容由林淑君副主任自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.xiehuijuan.com/baike/1686646057a90103.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论