零基础!!1小时学会跨时代的一门新语言 《建议收藏》
Posted @了凡
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了零基础!!1小时学会跨时代的一门新语言 《建议收藏》相关的知识,希望对你有一定的参考价值。
前言
博主介绍:
– 本人是了凡,意思为希望本人任何时候以善良为先,以人品为重,喜欢了凡四训中的立命之学、改过之法、积善之方、谦德之效四训,更喜欢每日在简书上投稿每日的读书感悟笔名:三月_刘超。专注于 Go Web 后端,辅学Python、Java、算法、前端等领域。
文章目录
引言
官方解释语言来历
很久以前,有一个IT公司,这公司有个传统,允许员工拥有20%自由时间来开发实验性项目。在2007的某一天,公司的几个大牛,正在用c++开发一些比较繁琐但是核心的工作,主要包括庞大的分布式集群,大牛觉得很闹心,后来c++委员会来他们公司演讲,说c++将要添加大概35种新特性。这几个大牛的其中一个人,名为:Rob Pike,听后心中一万个xxx飘过,“c++特性还不够多吗?简化c++应该更有成就感吧”。于是乎,Rob Pike和其他几个大牛讨论了一下,怎么解决这个问题,过了一会,Rob Pike说要不我们自己搞个语言吧,名字叫“go”,非常简短,容易拼写。其他几位大牛就说好啊,然后他们找了块白板,在上面写下希望能有哪些功能(详见文尾)。接下来的时间里,大牛们开心的讨论设计这门语言的特性,经过漫长的岁月,他们决定,以c语言为原型,以及借鉴其他语言的一些特性,来解放程序员,解放自己,然后在2009年,go语言诞生。
主要特征
1.自动立即回收
2.更丰富的内置类型
3.函数多返回值
4.错误处理
5.匿名函数和闭包
6.类型和接口
7.并发编程
8.反射
9.语言交互性
10.既面向过程也面向对象
优点
自带gc。
静态编译,编译好后,扔服务器直接运行。
简单的思想,没有继承,多态,类等。
丰富的库和详细的开发文档。
语法层支持并发,和拥有同步并发的channel类型,使并发开发变得非常方便。
简洁的语法,提高开发效率,同时提高代码的阅读性和可维护性。
超级简单的交叉编译,仅需更改环境变量。
Go 语言是谷歌 2009 年首次推出并在 2012 年正式发布的一种全新的编程语言,可以在不损失应用程序性能的情况下降低代码的复杂性。谷歌首席软件工程师罗布派克(Rob Pike)说:我们之所以开发 Go,是因为过去10多年间软件开发的难度令人沮丧。Google 对 Go 寄予厚望,其设计是让软件充分发挥多核心处理器同步多工的优点,并可解决面向对象程序设计的麻烦。它具有现代的程序语言特色,如垃圾回收,帮助开发者处理琐碎但重要的内存管理问题。Go 的速度也非常快,几乎和 C 或 C++ 程序一样快,且能够快速开发应用程序。
最大优点
Go语言为并发而生:
Go语言的并发是基于 goroutine 的,goroutine 类似于线程,但并非线程。可以将 goroutine 理解为一种虚拟线程。Go 语言运行时会参与调度 goroutine,并将 goroutine 合理地分配到每个 CPU 中,最大限度地使用CPU性能。开启一个goroutine的消耗非常小(大约2KB的内存),你可以轻松创建数百万个goroutine。
goroutine的特点:
具有可增长的分段堆栈。意味着它们只在需要时才会使用更多内存。
goroutine的启动时间比线程快。
goroutine原生支持利用channel安全地进行通信。
goroutine共享数据结构时无需使用互斥锁。
准备学习前讲解
语言IDE编辑器安装包及开发环境(全套)
链接:https://pan.baidu.com/s/18di4xhP-rvCt0xHeJkV15A
提取码:AAAA
安装教程讲解
参考:https://www.jb51.net/article/200627.htm
语言结构
基础组成有以下几个部分:
包声明
package main // 以 package 关键字作为包声明 后面加上当前包名
引入包
import "fmt" // 以 import 关键字作为引入包 后面加上要引入的包名 这里暂时举例fmt 数据格式化包为举例,后序讲解具体用法
函数
func main() {} // 以 func 关键字作为声明函数或者方法 后面跟你要声明的函数名或者方法名
变量
var a string = "hello" // 这里先声明一个字符串格式的 hello 后面细节讲解
语句 & 表达式
if 布尔表达式 {
/* 在布尔表达式为 true 时执行 */
} // 这里暂时举例一种表达式为 if 语句 后面分别讲解 if、for、goto、switch...
注释
/*...*/ // 多行注释
// // 单行注释
语言基础语法
语法简讲
fmt.Println("Hello, World!")
上述代码分别是由关键字,标识符,常量,字符串,符号组成
1. fmt // 关键字
2. . // 标识符
3. Println // 关键字
4. ( // 符号
5. "Hello, World!" // 字符串
6. ) // 符号
分割
go的多行数书写不需要用 ; 分号做间隔像C语言一样书写 和 Python 写法有一点相似
注释
注释不会被编译
单行注释用// 进行注释
// 单行注释
多行注释用/* */进行注释
/*
多行注释
*/
标识符
标识符用来命名变量、类型等程序实体
不能以数字开头、不能是Go 语言的关键字、不能用运算符
举例:
1ab 以数字开头
func 是Go 语言的关键字
a+b 用运算符
关键字
25 个关键字或保留字:
还有 36 个预定义标识符:
语法之变量
变量初始化
单个初始化
var 变量名 类型 = 表达式
多个初始化
var 变量名1, 变量名2 = 表示式1, 表达式2
变量声明
单个声明
var 变量名 变量类型
// 例如:
var a string = "hello" // 声明一个名叫做 a 字符串类型的变量
多个声明
var (
one string // 声明一个名叫做 one 字符串类型的变量
two int // 声明一个名叫做 two 整型类型的变量
three bool // 声明一个名叫做 three 布尔类型的变量
)
全局声明
在程序的任意一行代码都可以引用的变量
局部声明
函数内部,可以使用更简略的 := 方式声明并初始化变量
举例:
package main
import (
"fmt"
)
// 全局变量
var All = 10
func main() {
n := 30
toPo := 20 // 局部变量
fmt.Println(toPo, n)
}
打印结果:
常量声明
单个常量声明
count a string = "hello" // 声明一个名叫做 a 字符串类型的常量
多个常量声明
count (
one string // 声明一个名叫做 one 字符串类型的常量
two int // 声明一个名叫做 two 整型类型的常量
three bool // 声明一个名叫做 three 布尔类型的常量
)
匿名变量
如果想要忽略某一个返回值的时候可以使用以_下划线符号来做匿名变量返回值
例如:
package main
import "fmt"
func fun1()(int, int) {
return 1, 2
}
func main() {
_, b := fun1() // 这里使用匿名返回值,对1返回值进行忽略掉
fmt.Println(b)
}
打印结果:
iota
iota 是一个常量计数器
目前没有发现什么大的用处
具体可以看:https://segmentfault.com/a/1190000023532777
语法之数据类型
整型
普通整型
普通整型:uint8 无符号 8位整型 (0 到 255) int8 有符号 8位整型 (-128 到 127)
特殊整型
特殊整型:uint 32位操作系统上就是uint32,64位操作系统上就是uint64 int 32位操作系统上就是int32,64位操作系统上就是int64 uintptr 无符号整型,用于存放一个指针
注意: 在使用int和 uint类型时,不能假定它是32位或64位的整型,而是考虑int和uint可能在不同平台上的差异。
进制表示
二进制: v := 0b00101101, 代表二进制的 101101,相当于十进制的 45
八进制:v := 0o377,代表八进制的 377,相当于十进制的 255
十进制: 不做改变
十六进制:v := 0x1p-2,代表十六进制的 1 除以 2²,也就是 0.25
而用 _ 来分隔数字,比如说: v := 123_456 表示 v 的值等于 123456
浮点型
float32
float32 的浮点数的最大范围约为 3.4e38,可以使用常量定义:math.MaxFloat32
float64
float64 的浮点数的最大范围约为 1.8e308,可以使用一个常量定义:math.MaxFloat64
复数
复数有实部和虚部,complex64的实部和虚部为32位,complex128的实部和虚部为64位。
布尔值
两种状态:
以bool类型进行声明布尔型数据,布尔型数据只有true(真)和false(假)两个值
注意
1.布尔类型变量默认值为false。
2.不允许将整型强制转换为布尔型。
3.布尔型无法参与数值运算,也无法与其他类型进行转换。
字符串
单行声明
s1 := "hello"
多行声明
使用反引号字符 列如:
s1 := `第一行
第二行
第三行
`
注意:反引号间换行将被作为字符串中的换行,但是所有的转义字符均无效,文本将会原样输出
字符串必会:
字符串的内部实现使用UTF-8编码
— — — — — —
求长度:
len(str)
— — — — — —
拼接字符串
+或fmt.Sprintf
— — — — — —
分割
strings.Split
— — — — — —
判断是否包含
strings.contains
— — — — — —
前缀/后缀判断
strings.HasPrefix,strings.HasSuffix
— — — — — —
子串出现的位置
strings.Index(),strings.LastIndex()
— — — — — —
join操作
strings.Join(a[]string, sep string)
byte和rune类型
byte 类型
uint8类型,或者叫 byte 型,代表了ASCII码的一个字符
Go 使用了特殊的 rune 类型来处理 Unicode,让基于 Unicode 的文本处理更为方便,也可以使用 byte 型进行默认字符串处理,性能和扩展性都有照顾
rune 类型
rune类型,代表一个 UTF-8字符
需要处理中文、日文或者其他复合字符时,则需要用到rune类型。rune类型实际是一个int32
字符串底层是一个byte数组,所以可以和[]byte类型相互转换。字符串是不能修改的 字符串是由byte字节组成,所以字符串的长度是byte字节的长度。 rune类型用来表示utf8字符,一个rune字符由一个或多个byte组成
结论:rune比byte大
类型转换
Go语言中只有强制类型转换,没有隐式类型转换。该语法只能在两个类型之间支持相互转换的时候使用
格式:T(表达式)
T表示要转换的类型。表达式包括变量、函数返回值等
实战
编写代码统计出字符串"hello沙河小王子"中汉字的数量。
答案:
package main
import "fmt"
func main() {
a := 0
s1 := "hello沙河小王子"
for _, i := range s1 {
if i > 'z' {
a ++
}
}
fmt.Println(a)
}
运行结果:
语法之运算符
算数运算符
+
相加
-
相减
*
相乘
/
相除
%
求余
++
(自增)和--
(自减)在Go语言中是单独的语句,并不是运算符,Go语言中只可以后--
不可以前--
,++
也一样
关系运算符
==
检查两个值是否相等,如果相等返回 True 否则返回 False。
!=
检查两个值是否不相等,如果不相等返回 True 否则返回 False。
>
检查左边值是否大于右边值,如果是返回 True 否则返回 False。
>=
检查左边值是否大于等于右边值,如果是返回 True 否则返回 False。
<
检查左边值是否小于右边值,如果是返回 True 否则返回 False。
<=
检查左边值是否小于等于右边值,如果是返回 True 否则返回 False。
逻辑运算符
&&
逻辑 AND 运算符,如果两边的操作数都是 True,则为 True,否则为False。
||
逻辑 OR 运算符, 如果两边的操作数有一个 True,则为 True,否则为 False。
!
逻辑 NOT 运算符, 如果条件为 True,则为 False,否则为 True。
位运算符
&
参与运算的两数各对应的二进位相与。(两位均为1才为1)
|
参与运算的两数各对应的二进位相或。(两位有一个为1就为1)
^
参与运算的两数各对应的二进位相异或,当两对应的二进位相异时,结果为1。(两位不一样则为1)
<<
左移n位就是乘以2的n次方。“a<<b”是把a的各二进位全部左移b位,高位丢弃,低位补0。
>>
右移n位就是除以2的n次方。“a>>b”是把a的各二进位全部右移b位。
赋值运算符
=
简单的赋值运算符,将一个表达式的值赋给一个左值
+=
相加后再赋值
-=
相减后再赋值
*=
相乘后再赋值
/=
相除后再赋值
%=
求余后再赋值
<<=
左移后赋值
>>=
右移后赋值
&=
按位与后赋值
|=
按位或后赋值
^=
按位异或后赋值
实战
有一堆数字,如果除了一个数字以外,其他数字都出现了两次,那么如何找到出现一次的数字?
答案:
package main
import "fmt"
func main() {
var nums = []int {5,7,8,8,9,7,9}
i := 0
for j := 0; j < len(nums); j ++ {
i = i ^ nums[j]
}
fmt.Println(i)
}
执行结果
语法之流程控制
if else(分支结构)
基础写法:
if 表达式1 {
分支1
} else if 表达式2 {
分支2
} else{
分支3
}
规定与if/else匹配的左括号{必须与if/else和表达式放在同一行,{放在其他位置会触发编译错误
特殊写法
if条件判断还有一种特殊的写法,可以在 if 表达式之前添加一个执行语句,再根据变量值进行判断
for(循环结构)
Go 语言中的所有循环类型均可以使用for关键字来完成
基础写法
for 初始语句;条件表达式;结束语句{
循环体语句
}
初始语句,条件表达式,结束语句三者都可以省略,也可以理解为单独的三个部分
无限循环
for循环可以通过break、goto、return、panic语句强制退出循环,也可以配合goto,return,panic完成其他事情,不一定非要死循环中使用
for range(热键循环)
for range遍历数组、切片、字符串、map 及通道(channel)。
数组、切片、字符串返回索引和值。
map返回键和值。
通道(channel)只返回通道内的值。
switch case(分支结构)
使用switch语句可方便地对大量的值进行条件判断
Go语言规定每个switch只能有一个default分支
一个分支可以有多个值,多个case值中间使用英文逗号分隔
switch n := 7; n {
case 1, 3, 5, 7, 9:
fmt.Println("奇数")
分支还可以使用表达式,这时候switch语句后面不需要再跟判断变量
age := 30
switch {
case age < 25:
fmt.Println("你的年龄是",age,"岁")
fallthrough语法可以执行满足条件的case的下一个case,是为了兼容C语言中的case设计的
举例:
package main
import "fmt"
func main() {
s := "a"
switch {
case s == "a":
fmt.Println("a")
fallthrough
case s == "b":
fmt.Println("b")
}
}
运行结果
goto(跳转到指定标签)
goto语句通过标签进行代码间的无条件跳转。goto语句可以在快速跳出循环、避免重复退出上有一定的帮助。Go语言中使用goto语句能简化一些代码的实现过程
举例:
package main
import "fmt"
func main() {
Demo()
}
func Demo() {
for i := 0; i < 10; i++ {
for j := 0; j < 10; j++ {
if j == 2 {
// 设置退出标签
goto breakTag
}
fmt.Printf("%v-%v\\n", i, j)
}
}
return
// 标签
breakTag:
fmt.Println("结束for循环")
}
运行结果
break(结束循环)
break语句可以结束for、switch和select的代码块
break语句还可以在语句后面添加标签,表示退出某个标签对应的代码块,标签要求必须定义在对应的for、switch和 select的代码块上
例如:
package main
import "fmt"
func main() {
Demo()
}
func Demo() {
DEMO:
for i := 0; i < 10; i++ {
for j := 0; j < 10; j++ {
if j == 2 {
break DEMO
}
fmt.Printf("%v-%v\\n", i, j)
}
}
fmt.Println("...")
}
continue(继续下一个循环)
continue语句可以结束当前循环,开始下一次的循环迭代过程,仅限在for循环内使用。
在 continue语句后添加标签时,表示开始标签对应的循环
举例
package main
import "fmt"
func main() {
Demo()
}
func Demo() {
loop:
for i := 0; i < 5; i++ {
for j := 0; j < 5; j++ {
if i == 2 && j == 2 {
continue loop
}
fmt.Printf("%v-%v\\n", i, j)
}
}
}
运行结果
实战
编写代码打印9*9乘法表
答案:
package main
import "fmt"
func main() {
for i := 1; i <= 9; i++ {
for j := 1; j <= i; j++ {
fmt.Printf("%d * %d = %-2d ", i, j, i*j)
}
fmt.Println()
}
}
执行结果
语法之数组
基础语法
// 定义一个长度为6元素类型为int的数组a
var a [6]int
数据定义
var 数组变量名 [元素数量]T
数组的长度必须是常量,并且长度是数组类型的一部分。 [5]int和[10]int是不同的类型。
两种相等类型的数组可以直接交换值
var num = []int {2,3,5}
var nums = []int {3,8,7}
num, nums = nums, num
fmt.Println(num, nums)
数组可以通过下标进行访问,下标是从0开始,最后一个元素下标是:len-1,访问越界(下标在合法范围之外),则触发访问越界,会panic
数组的初始化
方法一:
初始化数组时可以使用初始化列表来设置数组元素的值
//数组会初始化为int类型的零值
var testArray [3]int
//使用指定的初始值完成初始化
var numArray = [3]int{1, 2}
//使用指定的初始值完成初始化
var cityArray = [3]string{"北京", "上海", "深圳"}
方法二:
也可以不写长度,编译器根据初始值的个数自行推断数组的长度
var testArray [3]int
var numArray = [...]int{1, 2}
var cityArray = [...]string{"北京", "上海", "深圳"}
方法三:
可以使用指定索引值的方式来初始化数组
a := [...]int{1: 1, 3: 5}
fmt.Println(a) // [0 1 0 5]
数组初始化后默认是0
数组的遍历
方法一:
// 方法1:for循环遍历
for i := 0; i < len(a); i++ {
fmt.Println(a[i])
}
方法二:
以上是关于零基础!!1小时学会跨时代的一门新语言 《建议收藏》的主要内容,如果未能解决你的问题,请参考以下文章