3.你不知道的go语言控制语句
本篇前瞻
好的,现在你已经来到一个新的小结,在这里你将学习到go语言的重要内容,习得go 25个关键字中的12个:var, const, if, else, switch, case, default, fallthrough, for, break, goto, continue,即在顺序结构学习var,const,在分支结构中学习if, else, switch, case, default, fallthrough,在循环结构中学习for, break, goto, continue。另外你最好注册一个Leetcode账号.
Leetcode习题9
先让我们来看下一个来自leetcode的例子,这个是一个比较好的例子,里面包含了循环,分支,顺序并且包含了上一章中
题目描述
给你一个整数 x
,如果 x
是一个回文整数,返回 true
;否则,返回 false
。
回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。
题目分析
首先看到的是它的取值范围是int32
的范围,这个很重要,事实上我们还没有学过数组,使得在解题遇到困难,当前仅有的办法只能使用整形来完成这个题目,你可以看到如果x
为2147483647
,那么它的回文数是7463847412
,是的,在这种情况下2147483647
的反转数超过int32
的范围,但是我需要用int64
吗?先试试看。
代码编写
注意原题中已经提供了这个函数结构
func isPalindrome(x int) bool {
}
为了方便我们编写代码,我们需要知道本函数的输入是x
,输出是代表是否是回文数(是:true,否:false
),return
能返回输出。
解题方法就是负数必然不是回文数,对于非负整数,我们循环x64除10
,通过x64%10
获得最低位,并且把最低位当作最高位加入到px64
中,这样我们得到了x的反转过来的数
px64`,判断他们是否相等就可以了。
代码如下,提交通过了,我们花费了28ms
,仅仅击败12%
的人
func isPalindrome(x int) bool {
if (x < 0) {
return false
}
x64 := int64(x)
px64 := int64(0)
for x64 != 0 {
px64 = px64*10 + x64%10
x64 /= 10
}
return px64 == int64(x)
}
我们去掉int64
的强制转化,居然也通过了只花费4ms
,击败了97%
的人,这不可思议。
func isPalindrome(x int) bool {
if (x < 0) { //分支结构
return false
}
x64 := x //整形 顺序结构
px64 := 0
for x64 != 0 { //循环结构
px64 = px64*10 + x64%10 // 顺序结构
x64 /= 10
}
return px64 == x //布尔型
}
那么int32
也能通过吗? 将上述代码提交,不行,答案错误。
func isPalindrome(x int) bool {
if (x < 0) {
return false
}
x64 := int32(x)
px64 := int32(x)
for x64 != 0 {
px64 = px64*10 + x64%10
x64 /= 10
}
return px64 == int32(x)
}
那么利用这三次提交的结果,并结合2.go语言基础类型漫游的知识,我们还可以得出:
- 变量强制转化会耗时
- 编程中的变量的取值范围很重要
- Leetcode的判题系统是64位的
知识点归纳
1.控制结构:顺序结构,分支结构,循环机构
2.基本数据类型:整形,布尔型
控制结构
顺序结构(Sequence)
声明和赋值
在顺序结构中声明和赋值是很重要的
var可以声明一个变量,而const则声明一个常量
package main
import "fmt"
func main() {
var i1 int //声明变量,默认值为0
var i2 int = 1 //声明变量,初始化为1
i3 := 2 //这是最常用的声明和初始化手段
fmt.Println(i1, i2, i3)
i4 := i2 + i3 //使用运算表达式赋值
i3 *= i4 //使用运算表达式赋值
fmt.Println(i3, i4)
const ci1 int = 13 //声明常量,无法
fmt.Println(ci1)
}
输出:
0 1 2
6 3
13
这里仅仅举例了整形int的声明
算术运算符
++ | -- | |||
---|---|---|---|---|
自增1 | 自减1 | |||
+= | -= | *= | /= | %= |
自增 | 自减 | 自乘 | 自除 | 自模,取余 |
+ | - | * | / | % |
加法 | 减法 | 乘法 | 除法 | 模,取余 |
注意: 例如如3/2 在整型中是整除即3/2=1,在浮点型是3.0/2.0=1.5,模运算智能用于整数
位运算符
<< | >> | & | | | ^ |
---|---|---|---|---|
左移 | 右移 | 与 | 或 | 亦或 |
<<= | >>= | &= | |= | ^= |
自左移 | 自右移 | 自与 | 自或 | 自亦或 |
位运算符几乎我们这篇实用的编程用不到,但是这个概念也很重要,计算机底层事实上是这样工作的。
逻辑运算
&& | || | == | != | ! |
---|---|---|---|---|
与 | 或 | 相等 | 不等于 | 非 |
>= | <= | > | < | |
大于等于 | 小于等于 | 大于 | 小于 |
这些会在分支语句中大放异彩。
分支结构
if 语句
if 语句有if,if-else以及if-else if-else结构,如下所示:
package main
import "fmt"
func main() {
var input int
fmt.Printf("请输入分数:")
fmt.Scanf("%d", &input)
if input < 60 { //if
fmt.Println("1.不合格")
}
if input < 60 { //if-else
fmt.Println("2.不合格")
} else{
fmt.Println("2.合格")
}
if input < 60 {//if-else if-else
fmt.Println("3.不合格")
} else if input < 70 {
fmt.Println("3.合格")
} else if input < 85 {
fmt.Println("3.良好")
} else {
fmt.Println("3.优秀")
}
}
结果如下:
请输入分数:59
1.不合格
2.不合格
3.不合格
switch 语句
事实上switch 语句比if语句更为强大,在有多个分支时更为符合go语言的风格,完整代码如下:
package main
import "fmt"
func main() {
var i int
fmt.Printf("请输入分数:")
fmt.Scanf("%d\n", &i)
switch {
case i < 60: //单个逻辑表达式
fmt.Println("不合格")
case i < 70:
fmt.Println("合格")
case i < 85:
fmt.Println("良好")
default:
fmt.Println("优秀")
}
var c byte
fmt.Printf("请输入等级:")
fmt.Scanf("%c\n", &c)
switch c {
case 'E', 'e': //可以有多个选择
fmt.Println("1.不合格")
case 'D', 'd':
fmt.Println("1.基本合格")
case 'C', 'c':
fmt.Println("1.合格")
case 'B', 'b':
fmt.Println("1.良好")
case 'A', 'a':
fmt.Println("1.优秀")
default:
fmt.Println("1.错误的输入")
}
switch {
case c == 'E', c == 'e': //可以有多个表达式
fmt.Println("2.不合格")
case c == 'D', c == 'd':
fmt.Println("2.基本合格")
case c == 'C', c == 'c':
fmt.Println("2.合格")
case c == 'B', c == 'b':
fmt.Println("2.良好")
case c == 'A', c == 'a':
fmt.Println("2.优秀")
default:
fmt.Println("2.错误的输入")
}
switch {
case c == 'E':
fmt.Println("3.不合格")
fallthrough //fallthrough会执行下一个case区块
case c == 'e':
fmt.Println("3.真的不合格")
case c == 'D', c == 'd':
fmt.Println("3.基本合格")
case c == 'C', c == 'c':
fmt.Println("3.合格")
case c == 'B', c == 'b':
fmt.Println("3.良好")
case c == 'A', c == 'a':
fmt.Println("3.优秀")
default:
fmt.Println("3.错误的输入")
}
var in interface{} = i
switch data := in.(type) { //类型推断
case int:
fmt.Printf("int: %v\n", data)
case uint:
fmt.Printf("uint: %v\n", data)
default:
fmt.Printf("type: %T\n", data)
}
}
结果如下:
请输入分数:90
优秀
请输入等级:E
1.不合格
2.不合格
3.不合格
3.真的不合格
int: 90
逻辑表达式
注意case可以是单个或多个逻辑表达式
switch {
case c == 'E', c == 'e': //可以有多个表达式
fmt.Println("2.不合格")。
case c == 'D', c == 'd':
fmt.Println("2.基本合格")
case c == 'C', c == 'c':
fmt.Println("2.合格")
case c == 'B', c == 'b':
fmt.Println("2.良好")
case c == 'A', c == 'a':
fmt.Println("2.优秀")
default:
fmt.Println("2.错误的输入")
}
fallthrough
fallthrough会执行下一个case区块
switch {
case c == 'E':
fmt.Println("3.不合格")
fallthrough //fallthrough会执行下一个case区块
case c == 'e':
fmt.Println("3.真的不合格")
case c == 'D', c == 'd':
fmt.Println("3.基本合格")
case c == 'C', c == 'c':
fmt.Println("3.合格")
case c == 'B', c == 'b':
fmt.Println("3.良好")
case c == 'A', c == 'a':
fmt.Println("3.优秀")
default:
fmt.Println("3.错误的输入")
}
类型推断
这个是一个强大的方式,它可以用于推断go语言的接口的类型,不过现在只能简单那介绍一下,你可以将interface{}可以表达任何类型
var in interface{} = i
switch data := in.(type) { //类型推断
case int:
fmt.Printf("int: %v\n", data)
case uint:
fmt.Printf("uint: %v\n", data)
default:
fmt.Printf("type: %T\n", data)
}
循环语句
循环语句只有for
package main
import "fmt"
func main() {
var input int
fmt.Printf("请输入分数(0-5):")
fmt.Scanf("%d", &input)
for i := 0; i < 5; i++ { //正常的for
fmt.Println("loop1:", i)
if i < 2 {
continue //跳过本次执行
}
if i == input {
fmt.Println("loop1: break") //跳出本层循环
break
}
}
i := 0
Loop:
for i < 5 { //去掉;的for循环
fmt.Println("loop2:", i)
for j := 0; j < 5; j++ {
if j == input {
fmt.Println("loop2: break Loop") //跳出Loop标记的循环
break Loop
}
if j == 1 {
break //跳出本层循环
}
}
i++
}
i = 0
for ; i < 5; i++ { //空缺一个元素并带有;的for循环
fmt.Println("loop3:", i)
for j := 0; j < 5; j++ {
if j < 2 {
continue
}
if j == input {
goto Exit //跳出到Exit
}
}
}
return
Exit:
fmt.Println("loop3: Exit")
}
结果如下:
请输入分数(0-5):1
loop1: 0
loop1: 1
loop1: 2
loop1: 3
loop1: 4
loop2: 0
loop2: break Loop
loop3: 0
loop3: 1
loop3: 2
loop3: 3
loop3: 4
请输入分数(0-5):2
loop1: 0
loop1: 1
loop1: 2
loop1: break
loop2: 0
loop2: 1
loop2: 2
loop2: 3
loop2: 4
loop3: 0
loop3: Exit
continue
跳过本次循环
break
没有加标签的就是跳过本层循环
加标签的就是跳过被标签标记的循环
goto
跳到被标签标记的循环,使用goto在处理一些同意的错误或者统一的出口而降低代码的冗余,增加代码可读性。这里挖个坑,之后我会在go-etl展示goto的魅力
注意:很多书籍指出goto会破环代码结构,降低代码可读性,那是因为这些书籍讲述使用goto的场景错了。
Leetcode习题69
我们以leetcode习题开始,而现在有以一道Leetcode习题结束
题目描述
给你一个非负整数 x
,计算并返回 x
的 算术平方根 。
由于返回类型是整数,结果只保留 整数部分 ,小数部分将被 舍去 。
注意:不允许使用任何内置指数函数和算符,例如 pow(x, 0.5)
或者 x ** 0.5
。
题目分析
这道题会比Leetcode习题1更加困难些,这次数据范围是int32
的非负整数范围,由于不能使用指数函数和算符,为此,在这里我们需要使用二分法,即通过二分[a,b]
(mid = a + (b-a)/2
, 第一轮a=0,b=x
)去获取mid=x/2
,如果mid*mid<x
那么此时二分[a,mid-1]
,反之二分[mid+1,b]
, 这样不断二分下去直到 mid*mid=x
或者a<b
。好的,这样我们获得了解题思路,但是还有个问题,选择y的数据类型是什么,如果选择int32
,那么相乘必然超过int32
, 为此我们必须选择int64
,注意:在Leetcode习题9中得出了结论,int
是64位的,所以不用改为int64
。
代码编写
func mySqrt(x int) int {
a, b := 0, x
for a <= b {
mid := a + (b-a)/2 //二分区间
if mid*mid == x {
return mid
}
if mid*mid < x {
a = mid + 1 //选择上面的区间
} else {
b = mid - 1
}
}
return b
}
本篇小结
恭喜你已经完成了所有控制结构的学习,你以及知道了所有控制结构用到的保留字和注意点。另外,通过Leetcode习题69和Leetcode习题9,你已经知道在编程时选择数据类型的重要性,并且练习了所有控制结构。这里的相关代码放在go语言学习的go-base/3中,请下载后进行实际的联系
注意:之后的Leetcode题目解答以及使用工具的编程中,数据类型的选择以及控制结构的应用是非常重要的,也是最为基础的。
下篇预告
go语言复合类型
3.你不知道的go语言控制语句的更多相关文章
- Objective-C语言控制语句
• 分支语句• 循环语句• 跳转语句 Objective-C中的控制语句有以下几类:• 分支语句:if-else, switch• 循环语句:while, do-while, for• 与程序转移有关 ...
- C语言编程入门之--第六章C语言控制语句
导读:本章带读者理解什么是控制语句,然后逐个讲解C语言常用的控制语句,含有控制语句的代码量多起来后就要注意写代码的风格了,本章末节都是练习题,大量的练习才能掌握好控制语句的使用. 6.1 什么是控制语 ...
- C语言控制语句总结(if else for switch while break continue)
一.if语句 1表达式 if(条件表达式) 语句 注: (1)条件表达式,一般为逻辑表达式或关系表达式,但也可以是任何数值类型,如整型.实型.字符型.指针型数据等. (2)语句,由于是C语言的语句,而 ...
- 第7章,c语言控制语句:分支和跳转
7.1 if语句 通用形式:if(expression) statment 7.2 if else语句 通用形式:if(expression) startment else startment2 7. ...
- 20160202.CCPP体系详解(0012天)
内容概要:C语言控制语句题库.doc 第三章 控制语句 一.选择题 1. 以下语句中无限循环语句是[B]. A)for(;2&5;); B)while(1,2,3); -> while( ...
- 1-了解Python
为什么使用python: 软件质量: 可读写.一致性.软件质量 支持软件开发的高级重用机制 提供开发者的效率: 代码只有java或C++的1/5~1/3 无须编译链接,提高了程序原的效率 程序的可移植 ...
- 20165327 2017-2018-2 《Java程序设计》第2周学习总结
20165327 2017-2018-2 <Java程序设计>第2周学习总结 内容:教材第2.3章 内容小结: (一)标识符由字母.下划线.美元符号和数字组成, 并且第一个字符不能是数字字 ...
- C#基础教程/适合初学者
C#基础教程 第一章 C#语言基础 本章介绍C#语言的基础知识,希望具有C语言的读者能够基本掌握C#语言,并以此为基础,能够进一步学习用C#语言编写window应用程序和Web应用程序.当 ...
- 【C语言入门教程】3.3 条件控制语句
在程序的 3 种基本结构中,第二种是选择结构,选择结构是根据程序运行时获得的条件,决定程序执行情况.条件控制语句可用来实现这种结构,C 语言提供了 if 语句和 switch 语句两种条件控制语句,i ...
- 【C语言入门教程】3.4 循环控制语句
循环结构又称重复结构,是程序的 种基本结构之一.它反复执行循环体内的代码,解决需要大量重复处理的问题.循环结构由循环控制语句实现,其中内建有条件控制语句,用来判读是否继续执行循环操作.C 语言提供了 ...
随机推荐
- PostgreSQL一站式插件推荐 -- pg_enterprise_views
近日发现PG官方插件列表中新收录了一款插件 pg_enterprise_views,因为官方已经数年未添新的插件了很是新奇,找了台设备测试过后果断上了生产,得空分享给大家. 该插件提供了数十张系统表及 ...
- MVCC-数据库
参考地址:看一遍就理解:MVCC原理详解 - 掘金 (juejin.cn) 1. 相关数据库知识点回顾 1.1 什么是数据库事务,为什么要有事务 事务,由一个有限的数据库操作序列构成,这些操作要么全部 ...
- 从0搭建Vue3组件库(九):VitePress 搭建部署组件库文档
VitePress 搭建组件库文档 当我们组件库完成的时候,一个详细的使用文档是必不可少的.本篇文章将介绍如何使用 VitePress 快速搭建一个组件库文档站点并部署到GitHub上 安装 首先新建 ...
- CANoe学习笔记(三):CANoe的诊断功能和cdd文件
内容: UDS诊断学习 CDD文件配置 诊断功能 一.UDS诊断学习: ①.UDS请求命令4种构成方式: SIDSID+SF(Sub-function)SID+DID(Data Identifier) ...
- CoFiltering:BestPracticesandTechniquesinTextGeneration
目录 Co-Filtering: Best Practices and Techniques in Text Generation Introduction: Text generation has ...
- React后台管理系统11 配置项目初始化展开代码
在上一文中,我们已经配置好了,刷新默认打开选中的样式,但是如果是在/page3/1,这种的,并没有选中到/page3里面的/page3/1,这个地方来,所以我们需要解决的就是这几个问题: 思路如下: ...
- JavaScript高级学习
JavaScript 进阶 学习作用域.变量提升.闭包等语言特征,加深对 JavaScript 的理解,掌握变量赋值.函数声明的简洁语法,降低代码的冗余度. 理解作用域对程序执行的影响 能够分析程序执 ...
- 手机号码吉利数PHP检测算法代码,超级实用
手机号码吉利数理预测解读:将手机号码末尾的四个数字,先除以八十,再减去整数部分,只使用剩下的小数(小数点反面的数字)乘以八十,然后将所得结果,对表查阅,就知道吉凶.(换句话说就是余数)例如:手机尾号是 ...
- K8S | 容器和Pod组件
对比软件安装和运行: 一.场景 作为研发人员,通常自己电脑的系统环境都是非常复杂,在个人的习惯上,是按照下图的模块管理电脑的系统环境: 对于「基础设施」.「主机操作系统」.「系统软件」来说,通常只做配 ...
- SpringBoot定义优雅全局统一Restful API 响应框架完结撒花篇封装starter组件
之前我们已经,出了一些列文章. 讲解如何封统一全局响应Restful API. 感兴趣的可以看我前面几篇文章 (整个starter项目发展史) SpringBoot定义优雅全局统一Restful AP ...