Golang核心编程

Go语言开篇介绍

Go语言 是Google公司 在2007开发一种静态强类型、编译型语言,并在 2009 年正式对外发布。

Go语言以其近C的执行性能和近解析型语言的开发效率,以及近乎于完美的编译速度,已经风靡全球。很多人将Go语言称为21世纪的C语言,因为Go不仅拥有C的简洁和性能,而且针对多处理器系统应用程序的编程进行了优化,很好的提供了21世纪互联网环境下服务端开发的各种实用特性。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uahYWlle-1659228427096)(assets/%E6%88%AA%E5%B1%8F2022-07-23%2023.59.38-8591994.png)]

Go语言的诞生

事件起源于2007年9月,当时 C++委员会正在 Google 对 C++ 语言新增加的35个新的特性进行一场分享演讲。

Google 的技术大神们也在认真听讲座,其中就有Go语言的三个创作者,分别是: Robert Griesemer(罗伯特.格利茨默),Rob Pike(罗伯.派克),Ken Thompson(肯.汤普森)。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NKkCfZgl-1659228427096)(assets/image-20210601130737782.png)]

  • Rob Pike(罗伯.派克)

    罗布·派克是Unix的先驱,是贝尔实验室最早和Ken Thompson以及 Dennis M. Ritche(C语言之父) 开发Unix的猛人,UTF-8的设计人。让人佩服不已的是,罗伯伯还是1980年奥运会射箭的银牌得主。

  • Ken Thompson(肯.汤普森)

    Ken Thompson,C语言前身B语言的作者,与Dennis Ritchie是Unix的原创者。1983年图灵奖得主以及1998年美国国家技术奖(National Medal of Technology)得主。

  • Robert Griesemer(罗伯特.格利茨默)

    参与制作了Java的HotSpot编译器以及Chrome浏览器的javascript的搜索引擎V8。

随着会议的中场休息,大家开始了对这些 C++ 语言新特性是否带来更多的价值进行吐槽。Rob Pike他们认为:简化语言的成就远大于添加功能。于是,一门新的语言,Go,在这个思路下应运而生。

2007 年 9 月 25 号,Rob Pike在回家的路上得到关于新语言名字的灵感,于是给另外两人发了邮件:

img

邮件正文大意为:

在开车回家的路上我得到了些灵感。

1.给这门编程语言取名为“go”,它很简短,易书写。工具类可以命名为:goc、 gol、goa。

交互式的调试工具也可以直接命名为“go”。语言文件后缀名为 .go 等等

这就是 Go 语言名字的来源,自此之后 Robert、Rob 和 Ken 三个人开始在 Google 内部进行了研发,一直到了 2009 年,Go 正式开源了,Go 项目团队将 2009 年 11 月 10 日,即该语言正式对外开源的日字作为其官方生日。源代码最初托管在 http://code.google.com 上,之后几年才逐步的迁移到 GitHub 上。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yDb6duBw-1659228427097)(assets/%E6%88%AA%E5%B1%8F2022-07-24%2007.34.20-8620011.png)]

Go语言的版本

Go 1.0 — 2012 年 3 月:Go 的第一个版本,带着一份兼容性说明文档来保证与未来发布版本的兼容性,进而不会破坏已有的程序。

Go 1.1 — 2013 年 5 月:这个 Go 版本专注于优化语言(编译器,gc,map,go 调度器)和提升它的性能。

Go 1.3 — 2014 年 6 月:这个版本对栈管理做了重要的改进。栈可以申请[连续的内存片段,提高了分配的效率

Go 1.4 — 2014 年 12 月:此版本带来了官方对 Android 的支持,让我们可以只用 Go 代码就能写出简单的 Android 程序。

Go 1.7 — 2016 年 8 月: 这个版本发布了context 包,为用户提供了处理超时和任务取消的方法。

Go 1.11 — 2018 年 8 月: Go 1.11 带来了一个重要的新功能:Go modules。

Go语言的优势

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gZ704dVq-1659228427098)(assets/%E6%88%AA%E5%B1%8F2022-07-24%2007.18.27-8618378.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1fNi6AUM-1659228427098)(assets/%E6%88%AA%E5%B1%8F2022-07-24%2007.29.21-8618975.png)]

Go语言的应用领域

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0UMtRGfr-1659228427099)(assets/%E6%88%AA%E5%B1%8F2022-07-24%2007.56.06-8620580.png)]

使用Go的大型互联网公司

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-56PKdAT8-1659228427099)(assets/%E4%BD%BF%E7%94%A8Go%E7%9A%84%E4%BA%92%E8%81%94%E7%BD%91%E5%85%AC%E5%8F%B8-1622538812909.png)]

Go语言的强项在于它适合用来开发网络并发方面的服务,比如消息推送、监控、容器等,所以在高并发的项目上大多数公司会优先选择 Golang 作为开发语言。另外一个应用就是对一些python,php或者java项目进行重构。

介绍完Go语言,那么接下来我们就可以正式进入Golang的学习了。

一、计算机基础

计算机(computer)俗称电脑,是现代一种用于高速计算的电子计算机器,可以进行数值计算,又可以进行逻辑计算,还具有存储记忆功能。是能够按照程序运行,自动、高速处理海量数据的现代化智能电子设备。

计算机是20世纪最先进的科学技术发明之一,对人类的生产活动和社会活动产生了极其重要的影响。它的应用领域从最初的军事科研应用扩展到社会的各个领域,已形成了规模巨大的计算机产业,带动了全球范围的技术进步,由此引发了深刻的社会变革。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WgGOB7lT-1659228427099)(assets/u=3569666097,3164525901&fm=253&fmt=auto&app=120&f=JPEG.jpeg)]

1.1、计算机硬件组成

  • CPU

其中,CPU包括运算器和控制器,相当于计算机的大脑,是计算机的运算核心和控制核心。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-glw3AAoL-1659228427100)(assets/cpu2.jpg)]

(1) 运算器是用来进行数据运算加工的。

(2) 控制器是是计算机的指挥中心,负责决定执行程序的顺序,给出执行指令时机器各部件所需要的操作控制命令,用于协调和控制计算机的运行。

  • 存储器

储存器可分为内储存器和外储存器两部分:内存属于内储存器,内存是CPU与硬盘之间的桥梁,只负责在CPU与硬盘之间做数据预存加速的功能。断电后即会被清除。输入设备的数据是从设备接口进去到端口缓冲器的,再经主板的输入输出总线(I/O总线)直接到CPU的,不经过内存。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LsghsRMJ-1659228427100)(assets/image-20210412133337911-1618215970205.png)]

外储存器是指除计算机内存及CPU缓存以外的储存器,此类储存器一般断电后仍然能保存数据。常见的外存储器有硬盘、软盘、光盘、U盘等。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DkQqb90l-1659228427101)(assets/image-20210412133939847-1618215970206.png)]

  • 输入输出设备

输入设备就是键盘、鼠标、麦克风、扫描仪等等,向电脑输入信息。输入设备则相反,电脑向外部输出信息,如显示器、打印、音像、写入外存等。

1.2、冯-诺伊曼计算机

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nP2icyOX-1659228427101)(assets/image-20210406113742869-1618215970206.png)]

提到计算机,就不得不提及在计算机的发展史上做出杰出贡献的著名应用数学家冯诺依曼(Von Neumann,是他带领专家提出了一个全新的存储程序的通用电子计算机方案。这个方案规定了新机器由5个部分组成:运算器、逻辑控制装置、存储器、输入和输出。并描述了这5个部分的职能和相互关系。

早期的ENIAC有一个致命的缺点就是程序与计算两分离。在埃历阿克ENIAC尚未投入运行前,冯·诺依曼就已开始着手起草一份新的设计报告,要对这台电子计算机进行脱胎换骨的改造。他把新机器的方案命名为“离散变量自动电子计算机”,英文缩写译音是“埃德瓦克”(EDVAC)。1945年6月,冯·诺依曼与戈德斯坦、勃克斯等人,为埃德瓦克方案联名发表了一篇长达101页纸洋洋万言的报告,即计算机史上著名的“101页报告”。这份报告奠定了现代电脑体系结构坚实的根基,直到今天,仍然被认为是现代电脑科学发展里程碑式的文献。报告明确规定出计算机的五大部件**(输入系统、输出系统、存储器、运算器、控制器),并用二进制替代十进制运算**,大大方便了机器的电路设计。埃德瓦克方案的革命意义在于**“存储程序”**──程序也被当作数据存进了机器内部,以便电脑能自动依次执行指令,再也不必去接通什么线路。
  人们后来把根据这一方案思想设计的机器统称为“诺依曼机”。自冯·诺依曼设计的埃德瓦克始,直到今天我们用“奔腾”芯片制作的多媒体计算机为止,电脑一代又一代的“传人”,大大小小千千万万台计算机,都没能够跳出诺依曼机的掌心。在这个意义上,冯·诺依曼是当之无愧的“计算机之父”。而

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YDAXdu4R-1659228427101)(assets/%E6%88%AA%E5%B1%8F2022-07-23%2023.50.15-8591532.png)]

总线(Bus)是计算机各种功能部件之间传送信息的公共通信干线,它是由导线组成的传输线束, 按照计算机所传输的信息种类,计算机的总线可以划分为数据总线地址总线控制总线,分别用来传输数据、数据地址和控制信号。总线是一种内部结构,它是cpu、内存、输入、输出设备传递信息的公用通道,主机的各个部件通过总线相连接,外部设备通过相应的接口电路再与总线相连接,从而形成了计算机硬件系统

二、编程语言介绍

2.1、什么是编程语言

编程语言是用来控制计算机的一系列指令(Instruction),它有固定的格式和词汇(不同编程语言的格式和词汇不一样)。就像我们中国人之间沟通需要汉语,英国人沟通需要英语一样,人与计算机之间进行沟通需要一门语言作为介质,即编程语言。

编程语言的发展经历了机器语言(指令系统)=>汇编语言=>高级语言(C、java、Go等)。

010010101001-》ADD

  • 计算机在设计中规定了一组指令(二级制代码),这组指令的集和就是所谓的机器指令系统,用机器指令形式编写的程序称为机器语言。
  • 但由于机器语言的千上万条指令难以记忆,并且维护性和移植性都很差,所以在机器语言的基础上,人们提出了采用字符和十进制数代替二进制代码,于是产生了将机器语言符号化的汇编语言。
  • 虽然汇编语言相较于机器语言简单了很多,但是汇编语言是机器指令的符号化,与机器指令存在着直接的对应关系,无论是学习还是开发,难度依然很大。所以更加接近人类语言,也更容易理解和修改的高级语言就应运而生了,高级语言的一条语法往往可以代替几条、几十条甚至几百条汇编语言的指令。因此,高级语言易学易用,通用性强,应用广泛。

2.2、编译型语言与解释性语言

计算机是不能理解高级语言的,更不能直接执行高级语言,它只能直接理解机器语言,所以使用任何高级语言编写的程序若想被计算机运行,都必须将其转换成计算机语言,也就是机器码。而这种转换的方式分为编译和解释两种。由此高级语言也分为编译型语言和解释型语言。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AVSXLGro-1659228427102)(assets/%E6%88%AA%E5%B1%8F2022-07-23%2023.39.38-8590805.png)]

  • 编译型语言

使用专门的编译器,针对特定的平台,将高级语言源代码一次性的编译成可被该平台硬件执行的机器码,并包装成该平台所能识别的可执行性程序的格式。

编译型语言写的程序执行之前,需要一个专门的编译过程,把源代码编译成机器语言的文件,如exe格式的文件,以后要再运行时,直接使用编译结果即可,如直接运行exe文件。因为只需编译一次,以后运行时不需要编译,所以编译型语言执行效率高。

1、一次性的编译成平台相关的机器语言文件,运行时脱离开发环境,运行效率高;

2、与特定平台相关,一般无法移植到其他平台;

  • 解释型语言

使用专门的解释器对源程序逐行解释成特定平台的机器码并立即执行。是代码在执行时才被解释器一行行动态翻译和执行,而不是在执行之前就完成翻译。

1.解释型语言每次运行都需要将源代码解释称机器码并执行,执行效率低;

2.只要平台提供相应的解释器,就可以运行源代码,所以可以方便源程序移植;

三、Go环境安装

3.1、Go编译器的下载

-- 官网:https://golang.google.cn/
-- go中文网:https://studygolang.com/dl

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ukPvOebR-1659228427102)(assets/image-20220719153946581-8216387.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kjlLJcdb-1659228427102)(assets/image-20220719153914987-8216356.png)]

3.2、安装 for Mac

3.2.1、 mac系统下安装SDK

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ApxF86pP-1659228427102)(assets/image-20220719160916965.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CtJzwWpY-1659228427103)(assets/%E6%88%AA%E5%B1%8F2022-07-19%2015.44.41-8218367.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-m6DU4PV1-1659228427103)(assets/%E6%88%AA%E5%B1%8F2022-07-19%2015.45.31-8218367.png)]

安装完成以后可以使用终端软件(例如iTerm)中输入go version查看Go编译器的版本信息

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pdqkPmxp-1659228427103)(assets/image-20220720133017365-8295019.png)]

mac系统下会默认安装到GOROOT="/usr/local/go"中,通过go env可以查看

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5pBh47h3-1659228427104)(assets/image-20220720133041195-8295042.png)]

3.2.2、 mac系统下配置GOPATH

开发包安装完成后,我们还需要配置一下GOPATH 环境变量,之后才可以使用Go语言进行开发。GOPATH是开发人员编写Go程序的工作空间路径,也就是存放Go代码的地方

在终端中运行 vi ~/.bash_profile 添加下面这行代码

export GOPATH=$HOME/goWork

保存然后退出你的编辑器。然后在终端中运行下面命令

source ~/.bash_profile

提示:$HOME 是每个电脑下的用户主目录,每个电脑可能不同,可以在终端运行 echo $HOME 获取

然后保存并退出编辑器,运行 source ~/.bash_profile 命令即可。

3.3 安装 for Window

3.3.1、window系统下安装SDK

双击我们下载好的Go语言开发包即可启动安装程序,如下图所示,这是Go语言的用户许可协议,无需管它,直接勾选“I accept …”然后点击“Next”即可。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ER2CcJAO-1659228427104)(assets/wps1-8295805-8298119.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ev4E95Bh-1659228427104)(assets/wps2-8298130-8298133.png)]

在 Windows 系统下Go语言开发包会默认安装到 C 盘的 Go 目录下,推荐在这个目录下安装,使用起来较为方便。当然,你也可以选择其他的安装目录,确认无误后点击“Next”,如下图所示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Q9gbnJbK-1659228427104)(assets/wps3-8298145-8298146.png)]

Go语言开发包的安装没有其他需要设置的选项,点击“Install”即可开始安装,如下图所示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-822H0Gdd-1659228427105)(assets/wps4-8298156-8298158.png)]

等待程序完成安装,然后点击“Finish”退出安装程序。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Of4yfhCj-1659228427105)(assets/wps5-8298167-8298168.png)]

安装完成后,在我们所设置的安装目录下将生成一些目录和文件,如下图所示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mgGEGSRA-1659228427105)(assets/wps6-8296013-8298175-8298179.png)]

在默认情况下,win系统下Go 将会被安装在目录 c:\go 下,但如果你在安装过程中修改安装目录,则需要手动修改所有的环境变量的值。

通过go env命令可以查看环境变量的所有情况。值得一提的是,GOROOT 表示 Go 开发包的安装目录。

国内Go语言库镜像:https://github.com/goproxy/goproxy.cn 在终端输入:go env -w GOPROXY=https://goproxy.cn,direct对代理进行修改。

GOPROXY https://proxy.golang.org,direct

阿里云: export GOPROXY=https://mirrors.aliyun.com/goproxy/

七牛云: export GOPROXY= https://goproxy.cn

go env -w “GO111MODULE=off” // 关闭go mod

3.3.2、window系统下配置GOPATH

GOPATH 是 Go语言中使用的一个环境变量,它使用绝对路径提供项目的工作目录(workspace)。

GOPATH下创建src文件夹,即存放Go项目代码的位置。

开发包安装完成后,我们还需要配置一下GOPATH 环境变量,之后才可以使用Go语言进行开发。GOPATH是开发人员编写Go程序的工作空间路径,也就是存放Go代码的地方。
在桌面或者资源管理器右键“此电脑”(或者“我的电脑”)→“属性”→“高级系统设置”→“环境变量”,如下图所示。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FS24IgK1-1659228427106)(assets/wps7.jpg)]

在弹出的菜单里找到 GOPATH 对应的选项点击编辑之后就可以修改了,没有的话可以选择新建,并将变量名填写为 GOPATH,变量值设置为任意目录均可(尽量选择空目录),例如 F:\GoWork。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-enN7VXu3-1659228427106)(assets/wps8.jpg)]

GOPATH对应创建的文件夹中里面,手动创建如下3个目录

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-66FDT5kd-1659228427106)(assets/image-20210315120607129-8298550.png)]

src    存储go的源代码(需要我们自己手动创建)
pkg  存储编译后生成的包文件 (自动生成)
bin   存储生成的可执行文件(自动生成)

3.4、第一个Go程序


package main

import "fmt"

func main() {
	fmt.Println("Hello Yuan!")
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gKYX8OFu-1659228427106)(assets/image-20220722120013307-8462415.png)]

  1. 程序没有涉及到自定义包调用时可以放在电脑任何位置
  2. 为了以后方便管理,我们暂时统一放在gopath的src下
  3. 后面会学习go mod更好进行包管理

3.4.1、程序语法解析

(1) main包和main函数

Go语言以“包”作为管理单位,每个 Go 源文件必须先声明它所属的包,所以我们会看到每个 Go 源文件的开头都是一个 package 声明。Go语言的包与文件夹是一一对应的。一个Go语言程序必须有且仅有一个 main 包。main 包是Go语言程序的入口包,如果一个程序没有 main 包,那么编译时将会出错,无法生成可执行文件。

(2) import

在包声明之后,是 import 语句,用于导入程序中所依赖的包,导入的包名使用双引号""包围,格式如下:

import "name"

其中 import 是导入包的关键字,name 为所导入包的名字。

导入的包中不能含有代码中没有使用到的包,否则Go编译器会报编译错误

也可以使用一个 import 关键字导入多个包,此时需要用括号( )将包的名字包围起来,并且每个包名占用一行

import(
    "p1"
    "p2"
)

3.4.2、程序编译执行

我们上面给大家介绍过,Go语言是像C语言一样的编译型的静态语言,所以在运行Go语言程序之前,先要将其编译成二进制的可执行文件。

可以通过Go语言提供的go build或者go run命令对Go语言程序进行编译:

(1) go build命令可以将Go语言程序代码编译成二进制的可执行文件,但是需要我们手动运行该二进制文件;

1、如果是普通包,当你执行go build之后,它不会产生任何文件。【非main包】

2、如果是main包,当你执行go build之后,它就会在当前目录下生成一个可执行文件,比如win系统的exe文件

3、你也可以指定编译输出的文件名。我们可以指定go build -o 可执行文件.exe

(2)除了使用go build命令外,Go语言还为我们提供了go run命令,go run命令将编译和执行指令合二为一,会在编译之后立即执行Go语言程序,但是不会生成可执行文件。

go run go文件名称  //  go文件名称不能为空

3.5、IDE的安装与使用

3.5.1、安装Goland

GoLand是Jetbrains公司推出专为Go开发人员构建的跨平台IDE,可以运行在Windows,Linux,macOS系统之上,

下载地址:https://www.jetbrains.com/go/download/#section=windows

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-to8ebnfO-1659228427107)(assets/%E6%88%AA%E5%B1%8F2022-07-20%2015.25.45-8301995.png)]

下载完成之后便可以进行安装了

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CYPzcFBC-1659228427107)(assets/%E6%88%AA%E5%B1%8F2022-07-20%2018.39.14.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QxWuwk6l-1659228427107)(assets/%E6%88%AA%E5%B1%8F2022-07-20%2018.39.26.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-drw7YhQ1-1659228427107)(assets/%E6%88%AA%E5%B1%8F2022-07-20%2018.39.46.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oh5cRCsM-1659228427108)(assets/%E6%88%AA%E5%B1%8F2022-07-20%2018.39.59.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HO2IeAjL-1659228427108)(assets/%E6%88%AA%E5%B1%8F2022-07-20%2018.43.07.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2EtX4Ltv-1659228427108)(assets/%E6%88%AA%E5%B1%8F2022-07-20%2018.44.16.png)]

因为GoLand是收费的IDE,同时也提供了30天免费试用的方式。如果经济能力允许的话,可以从指定渠道购买正版GoLand.
GoLand提供了Jetbrains Account,Activition Code和License Server三种激活方式,使用前必须激活或者选择免费试用
当激活或者选择免费试用之后便会启动GoLand。

免费试用需要点击log in,进行账户注册(在PC端完成),然后登陆,即可试用30天

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Y0urpHbQ-1659228427109)(assets/%E6%88%AA%E5%B1%8F2022-07-20%2015.45.56-8303165.png)]

此时可以选择New Project在指定的路径创建新的项目目录或者选择Open打开已经存在的项目目录,进行编辑。

3.5.2、GoLand下编写Go程序

当GoLand启动后,便可以使用它来编写Go程序了。首先选择New Project创建一个项目。然后设置项目路径和GOROOT

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KPMQf0Kv-1659228427109)(assets/%E6%88%AA%E5%B1%8F2022-07-20%2015.49.47-8303415.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-befldgul-1659228427109)(assets/%E6%88%AA%E5%B1%8F2022-07-20%2015.55.22-8303758.png)]

然后点击create创建。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IlArwsCT-1659228427110)(assets/image-20220720155651723-8303813.png)]

创建文件和文件夹:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qUzFFFc4-1659228427110)(assets/%E6%88%AA%E5%B1%8F2022-07-20%2016.01.55-8304149.png)]

goland安装好后没有编译器的单独配置go编译器路径:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NTFmaYTS-1659228427110)(assets/%E6%88%AA%E5%B1%8F2022-07-20%2016.04.55-8304361.png)]

3.5.3、IDE的快捷键

快捷键作用
Ctrl + /单行注释
Ctrl + Shift + /多行注释
Ctrl + D复制当前光标所在行
Ctrl + X删除当前光标所在行
Ctrl + Alt + L格式化代码
Ctrl + Shift + 方向键上或下将光标所在的行进行上下移动(也可以使用 Alt+Shift+方向键上或下)
Ctrl + Alt + left/right返回至上次浏览的位置
Ctrl + R替换
Ctrl + F查找文本
Ctrl + Shift + F全局查找

3.5.4、控制台折叠多余信息

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ufd16XDQ-1659228427110)(assets/image-20220722112303208-8460185.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kYeNaVL2-1659228427111)(assets/image-20220722112534240-8460335.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MaXeX22W-1659228427112)(assets/image-20220722112629909-8460391.png)]

四、基础语法

4.1、注释

注释就是对代码的解释和说明,其目的是让人们能够更加轻松地了解代码。注释是开发人员一个非常重要的习惯,也是专业的一种表现。单行注释是最常见的注释形式,你可以在任何地方使用以 // 开头的单行注释。多行注释也叫块注释,均已以 /* 开头,并以 */ 结尾。

注释只是为了提高可读性,不会被计算机编译。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7UkKcbun-1659228427112)(assets/image-20220105164023755-16413720250637.png)]

4.2、变量

在计算机编程中,我们用变量来保存并管理很多数据,并用变量名来区分、识别和处理这些数据。

变量本质上是一种对内存地址的引用,让你能够把程序中准备使用的每一段数据都赋给一个简短、易于记忆的名字进行操作。

4.2.1、声明变量

和C语言一样,Go语言也是通过var关键字进行声明,不同的是变量名放在类型前,具体格式如下

var  变量名 变量类型
var x int
var s string
var b bool

fmt.Println(x)  // 0
fmt.Println(s)  // ""
fmt.Println(b)  // false

声明未赋值,系统默认赋这些类型零值

如果声明多个变量,可以进行简写

// 声明多个相同类型变量
var x,y int
// 声明多个不同类型变量
var (
		name      string
		age       int
		isMarried bool
	)

4.2.2、变量赋值

变量赋值的3种方法

(1)变量名=值
// 先声明再赋值
var x int
x = 10     // 不要 重复声明 : var x = 10
fmt.Println(x)
x = 20. // 重新赋值

//  直接声明赋值
// var y string= "hello yuan!"
var y = "hello yuan!"
fmt.Println(y)

// 声明赋值精简版
s := "hi,yuan!"  // 1、编译器会自动根据右值类型推断出左值的对应类型,等同于var s = "hi,yuan!"。2、该变量之前不能声明,否则重复声明
fmt.Println(s)

// 一行声明赋值多个变量
var name,age = "yuan",22
(2)变量名=变量名
	var a = 100
	var b = a // 变量之间的赋值是值拷贝
	fmt.Println(a, b)
	a = 200
	fmt.Println(b)
(3)变量名=值 + 值 (变量名)
     var a, b = 10, 20
	var c = a + b
	fmt.Println(c)
	var d = c + 100
	fmt.Println(d)

练习题:

  1. 将x,y两个变量的值进行交换

4.2.3、匿名变量

匿名变量即没有命名的变量,在使用多重赋值时,如果想要忽略某个值,可以使用匿名变量(anonymous variable)。 匿名变量用一个下划线_表示。

a,b,c :=4,5,6
fmt.Println(a,b,c)
// 如果只想接受第个变量,可以对前两个变量匿名
_,_,x := 4,5,6
fmt.Println(x)

匿名变量不占用命名空间,不会分配内存

让代码非常清晰,基本上屏蔽掉了可能混淆代码阅读者视线的内容,从而大幅降低沟通的复杂度和代码维护的难度。

4.2.4、变量命名规则

变量命名是需要遵循一定的语法规范的,否则编译器不会通过。

1、变量名称必须由数字、字母、下划线组成。

2、标识符开头不能是数字。

3、标识符不能是保留字和关键字。

4、建议使用驼峰式命名,当名字有几个单词组成的时优先使用大小写分隔

5、变量名尽量做到见名知意。

6、变量命名区分大小写

go语言中有25个关键字,不能用于自定义变量名

break        default          func           interface         select
case         defer            go             map               struct
chan         else             goto           package           switch
const        fallthrough      if             range             type
continue     for              import         return            var

还有30多个预定义的名字,用于内建的常量、类型和函数

// 内建常量:
    true false iota nil
// 内建类型:
    int int8 int16 int32 int64
    uint uint8 uint16 uint32 uint64 uintptr
    float32 float64 complex128 complex64
    bool byte rune string error
// 内建函数:
    make len cap new append copy close delete
    complex real imag
    panic recover

4.3、语句分隔符

就像我们写作文一样,一定要有像逗号或者句号这样的语句分隔符,否则无法断句根本不能理解,编程语言也一样,需要给解释器或者编译器一个语句分割,让它知道哪里到哪里是一个语句,才能再去解析语句。

在 Go 程序中,一行代表一个语句结束。每个语句不需要像 C 家族中的其它语言一样以分号 ; 结尾,因为这些工作都将由 Go 编译器自动完成。如果你打算将多个语句写在同一行,它们则必须使用 ; 人为区分(不建议这样写)。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7yNY22Zg-1659228427113)(assets/image-20220105163143091-16413715041204.png)]

//var name = "yuan";var age = 18 // 不推荐
//fmt.Println(name)
//fmt.Println(age)  // 不报错但是不推荐

// 推荐写法
var name = "yuan"  // 换行即分隔符
var age = 18
fmt.Println(name)
fmt.Println(age)

4.4、基本数据类型

基本数据类型包含整型和浮点型,布尔类型以及字符串,这几种数据类型在几乎所有编程语言中都支持。

4.4.1、整形

  • 整形类型
具体类型取值范围
int8-128到127
uint80到255
int16-32768到32767
uint160到65535
int32-2147483648到2147483647
uint320到4294967295
int64-9223372036854775808到9223372036854775807
uint640到18446744073709551615
uint与平台相关,32位操作系统上就是uint32,64位操作系统上就是uint64
int与平台相关,32位操作系统上就是int32,64位操作系统上就是int64
var x int
x = 9223372036854775809
fmt.Print(x) // overflows int
  • 进制转换
	// 十进制转化
	var a int = 10
	fmt.Printf("%d \n", a)  // 10    占位符%d表示十进制
	fmt.Printf("%b \n", a)  // 1010  占位符%b表示二进制
	fmt.Printf("%o \n", a)  // 12    占位符%o表示八进制
	fmt.Printf("%x \n", a)  // a     占位符%x表示十六进制

	// 八进制转化
	var b int = 020
	fmt.Printf("%o \n", b)  // 20
	fmt.Printf("%d \n", b)  // 16
	fmt.Printf("%x \n", b)  // 10
	fmt.Printf("%b \n", b)  // 10000

	// 十六进制转化
	var c = 0x12
	fmt.Printf("%d \n", c)  // 18
	fmt.Printf("%o \n", c)  // 22
	fmt.Printf("%x \n", c)  // 12
	fmt.Printf("%b \n", c)  // 10010

4.4.2、浮点型

  • float类型

float类型分为float32float64两种类型,这两种浮点型数据格式遵循 IEEE 754 标准。

单精度浮点数占用4个字节(32位)存储空间来存储一个浮点数。而双精度浮点数使用 8个字节(64位)存储空间来存储一个浮点数。

单精度浮点数最多有7位十进制有效数字,如果某个数的有效数字位数超过7位,当把它定义为单精度变量时,超出的部分会自动四舍五入。双精度浮点数可以表示十进制的15或16位有效数字,超出的部分也会自动四舍五入。

浮点类型默认声明为float64。

     var f1 float32 // float32:  单精度浮点型
	f1 = 3.1234567890123456789
	fmt.Println(f1, reflect.TypeOf(f1))

	var f2 float64 // 双精度浮点型
	f2 = 3.1234567890123456789
	fmt.Println(f2, reflect.TypeOf(f2))

	var f3 = 3.1234567890123456789
	fmt.Println(f3, reflect.TypeOf(f2)) // 默认64
  • 科学计数表示
var f1 = 2e10        // 即使是整数用科学技术表示也是浮点型
fmt.Println(f1,reflect.TypeOf(f1))

var f2 = 2e-2
fmt.Println(f2,reflect.TypeOf(f2))

4.4.3、布尔类型

布尔类型是最基本数据类型之一,只有两个值:true和false,分别代表逻辑判断中的真和假,主要应用在条件判断中。

package main

import (
	"fmt"
	"reflect"
)

func main() {
	var b bool // 声明b是一个布尔类型
	b = true
	b = false // 该类型只有true和false两个值,分别代表真假两种状态
	fmt.Println(b, reflect.TypeOf(b))

	fmt.Println(1 == 1) // 比较运算符的结果是一个布尔值
	// fmt.Println(1 == "1") // 报错,mismatched types不能比较
	fmt.Println(3 > 1)

	var name = "yuan"
	var b2 = name == "rain"
	fmt.Println(b2)

}

4.4.4、字符串

字符串是最基本也是最常用的数据类型,是通过双引号将多个字符按串联起来的一种数据,用于展示文本。

var s = "hello yuan"  
fmt.Println(s)

单引号只能标识字符

字符串的基本操作

字符串在内存中是一段连续存储空间

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mjQR1dC5-1659228427113)(assets/%E6%88%AA%E5%B1%8F2022-07-23%2020.58.43-8581139.png)]

注意:

  1. 索引从零开始计数
  2. go语言不支持负索引
var s = "hello yuan"
fmt.Println(s)

// (1)索引取值 slice[index]  
a:= s[2]
fmt.Println(string(a))

// (2)切片取值slice[start:end], 取出的元素数量为:结束位置 - 开始位置;
b1:=s[2:5]   //
fmt.Println(b1)
b2:=s[0:]    // 当缺省结束位置时,表示从开始位置到整个连续区域末尾;
fmt.Println(b2)
b3:=s[:8]    // 当缺省开始位置时,表示从连续区域开头到结束位置;
fmt.Println(b3)

// (3)字符串拼接
var s1 = "hello"
var s2 = "yuan"
var s3 = s1 + s2 // 生成一个新的字符串
fmt.Println(s3)

转义符

Go 语言的字符串常见转义符包含回车、换行、单双引号、制表符等,如下表所示。

转义符含义
\r回车符(返回行首)
\n换行符(直接跳到下一行的同列位置)
\t制表符
\'单引号
\"双引号
\\反斜杠

举个例子,我们要打印一个Windows平台下的一个文件路径:

package main

import "fmt"

func main() {
	var s1 = "hi yuan\nhi,alvin"
	fmt.Println(s1)
	var s2 = "his name is \"rain\""
	fmt.Println(s2)
	var s3 = "D:\\next\\go.exe"
	fmt.Println(s3)
}

多行字符串

Go语言中要定义一个多行字符串时,就必须使用反引号字符:

s1 := `第一行
第二行
第三行
`
fmt.Println(s1)

反引号间换行将被作为字符串中的换行,但是所有的转义字符均无效,文本将会原样输出。

字符串的常用方法
方法介绍
len(str)求长度
strings.ToUpper,strings.ToLower生成一个新的全部大写的字符串,生成一个新的全部小写的字符串
strings.ReplaceAll生成一个新的原字符串被指定替换后的字符串
strings.Contains判断是否包含
strings.HasPrefix,strings.HasSuffix前缀/后缀判断
strings.Trim去除字符串两端匹配的内容
strings.Index(),strings.LastIndex()子串出现的位置
strings.Split分割,将字符串按指定的内容分割成数组
strings.Join(a[]string, sep string)join操作,将数组按指定的内容拼接成字符串
package main

import (
	"fmt"
	"reflect"
	"strings"
)

func main() {
	s := "hello world"
	// fmt.Println(len(s))
	// strings.ToUpper 和 strings.ToLower
	s1 := strings.ToUpper("Yuan")
	s2 := strings.ToLower("Rain")
	fmt.Println(s1, s2)

	// strings.Trim
     user := "  yuan "
	fmt.Println(len(user))
	fmt.Println(strings.TrimLeft(user, " "))
	fmt.Println(strings.TrimSpace(user))
	fmt.Println(strings.Trim(user, " "))

	s := "alvin,yuan,eric"
	// strings.Index,strings.LastIndex
	var index = strings.Index(s, "yuan!")
	fmt.Println(index) // 未找到返回-1
	var index2 = strings.LastIndex(s, "l")
	fmt.Println(index2)

	// strings.HasPrefix,strings.HasSuffix,strings.Contains(实现的依赖的就是strings.Index)
	fmt.Println(strings.HasPrefix(s, "alv"))
	fmt.Println(strings.HasSuffix(s, "eric"))
	fmt.Println(strings.Contains(s, "eric"))

	// strings.Split: 将字符串分割成数组
	var ret2 = strings.Split(s, ",")
	fmt.Println(ret2, reflect.TypeOf(ret2))

	// strings.Join:将数组拼接成字符串
	var ret3 = strings.Join(ret2, "-")
	fmt.Println(ret3, reflect.TypeOf(ret3))

}

练习:

  1. 基于字符串操作获取用户名和密码* s := “mysql … -u root -p 123”

4.4.6、类型转换

Go语言中只有强制类型转换,没有隐式类型转换。该语法只能在两个类型之间支持相互转换的时候使用。


    // (1)整型之间的转换
	var a int8
	a = 99
	fmt.Println(int64(a), reflect.TypeOf(int64(a)))
	fmt.Println(float64(a), reflect.TypeOf(float64(a)))

	// (2)string与int类型的转换
	x := strconv.Itoa(98)
	fmt.Println(x, reflect.TypeOf(x))
	y, _ := strconv.Atoi("97")
	fmt.Println(y, reflect.TypeOf(y))

	// (3) Parse系列函数

	//  ParseInt
	//  输入:1.数字的字符串形式 2.base,数字字符串的进制,比如:2进制、10进制。
	//       3.bitSize的含义是⼤⼩限制,如果字符串转化的整形数据类型超过bitSize的最大值,那么输出的int64为bitSize的最大值,err就会显⽰数据超出范围。
	i1, _ := strconv.ParseInt("1000", 10, 8)
	println(i1)
	i2, _ := strconv.ParseInt("1000", 10, 64)
	println(i2)

	f2, _ := strconv.ParseFloat("3.1415926", 64)
	fmt.Println(f2, reflect.TypeOf(f2))
	f1, _ := strconv.ParseFloat("3.1415926", 32)
	fmt.Println(f1, reflect.TypeOf(f1))

	// 返回字符串表示的bool值。它接受1、0、t、f、T、F、true、false、True、False、TRUE、FALSE;否则返回错误。
	b1, _ := strconv.ParseBool("true")
	fmt.Println(b1, reflect.TypeOf(b1))
	b2, _ := strconv.ParseBool("T")
	fmt.Println(b2, reflect.TypeOf(b2))
	b3, _ := strconv.ParseBool("1")
	fmt.Println(b3, reflect.TypeOf(b3))
	b4, _ := strconv.ParseBool("100")
	fmt.Println(b4, reflect.TypeOf(b4))

4.5、运算符

一个程序的最小单位是一条语句,一条语句最少包含一条指令,而指令就是对数据做运算,我们已经学完基本数据类型了,知道如何构建和使用一些最简单的数据,那么我们能对这些数据做什么运算呢,比如fmt.Println(1+1)这条语句包含两个指令,首先是计算1+1的指令,1就是数据,+就是算术运算符中的相加,这样计算机就可以帮我们执行这个指令计算出结果,然后执行第二个指令,即将计算结果2打印在终端,最终完成这条语句。

4.5.1、算数运算符

运算符描述
+相加
-相减
*相乘
/相除
%求余

如何判断一个整型数字是奇数还是偶数?

4.5.2、关系运算符

运算符描述
==检查两个值是否相等,如果相等返回 True 否则返回 False。
!=检查两个值是否不相等,如果不相等返回 True 否则返回 False。
>检查左边值是否大于右边值,如果是返回 True 否则返回 False。
<检查左边值是否小于右边值,如果是返回 True 否则返回 False。
>=检查左边值是否大于等于右边值,如果是返回 True 否则返回 False。
<=检查左边值是否小于等于右边值,如果是返回 True 否则返回 False。

4.5.3、逻辑运算符

运算符描述
&&逻辑 AND 运算符。 如果两边的操作数都是 True,则条件 True,否则为 False。
||逻辑 OR 运算符。 如果两边的操作数有一个 True,则条件 True,否则为 False。
!逻辑 NOT 运算符。 如果条件为 True,则逻辑 NOT 条件 False,否则为 True。
     fmt.Println(2.1 > 1 || 3 == 2)
	// 用户名为root或者年龄大于18岁
	username := "root"
	age := 16
	ret := username == "root" || !(age < 18)
	fmt.Println(ret)

4.5.4、赋值运算符

运算符描述
=简单的赋值运算符,将一个表达式的值赋给一个左值
+=相加后再赋值
-=相减后再赋值
*=相乘后再赋值
/=相除后再赋值
%=求余后再赋值
<<=左移后赋值
>>=右移后赋值
&=按位与后赋值
^=按位异或后赋值
|=按位或后赋值
++自增
自减
     var a = 10
	// 使a自加1
	ret := a + 1
	a = ret
	// 使a自加1
	a = a + 1
	// 使a自加1
	a += 1 // 赋值元算符
	// 使a自加1
	a++ // 注意:不能写成 ++ a 或 -- a 必须放在右边使用
	// b := a++ // 此处为错误的用法,不能写在一行,要单独作为语句使用
	fmt.Println(a)

4.5.5、运算符优先级

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-U9V0SjdX-1659228427113)(assets/youxianji.png)]


    // 案例1
    var a, b, c, d = 8, 6, 4, 2
	ret := a + b*c/d
	fmt.Println(ret)
     // 案例2
     x := 10
	y := 1
	x += 5*(1+2) + y
	fmt.Println(x)
	z := 1+2 > 3 || 1 == 1*5
	fmt.Println(z)

为什么x = 1+1, 为什么先计算后赋值:运算符的优先级

4.6、输入输出函数

4.6.1、输出函数

fmt.Print有几个变种:

Print: 输出到控制台,不接受任何格式化操作
Println: 输出到控制台并换行
Printf : 只可以打印出格式化的字符串,只可以直接输出字符串类型的变量(不可以输出别的类型)
Sprintf:格式化并返回一个字符串而不带任何输出

(1)Print 和Println

Print和Println()函数可以打印出字符串或变量的值。

    name := "yuan"
	age := 24

	fmt.Print(name, age)

	fmt.Println("hello world")
	fmt.Println(name)
	fmt.Println(age)
	fmt.Println(name, age)
	fmt.Println("姓名:", name, "年龄:", age)
(2)格式化输出(Printf)

Printf 根据格式说明符格式化并写入标准输出。Printf 只打印字符串

比如上面打印一个人的基本信息格式:

     name := "yuan"
	age := 24
	isMarried := false
	salary := 3000.549
	fmt.Printf("姓名:%s 年龄:%d 婚否:%t 薪资:%.2f\n", name, age, isMarried, salary)
	fmt.Printf("姓名:%v 年龄:%v 婚否:%v 薪资:%v\n", name, age, isMarried, salary)
	fmt.Printf("姓名:%#v 年龄:%#v 婚否:%#v 薪资:%#v\n", name, age, isMarried, salary)
%v:以默认的方式打印变量的值
%#v:相应值的Go语法表示
%T:打印对应值的类型
%+d :带符号的整型,%d 不带符号的整型
%o :不带零的八进制,%#o 带零的八进制
%x :小写的十六进制,%X 大写的十六进制,%#x 带0x的十六进制
%b :打印整型的二进制
%t :打印true 或 false
%s :输出字符串表示,%-5s 最小宽度为5(左对齐)
%f 小数点而无指数,默认精度为6
%e 科学计数法,如-1234.456e+78
%p 带0x的指针,%#p 不带0x的指针
// 整形和浮点型
fmt.Printf("%b\n", 12)  // 二进制表示:1100
fmt.Printf("%d\n", 12)  // 十进制表示:12
fmt.Printf("%o\n", 12)  // 八进制表示:14
fmt.Printf("%x\n", 12)  // 十六进制表示:c
fmt.Printf("%X\n", 12)  // 十六进制表示:c
fmt.Printf("%f\n", 3.1415)  // 有小数点而无指数:3.141500
fmt.Printf("%.3f\n", 3.1415)  // 3.142
fmt.Printf("%e\n", 1000.25)  // 科学计数法:  1.000250e+03,默认精度为6

// 设置宽度
fmt.Printf("学号:%s 姓名:%-20s 平均成绩:%-4d\n", "1001", "alvin", 100)
fmt.Printf("学号:%s 姓名:%-20s 平均成绩:%-4d\n", "1002", "zuibangdeyuanlaoshi", 98)
fmt.Printf("学号:%s 姓名:%-20s 平均成绩:%-4d\n", "1003", "x", 78)

(3)Sprintf

Printf和Sprintf都是替换字符串,Printf是直接输出到终端,Sprintf是不直接输出到终端,而是返回该字符串

     name := "yuan"
	age := 24
	isMarried := false
	salary := 3000.549
	info := fmt.Sprintf("姓名:%s 年龄:%d 婚否:%t 薪资:%.2f\n", name, age, isMarried, salary)
	fmt.Println(info)

4.6.2、输入函数

go语言fmt包下有三个函数,可以在程序运行过程中从标准输入获取用户的输入:

(1)fmt.Scan

语法:

func Scan(a ...interface{}) (n int, err error)
  • Scan 从标准输入扫描文本,读取由空白符分隔的值保存到传递给本函数的参数中,换行符视为空白符。
  • 本函数返回成功扫描的数据个数和遇到的任何错误。如果读取的数据个数比提供的参数少,会返回一个错误报告原因。
package main

import "fmt"

func main() {
	var (
		name      string
		age       int
		isMarried bool
	)
	fmt.Scan(&name, &age, &isMarried) // 输入类型不一致,按默认值
	fmt.Printf("扫描结果 name:%s age:%d married:%t\t", name, age, isMarried)
}

将上述代码在终端运行,在终端依次输入 yuan 、26、false使用空格分隔。

go run main.go
yuan 26 false
扫描结果 name:yuan age:26 married:false

fmt.Scan从标准输入中扫描用户输入的数据,将以空白符分隔的数据分别存入指定的参数中。

(2)fmt.Scanf

语法

func Scanf(format string, a ...interface{})(n int, err error)
  • Scanf从标准输入扫描文本,根据format参数指定的格式去读取由空白符分隔的值保存到传递给本函数的参数中。
  • 本函数返回成功扫描的数据个数和遇到的任何错误。
// 案例1
var (
		name      string
		age         int
		isMarried bool
	)
fmt.Scanf("1:%s 2:%d 3:%t", &name,&age,&isMarried)
fmt.Printf("扫描结果 姓名:%s 年龄:%d 婚否:%t", name,age,isMarried)

// 案例2
var a, b int
fmt.Scanf("%d+%d", &a, &b)
fmt.Println(a + b)
(3)fmt.Scanln

语法

func Scanln(a ...interface{}) (n int, err error)
  • Scanln类似于Scan,它遇到换行立即停止扫描。
  • 本函数返回成功扫描的数据个数和遇到的任何错误。

Scanln和Scan的区别就是Scanln遇到换行立即结束输入,而Scan则会将换行符作为一个空白符继续下一个输入

4.7、常量与itoa

4.7.1 常量

常量是⼀个简单值的标识符,在程序运⾏时,不会被修改的量。
在Python、Java编程规范中,常量⼀般都是全⼤写字母,但是在Golang中,⼤⼩写是具有⼀定特殊含义的,所以不⼀定所有常量都得全⼤写。

声明赋值方式与变量接近,通过const实现

const 常量名[数据类型] = value

数据类型可以忽略不写,Golang编译器会⾃动推断出数据类型。
在使⽤时,要注意以下⼏点:

  1. 数据类型只可以是布尔型、数字型(整数型、浮点型和复数)和字符串型
  2. 满⾜多重赋值
  3. 常量只定义不使⽤,编译不会报错
  4. 常量可以作为枚举,常量组
  5. 常量组中如不指定类型和初始化值,则与上⼀⾏⾮空常量右值相同
  6. 显⽰指定类型的时候,必须确保常量左右值类型⼀致,需要时可做显⽰类型转换。
     // (1)声明常量
	const pai = 3.1415926
	const e float64 = 2.7182818
	fmt.Println(pai * pai)

	// (2)常量也可以和变量一样一组一起声明
	// const monday, tuesday, wednesday = 1, 2, 3
	// 更推荐下面这种方式
	const (
		monday    = 1
		tuesday   = 2
		wednesday = 3
		thursday  = 4
		friday    = 5
		saturday  = 6
		sunday    = 7
	)

	const (
		female = 0
		male   = 1
	)

	// ⼀组常量中,如果某个常量没有初始值,默认和上⼀⾏⼀致

	const (
		a int = 1
		b
		c = 2
		d
	)
	fmt.Println(a, b, c, d)

4.7.2 iota计数器

iota是go语言的常量计数器,只能在常量的表达式中使用。 使用iota时只需要记住以下两点

1.iotaconst关键字出现时将被重置为0。

2.const中每新增一行常量声明将使iota计数一次(iota可理解为const语句块中的行索引)。

const (
		food = iota
		cloth
		bed
		electric
	)

	fmt.Println(food, cloth, bed, electric)

	const (
		a = 1
		b = iota
		c = 6
		d
		e = iota
		f
	)

	fmt.Println(a, b, c, d, e, f)

const (
		b  = 1 << (iota * 10)
		kb 
		mb 
		gb 
		tb
		pb 
	)
fmt.Println(b, kb, mb, gb, tb, pb)

思考题:

const (
		n1 = iota
		n2
		_
		n4
	)
const (
		a = iota
		b
		_
		c, d = iota + 1, iota + 2
		e    = iota
	)
fmt.Println(a, b, c, d, e)

五、流程控制语句

程序是由语句构成,而流程控制语句 是用来控制程序中每条语句执行顺序的语句。可以通过控制语句实现更丰富的逻辑以及更强大的功能。几乎所有编程语言都有流程控制语句,功能也都基本相似。

其流程控制方式有

  • 顺序结构
  • 分支结构
  • 循环结构

这里最简单最常用的就是顺序结构,即语句从上至下一一执行。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VJViPpdL-1659228427113)(assets/image-20210318154636648.png)]

5.1、分支语句

顺序结构的程序虽然能解决计算、输出等问题,但不能做判断再选择。对于要先做判断再选择的问题就要使用分支结构。

5.1.1、单分支语句

语法:

if 布尔表达式 {  // 注意左花括号必须与表达式同行
   /* 在布尔表达式为 true 时执行 */
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YLUqxaWB-1659228427114)(assets/image-20211216155050847-16396410524811.png)]

var username,password string

fmt.Print("请输入用户名:")
fmt.Scanln(&username)
fmt.Println("username",username)

fmt.Print("请输入密码:")
fmt.Scanln(&password)
fmt.Println("password",password)

if username == "yuan" && password=="123"{
    fmt.Println("登录成功!")
}

5.1.2、双分支语句

双分支语句顾名思义,二条分支二选一执行!

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3viDk1FO-1659228427114)(assets/image-20210318171626403.png)]

var username,password string
fmt.Print("请输入用户名:")
fmt.Scanln(&username)
fmt.Println("username",username)

fmt.Print("请输入密码:")
fmt.Scanln(&password)
fmt.Println("password",password)

if username == "yuan" && password=="123"{
    fmt.Println("登录成功!")
}else {
    fmt.Println("用户名或者密码错误!")
}

5.1.3、if多分支语句

多分支即从比双分支更多的分支选择一支执行。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EBeXlO7V-1659228427114)(assets/image-20210318173151614.png)]

package main

import "fmt"

func main() {
	var score int
	fmt.Scanln(&score)
	if score > 100 && score < 0 {
		fmt.Println("输入数字应该在1-100之间")
	} else if score > 90 {
		fmt.Println("成绩优秀!")
	} else if score > 80 {
		fmt.Println("成绩良好!")
	} else if score > 60 {
		fmt.Println("成绩及格!")
	} else {
		fmt.Println("请输入一个数字!")
	}
}

不管多少条分支只能执行一条分支!

练习:根据用户输入的生日判断星座

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oKlKvh5Z-1659228427115)(assets/image-20220106172826024-16414613080351.png)]

var birth string
fmt.Print("请输入你的生日(格式如2000-3-16):")
fmt.Scanln(&birth)
fmt.Println("birth",birth)
birth_arr := strings.Split(birth,"-")
month := birth_arr[1]
day := birth_arr[2]

var date  = month + "." + day
date_float,_ := strconv.ParseFloat(date,64)

if date_float>=3.21 && date_float <=4.19{
    fmt.Println("您是白羊座")
}else if date_float >=4.20 && date_float<=5.20{
    fmt.Println("您是金牛座")
}else if date_float >=5.21 && date_float<=6.21{
    fmt.Println("您是双子座")
}else if date_float >=6.22 && date_float<=7.22{
    fmt.Println("您是巨蟹座")
}else if date_float >=7.23 && date_float<=8.22{
    fmt.Println("您是狮子座")
}else if date_float >=8.23 && date_float<=9.22{
    fmt.Println("您是处女座")
}else if date_float >=9.23 && date_float<=10.23{
    fmt.Println("您是天秤座")
}else if date_float >=10.24 && date_float<=11.22{
    fmt.Println("您是天蝎座")
}else if date_float >11.23 && date_float<=12.21{
    fmt.Println("您是射手座")
}else if date_float >12.22 && date_float<=1.19{
    fmt.Println("您是魔羯座")
}else if date_float >2.19 && date_float<=3.20{
    fmt.Println("您是双鱼座")
}else{
    fmt.Println("您不是人!")
}

5.1.4、switch多分支语句

语法:

switch var {
    case val1:
        ...
    case val2:
        ...
    default:
        ...
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mgU7B8yF-1659228427115)(assets/image-20210319120205199.png)]

switch语句也是多分支选择语句,执行哪一代码块,取决于switch后的值与哪一case值匹配成功,则执行该case后的代码块。

/*
给出如下选项,并根据选项进行效果展示:
    输入1:则输出"普通攻击"
    输入2:则输出"超级攻击"
    输入3:则输出"使用道具"
    输入3:则输出"逃跑"
*/

var choice int
fmt.Println("请输入选择:")
fmt.Scanln(&choice)
//fmt.Println(choice,reflect.TypeOf(choice))

switch choice {
     case 1:fmt.Println("普通攻击")
	case 2:fmt.Println("超级攻击")
	case 3:fmt.Println("使用道具")
	case 4:fmt.Println("逃跑")
	default:fmt.Println("输入有误!")
}
 

1、switch比if else更为简洁

2、执行效率更高。switch…case会生成一个跳转表来指示实际的case分支的地址,而这个跳转表的索引号与switch变量的值是相等的。从而,switch…case不用像if…else那样遍历条件分支直到命中条件,而只需访问对应索引号的表项从而到达定位分支的目的。

3、到底使用哪一个选择语句,代码环境有关,如果是范围取值,则使用if else语句更为快捷;如果是确定取值,则使用switch是更优方案。

switch同时支持多条件匹配:

switch{
    case 1,2:
    default:
}

练习:将星座判断改为switch版本

5.1.5、分支嵌套

// 分支嵌套
    var user string
	var pwd int

	fmt.Printf("请输入用户名:")
	fmt.Scanln(&user)
	fmt.Printf("请输入密码:")
	fmt.Scanln(&pwd)

	if user == "yuan" && pwd==123{
		var score int
		fmt.Printf("请输入成绩:")
		fmt.Scanln(&score)

		if score >= 90 && score<=100 {
			fmt.Println("成绩优秀!")
		} else if score >= 80 {
			fmt.Println("成绩良好!")
		} else if score >= 60 {
			fmt.Println("成绩及格")
		} else {
			fmt.Println("不及格!")
		}

	}else {
		fmt.Println("用户名或者密码错误!")
	}

5.2、循环语句

在不少实际问题中有许多具有规律性的重复操作,因此在程序中就需要重复执行某些语句。一组被重复执行的语句称之为循环体,能否继续重复,决定循环的终止条件。

与其它主流编程语言不同的的是,Go语言中的循环语句只支持 for 关键字,而不支持 while 和 do-while 结构。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PYGPveSG-1659228427115)(assets/image-20210319125002230.png)]

5.2.1、for循环

原始for循环

通过关系表达式或逻辑表达式控制循环

for  condition { }

简单循环案例:

count := 0   // 初始化语句
for count<10 {   // 条件判断
    fmt.Println(count)
    count ++  //  步进语句
}

无限循环案例:

/*
无限循环
for true{
	  
	}
*/

// 循环中嵌入分支语句
func main() {
	fmt.Printf(`
	1、普通攻击
	2、超级攻击
	3、使用道具
	4、逃跑
`)
	for true {
		var choice int
		fmt.Printf("请输入选择:")
		fmt.Scanln(&choice)
		//fmt.Println(choice,reflect.TypeOf(choice))

		switch choice {
		case 1:
			fmt.Println("普通攻击")
		case 2:
			fmt.Println("超级攻击")
		case 3:
			fmt.Println("使用道具")
		case 4:
			fmt.Println("逃跑")
		default:
			fmt.Println("输入有误!")
		}
	}
}

三要素for循环(核心)

将初始化语句、条件判断以及步进语句格式固定化的循环方式,本质上和上面的for循环没有区别。

for init;condition;post { 
    // 循环体语句
}
  • init: 初始化语句,一般为赋值表达式,给控制变量赋初值;

  • condition:条件判断,一般是关系表达式或逻辑表达式,循环控制条件;

  • post: 步进语句,一般为赋值表达式,给控制变量增量或减量。

for i := 1; i < 10; i++ {
		fmt.Println(i)
	}

执行流程:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nTKJXsKe-1659228427116)(assets/image-20210319143615065.png)]

遍历for循环
// 遍历字符串
hello := "HelloYuan"
for k, v := range hello {
    fmt.Printf("%d,%c\n", k, v)
}

案例:计算1-100的和

var x  = 0
x += 1
x += 2
x += 3
x += 4
x += 5
x += 6
x += 7
x += 8
x += 9
x += 10
fmt.Println(x)

// 如果是1+2+3+....100呢?如何借助循环语法实现
var ret = 0
for i := 1; i <= 100; i++ {
    ret += i
}
fmt.Println(ret)

5.2.2、退出循环

如果想提前结束循环(在不满足结束条件的情况下结束循环),可以使用break或continue关键字。

break

当 break 关键字用于 for 循环时,会终止循环而执行整个循环语句后面的代码。break 关键字通常和 if 语句一起使用,即满足某个条件时便跳出循环,继续执行循环语句下面的代码。

for i := 0; i < 10; i++ {
		if i==8{
			break
		}
		fmt.Println(":",i)
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DF0evyTV-1659228427116)(assets/image-20210319143907273.png)]

continue

不同于break退出整个循环,continue指的是退出当次循环。

for i := 0; i < 10; i++ {
		if i==8{
			continue
		}
		fmt.Println(":",i)
	}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AZChbEFS-1659228427116)(assets/image-20210319144123476.png)]

5.2.3、循环嵌套

在一个循环体语句中又包含另一个循环语句,称为循环嵌套

独立嵌套

在控制台上打印一个五行五列的矩形,如下图所示

*****
*****
*****
*****
*****
for i := 0; i < 5; i++ {
    
    for j:=0;j<5;j++ {
        fmt.Print("*")
    }
    fmt.Print("\n")
}
关联嵌套

在控制台上打印一个如下图所示的三角形

*
**
***
****
*****
for i := 0; i < 5; i++ {
    for j := 0; j <= i; j++ {
        fmt.Printf("*")
    }
    fmt.Println()
}

5.3、练习题

/*

(1) 计算 1 - 2 + 3 - 4 + ... + 99 中除了88以外所有数的总和?

(2) 求1+2!+3!+4!+……+10!的和

(3) 程序随机内置一个位于一定范围内的数字作为猜测的结果,由用户猜测此数字。用户每猜测一次,由系统提示猜测结果:太大了、太小了或者猜对了,直到用户猜对结果或者猜测次数用完导致失败。设定一个理想数字比如:66,让用户三次机会猜数字,如果比66大,则显示猜测的结果大了;
如果比66小,则显示猜测的结果小了;只有等于66,显示猜测结果正确,退出循环。最多三次都没有猜测正确,退出循环,并显示‘都没猜对,继续努力’。

(4) 计算索引为10的斐波那契数列对应的值(斐波那契数列指的是一个数列 0, 1, 1, 2, 3, 5, 8, 13,特别指出:第0项是0,第1项是第一个1。从第三项开始,每一项都等于前两项之和)


#### 遍历for循环

```go
// 遍历字符串
hello := "HelloYuan"
for k, v := range hello {
    fmt.Printf("%d,%c\n", k, v)
}

案例:计算1-100的和

var x  = 0
x += 1
x += 2
x += 3
x += 4
x += 5
x += 6
x += 7
x += 8
x += 9
x += 10
fmt.Println(x)

// 如果是1+2+3+....100呢?如何借助循环语法实现
var ret = 0
for i := 1; i <= 100; i++ {
    ret += i
}
fmt.Println(ret)

5.2.2、退出循环

如果想提前结束循环(在不满足结束条件的情况下结束循环),可以使用break或continue关键字。

break

当 break 关键字用于 for 循环时,会终止循环而执行整个循环语句后面的代码。break 关键字通常和 if 语句一起使用,即满足某个条件时便跳出循环,继续执行循环语句下面的代码。

for i := 0; i < 10; i++ {
		if i==8{
			break
		}
		fmt.Println(":",i)
}

[外链图片转存中…(img-DF0evyTV-1659228427116)]

continue

不同于break退出整个循环,continue指的是退出当次循环。

for i := 0; i < 10; i++ {
		if i==8{
			continue
		}
		fmt.Println(":",i)
	}

[外链图片转存中…(img-AZChbEFS-1659228427116)]

5.2.3、循环嵌套

在一个循环体语句中又包含另一个循环语句,称为循环嵌套

独立嵌套

在控制台上打印一个五行五列的矩形,如下图所示

*****
*****
*****
*****
*****
for i := 0; i < 5; i++ {
    
    for j:=0;j<5;j++ {
        fmt.Print("*")
    }
    fmt.Print("\n")
}
关联嵌套

在控制台上打印一个如下图所示的三角形

*
**
***
****
*****
for i := 0; i < 5; i++ {
    for j := 0; j <= i; j++ {
        fmt.Printf("*")
    }
    fmt.Println()
}

5.3、练习题

/*

(1) 计算 1 - 2 + 3 - 4 + ... + 99 中除了88以外所有数的总和?

(2) 求1+2!+3!+4!+……+10!的和

(3) 程序随机内置一个位于一定范围内的数字作为猜测的结果,由用户猜测此数字。用户每猜测一次,由系统提示猜测结果:太大了、太小了或者猜对了,直到用户猜对结果或者猜测次数用完导致失败。设定一个理想数字比如:66,让用户三次机会猜数字,如果比66大,则显示猜测的结果大了;
如果比66小,则显示猜测的结果小了;只有等于66,显示猜测结果正确,退出循环。最多三次都没有猜测正确,退出循环,并显示‘都没猜对,继续努力’。

(4) 计算索引为10的斐波那契数列对应的值(斐波那契数列指的是一个数列 0, 1, 1, 2, 3, 5, 8, 13,特别指出:第0项是0,第1项是第一个1。从第三项开始,每一项都等于前两项之和)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值