【GO 开发系列 -- 基础】Go 基础简介
【1】Golang 语言简介
【1.1】GO 语言的定义
Go(又称Golang)是Google开发的一种静态强类型、编译型、并发型,并具有垃圾回收功能的编程语言。
【1.2】GO 语言的特点
Go语言既拥有静态编译语言的安全和性能,又拥有动态语言开发维护的高效率;
静态编译语言 : 静态编译语言是在编译时变量的数据类型即可确定的语言,多数静态类型语言要求在使用变量之前必须声明数据类型;
动态语言 : 动态语言是在运行时确定数据类型的语言,变量使用之前不需要类型声明,通常变量的类型是被赋值的那个值的类型;
- 1. 包含与 C 语言类似的语法、控制结构,基础数据类型,调用参数传值,指针等;
- 2. 引入包的概念,Go语言的每一个文件都属于一个包,不能单独存在;
- 3. 垃圾回收机制,内存自动回收;
- 4. 天然并发;
- (1) 从语言层面支持并发;
- (2) goroutine,轻量级线程,高效利用多核;
- (3) 基于 CPS (Communicating Sequential Processes) 并发模型实现;
- 5. 管道通信机制,通过管道实现不同的 goroute 之间的通信;
- 6. 函数可以返回多个值;
【2】Golang 语言基本语法示例
【2.1】变量
golang 中标识符的使用
package main
import "fmt"
//golang 中标识符的使用
func main() {
//Golang中严格区分大小写
//golang 中 认为 num 和 Num是不同的变量
var num int = 10
var Num int = 20
//输出: num=10 Num=20
fmt.Printf("num=%v Num=%v\n", num, Num)
//标识符不能包含空格
//var ab c int = 30
//_ 是空标志符,用于占用
// var _ int = 40 //error
// fmt.Println(_)
var int int = 90
//输出: 90
fmt.Println(int)
}
golang 中变量的使用
package main
import "fmt"
//golang 中变量的使用
func main() {
//golang的变量使用方式1
//第一种:指定变量类型,声明后若不赋值,使用默认值
// int 的默认值是0 , 其它数据类型的默认值后面马上介绍
var i int
//输出: i= 0
fmt.Println("i=", i)
//第二种:根据值自行判定变量类型(类型推导)
var num = 10.11
//输出: num= 10.11
fmt.Println("num=", num)
//第三种:省略var, 注意 :=左侧的变量不应该是已经声明过的,否则会导致编译错误
//下面的方式等价 var name string name = "tom"
// := 的 :不能省略,否则错误
name := "tom"
//输出: name= tom
fmt.Println("name=", name)
}
package main
import "fmt"
//定义全局变量
var n1 = 100
var n2 = 200
var name = "jack"
//上面的声明方式,也可以改成一次性声明
var (
n3 = 300
n4 = 900
name2 = "mary"
)
func main() {
//该案例演示golang如何一次性声明多个变量
var n5, n6, n7 int
//输出: n5= 0 n6= 0 n7= 0
fmt.Println("n5=", n5, "n6=", n6, "n7=", n7)
//一次性声明多个变量的方式2
var n8, name3, n9 = 100, "tom", 888
//输出: n8= 100 name3= tom n9= 888
fmt.Println("n8=", n8, "name3=", name3, "n9=", n9)
//一次性声明多个变量的方式3, 同样可以使用类型推导
n10, name4, n11 := 100, "tom~", 888
//输出: n10= 100 name4= tom~ n11= 888
fmt.Println("n10=", n10, "name4=", name4, "n11=", n11)
//输出全局变量
//输出: n1= 100 name= jack n2= 200
fmt.Println("n1=", n1, "name=", name, "n2=", n2)
//输出: n3= 300 name2= mary n4= 900
fmt.Println("n3=", n3, "name2=", name2, "n4=", n4)
}
package main
import (
"fmt"
//为了使用utils.go文件的变量或者函数,我们需要先引入该model包
"GO_LEARN_CODE/chapter03/demo04/model"
)
//变量使用的注意事项
func main() {
//该区域的数据值可以在同一类型范围内不断变化
var i int = 10
i = 30
i = 50
//输出: i= 50
fmt.Println("i=", i)
//i = 1.2 //int ,原因是不能改变数据类型
//变量在同一个作用域(在一个函数或者在代码块)内不能重名
//var i int = 59
//i := 99
//我们使用 utils.go 的 heroName 包名.标志符
//输出: 宋江
fmt.Println(model.HeroName)
}
package model
//定义了一个变量
var HeroName string = "宋江"
golang 中整数类型使用
package main
// import "fmt"
// import "unsafe"
import (
"fmt"
"unsafe"
)
// golang 中整数类型使用
func main() {
var i int = 1
//输出: i= 1
fmt.Println("i=", i)
//测试一下 int8 的范围 -128~127,
//其它的 int16, int32, int64, 类推 ...
var j int8 = 127
//输出: j= 127
fmt.Println("j=", j)
//测试一下 uint8 的范围(0-255),其它的 uint16, uint32, uint64 类推即可
var k uint16 = 255
// 输出: k= 255
fmt.Println("k=", k)
//int , uint , rune , byte的使用
var a int = 8900
//输出: a= 8900
fmt.Println("a=", a)
var b uint = 1
var c byte = 255
//输出: b= 1 c= 255
fmt.Println("b=", b, "c=", c)
//整型的使用细节
var n1 = 100 // n1 是什么类型
//这里我们给介绍一下如何查看某个变量的数据类型
//fmt.Printf() 可以用于做格式化输出。
//输出: n1 的 类型 int
fmt.Printf("n1 的 类型 %T \n", n1)
//如何在程序查看某个变量的占用字节大小和数据类型 (使用较多)
var n2 int64 = 10
//unsafe.Sizeof(n1) 是 unsafe 包的一个函数,可以返回 n1 变量占用的字节数
//输出: n2 的 类型 int64 n2占用的字节数是 8
fmt.Printf("n2 的 类型 %T n2占用的字节数是 %d ", n2, unsafe.Sizeof(n2))
}
golang 中小数类型使用
package main
import (
"fmt"
"unsafe"
)
//golang 中小数类型使用
func main() {
var price float32 = 89.12
//输出: price= 89.12
fmt.Println("price=", price)
var num1 float32 = -0.00089
var num2 float64 = -7809656.09
//输出: num1= -0.00089 num2= -7.80965609e+06
fmt.Println("num1=", num1, "num2=", num2)
//尾数部分可能丢失,造成精度损失。 -123.0000901
var num3 float32 = -123.0000901
var num4 float64 = -123.0000901
num3= -123.00009 num4= -123.0000901
fmt.Println("num3=", num3, "num4=", num4)
//Golang 的浮点型默认声明为 float64 类型
var num5 = 1.1
//输出: num5的数据类型是 float64
fmt.Printf("num5的数据类型是 %T \n", num5)
//十进制数形式:如:5.12 .512 (必须有小数点)
num6 := 5.12
num7 := .123 //=> 0.123
//输出: num6= 5.12 num7= 0.123
fmt.Println("num6=", num6, "num7=", num7)
//科学计数法形式
num8 := 5.1234e2 // 5.1234 * 10的2次方
num9 := 5.1234E2 // 5.1234 * 10的2次方
num10 := 5.1234E-2 // 5.1234 / 10的2次方 0.051234
//输出: num8= 512.34 num9= 512.34 num10= 0.051234
fmt.Println("num8=", num8, "num9=", num9, "num10=", num10)
/**
* byte 等同于 int8,常用来处理 ascii 字符
* rune 等同于 int32,常用来处理 unicode 或 utf-8 字符
*/
var c1 rune = '北'
//输出: c1= 21271 4
fmt.Println("c1=", c1, unsafe.Sizeof(c1))
}
golang 中基本数据类型的转换
package main
import (
"fmt"
)
// golang 中基本数据类型的转换
func main() {
var i int32 = 100
//希望将 i => float
var n1 float32 = float32(i)
var n2 int8 = int8(i)
var n3 int64 = int64(i) //低精度->高精度
//输出: i=100 n1=100 n2=100 n3=100
fmt.Printf("i=%v n1=%v n2=%v n3=%v \n", i, n1, n2, n3)
//被转换的是变量存储的数据(即值),变量本身的数据类型并没有变化
//输出: i type is int32
fmt.Printf("i type is %T\n", i) // int32
//在转换中,比如将 int64 转成 int8 【-128---127】 ,编译时不会报错,
//只是转换的结果是按溢出处理,和我们希望的结果不一样
var num1 int64 = 999999
var num2 int8 = int8(num1)
//输出: num2= 63
fmt.Println("num2=", num2)
}
golang 中指针类型使用
package main
import (
"fmt"
)
//golang 中指针类型
func main() {
//基本数据类型在内存布局
var i int = 10
// i 的地址是什么,&i
//输出: i的地址= 0xc00004e080
fmt.Println("i的地址=", &i)
//下面的 var ptr *int = &i
//1. ptr 是一个指针变量
//2. ptr 的类型 *int
//3. ptr 本身的值&i
var ptr *int = &i
//输出: ptr=0xc00004e080
fmt.Printf("ptr=%v\n", ptr)
//输出: ptr 的地址=0xc000076020ptr 指向的值=10
fmt.Printf("ptr 的地址=%v", &ptr)
fmt.Printf("ptr 指向的值=%v", *ptr)
}
golang 中字符类型使用
package main
import (
"fmt"
)
//golang 中字符类型使用
func main() {
var c1 byte = 'a'
var c2 byte = '0' //字符的0
//当我们直接输出byte值,就是输出了的对应的字符的码值
// 'a' ==>
//输出: c1= 97 c2= 48
fmt.Println("c1=", c1)
fmt.Println("c2=", c2)
//如果我们希望输出对应字符,需要使用格式化输出
//输出: c1=a c2=0
fmt.Printf("c1=%c c2=%c\n", c1, c2)
//var c3 byte = '北' //overflow溢出
var c3 int = '北' //overflow溢出
//输出: c3=北 c3对应码值=21271
fmt.Printf("c3=%c c3对应码值=%d\n", c3, c3)
//可以直接给某个变量赋一个数字,然后按格式化输出时%c,会输出该数字对应的unicode 字符
var c4 int = 22269 // 22269 -> '国' 120->'x'
//输出: c4=国
fmt.Printf("c4=%c\n", c4)
//字符类型是可以进行运算的,相当于一个整数,运输时是按照码值运行
var n1 = 10 + 'a' // 10 + 97 = 107
//输出: n1= 107
fmt.Println("n1=", n1)
}
golang 中 bool 类型使用
package main
import (
"fmt"
"unsafe"
)
//golang 中 bool 类型使用
func main() {
var b = false
//输出: b= false
fmt.Println("b=", b)
//输出: b 的占用空间 = 1
//注意事项
//1. bool类型占用存储空间是1个字节
fmt.Println("b 的占用空间 =", unsafe.Sizeof(b))
//2. bool类型只能取true或者false
}
golang 中 string 类型使用
package main
import (
"fmt"
)
//golang 中 string 类型使用
func main() {
//string 的基本使用
var address string = "北京长城 110 hello world!"
//输出: 北京长城 110 hello world!
fmt.Println(address)
//字符串一旦赋值了,字符串就不能修改了:在Go中字符串是不可变的
//var str = "hello"
//str[0] = 'a' //这里就不能去修改str的内容,即go中的字符串是不可变的。
//字符串的两种表示形式
//(1) 双引号, 会识别转义字符;
//(2) 反引号,以字符串的原生形式输出,包括换行和特殊字符,可以实现防止攻击, 输出源代码等效果
str2 := "abc\nabc"
/**
* 输出:
* abc
* abc
*/
fmt.Println(str2)
//使用的反引号 ``
str3 := `
package main
import (
"fmt"
"unsafe"
)
//演示golang中bool类型使用
func main() {
var b = false
fmt.Println("b=", b)
//注意事项
//1. bool类型占用存储空间是1个字节
fmt.Println("b 的占用空间 =", unsafe.Sizeof(b) )
//2. bool类型只能取true或者false
}
`
fmt.Println(str3)
//字符串拼接方式
var str = "hello " + "world"
str += " haha!"
fmt.Println(str)
//当一个拼接的操作很长时,怎么办,可以分行写,但是注意,需要将+保留在上一行.
str4 := "hello " + "world" + "hello " + "world" + "hello " +
"world" + "hello " + "world" + "hello " + "world" +
"hello " + "world"
fmt.Println(str4)
var a int // 0
var b float32 // 0
var c float64 // 0
var isMarried bool // false
var name string // ""
//这里的 %v 表示按照变量的值输出
//输出: a=0,b=0,c=0,isMarried=false name=
fmt.Printf("a=%d,b=%v,c=%v,isMarried=%v name=%v", a, b, c, isMarried, name)
}
golang 中基本数据转成 string
package main
import (
"fmt"
"strconv"
_ "unsafe"
)
//golang 中基本数据转成 string
func main() {
var num1 int = 99
var num2 float64 = 23.456
var b bool = true
var myChar byte = 'h'
var str string //空的str
//使用第一种方式来转换 fmt.Sprintf 方法
//输出: str type string str="99"
str = fmt.Sprintf("%d", num1)
fmt.Printf("str type %T str=%q\n", str, str)
//输出: str type string str="23.456000"
str = fmt.Sprintf("%f", num2)
fmt.Printf("str type %T str=%q\n", str, str)
//输出: str type string str="true"
str = fmt.Sprintf("%t", b)
fmt.Printf("str type %T str=%q\n", str, str)
//输出: str type string str="h"
str = fmt.Sprintf("%c", myChar)
fmt.Printf("str type %T str=%q\n", str, str)
//第二种方式 strconv 函数
var num3 int = 99
var num4 float64 = 23.456
var b2 bool = true
//输出: str type string str="99"
str = strconv.FormatInt(int64(num3), 10)
fmt.Printf("str type %T str=%q\n", str, str)
// strconv.FormatFloat(num4, 'f', 10, 64)
// 说明: 'f' 格式 10:表示小数位保留10位 64 :表示这个小数是 float64
// 输出: str type string str="23.4560000000"
str = strconv.FormatFloat(num4, 'f', 10, 64)
fmt.Printf("str type %T str=%q\n", str, str)
//输出: str type string str="true"
str = strconv.FormatBool(b2)
fmt.Printf("str type %T str=%q\n", str, str)
//strconv 包中有一个函数 Itoa
//输出: str type string str="4567"
var num5 int64 = 4567
str = strconv.Itoa(int(num5))
fmt.Printf("str type %T str=%q\n", str, str)
}
golang 中 string 转成基本数据类型
package main
import (
"fmt"
"strconv"
)
// golang 中 string 转成基本数据类型
func main() {
// 输出: b type bool b=true
var str string = "true"
var b bool
// b, _ = strconv.ParseBool(str)
// 说明
// 1. strconv.ParseBool(str) 函数会返回两个值 (value bool, err error)
// 2. 因为我只想获取到 value bool ,不想获取 err 所以我使用_忽略
b, _ = strconv.ParseBool(str)
//输出: b type bool b=true
fmt.Printf("b type %T b=%v\n", b, b)
// 输出: n1 type int64 n1=1234590
// n2 type int n2=1234590
var str2 string = "1234590"
var n1 int64
var n2 int
n1, _ = strconv.ParseInt(str2, 10, 64)
n2 = int(n1)
//输出: n1 type int64 n1=1234590
fmt.Printf("n1 type %T n1=%v\n", n1, n1)
//输出: n2 type int n2=1234590
fmt.Printf("n2 type %T n2=%v\n", n2, n2)
// 输出: f1 type float64 f1=123.456
var str3 string = "123.456"
var f1 float64
f1, _ = strconv.ParseFloat(str3, 64)
//输出: f1 type float64 f1=123.456
fmt.Printf("f1 type %T f1=%v\n", f1, f1)
// 输出: n3 type int64 n3=0
var str4 string = "hello"
var n3 int64 = 11
n3, _ = strconv.ParseInt(str4, 10, 64)
//输出: n3 type int64 n3=0
fmt.Printf("n3 type %T n3=%v\n", n3, n3)
}
【2.2】运算符
golang 语言运算符注意点总结
++,-- 运算符
package main
import (
"fmt"
_ "fmt"
)
func main() {
//在golang中,++ 和 -- 只能独立使用.
var i int = 8
// var a int
// a = i++ //错误,i++只能独立使用
// a = i-- //错误, i--只能独立使用
// 编译出错
// if i++ > 0 {
// fmt.Println("ok")
// }
i++
// ++i // 错误,在golang没有 前++
fmt.Println("i=", i)
i--
// --i // 错误,在golang没有 前--
fmt.Println("i=", i)
}
【2.3】典型流程控制示例
golang 语言 break 总结
package main
import (
"fmt"
"math/rand"
"time"
)
func main() {
//我们为了生成一个随机数,还需要个rand设置一个种子.
//time.Now().Unix() : 返回一个从1970:01:01 的0时0分0秒到现在的秒数
//rand.Seed(time.Now().Unix())
//如何随机的生成1-100整数
//n := rand.Intn(100) + 1 // [0 100)
//fmt.Println(n)
//随机生成1-100的一个数,直到生成了99这个数,看看你一共用了几次
//分析思路:
//编写一个无限循环的控制,然后不停的随机生成数,当生成了99时,就退出这个无限循环==》break
var count int = 0
for {
rand.Seed(time.Now().UnixNano())
n := rand.Intn(100) + 1
fmt.Println("n=", n)
count++
if n == 99 {
break //表示跳出for循环
}
}
fmt.Println("生成 99 一共使用了 ", count)
//这里演示一下指定标签的形式来使用 break
//break 语句出现在多层嵌套的语句块中时,可以通过标签指明要终止的是哪一层语句块
//lable2:
for i := 0; i < 4; i++ {
lable1: // 设置一个标签
for j := 0; j < 10; j++ {
if j == 2 {
// break // break 默认会跳出最近的for循环
break lable1
// break lable2
}
//break : j=0,j=1; i=0,i=1,i=2,i=3;
//break lable1 : j=0,j=1; i=0,i=1,i=2,i=3;
//break lable2 : j=0,j=1; i 不会打印;
fmt.Println("j=", j)
}
fmt.Println("i=", i)
}
}
golang 语言 continue 总结
package main
import "fmt"
func main() {
//continue案例
//这里演示一下指定标签的形式来使用
lable2:
for i := 0; i < 4; i++ {
// lable1: // 设置一个标签
for j := 0; j < 10; j++ {
if j == 2 {
// continue
// continue lable1
continue lable2
}
// continue : i=0--3;j=0,1,3--9;
// continue lable1 : i=0--3;j=0,1,3--9;
// continue lable2 : j=0,1; i 不打印
fmt.Println("j=", j)
}
fmt.Println("i=", i)
}
}
golang 语言 for 总结
package main
import (
"fmt"
)
func main() {
//for 循环的第一种写法
for i := 1; i <= 10; i++ {
fmt.Println("你好,尚硅谷", i)
}
//for 循环的第二种写法
j := 1 //循环变量初始化
for j <= 10 { //循环条件
fmt.Println("你好,尚硅谷~", j)
j++ //循环变量迭代
}
//for 循环的第三种写法, 这种写法通常会配合 break 使用
k := 1
for { // 这里也等价 for ; ; {
if k <= 10 {
fmt.Println("ok~~", k)
} else {
break //break就是跳出这个for循环
}
k++
}
//字符串遍历方式1-传统方式
var str string = "hello,world!北京"
for i := 0; i < len(str); i++ {
fmt.Printf("%c \n", str[i]) //使用到下标...
}
//字符串遍历方式1-传统方式
str2 := []rune(str) // 就是把 str 转成 []rune
for i := 0; i < len(str2); i++ {
fmt.Printf("%c \n", str2[i]) //使用到下标...
}
//字符串遍历方式2-for-range
str = "abc~ok上海"
for index, val := range str {
fmt.Printf("index=%d, val=%c \n", index, val)
}
}
golang 语言 goto / return 总结
package main
import (
"fmt"
)
func main() {
var n int = 30
//演示goto的使用
fmt.Println("GOTO1")
if n > 20 {
goto label1
}
fmt.Println("GOTO2")
fmt.Println("GOTO3")
fmt.Println("GOTO4")
label1:
fmt.Println("GOTO5")
fmt.Println("GOTO6")
fmt.Println("GOTO7")
//演示return的使用
fmt.Println("RETURN1")
if n > 20 {
return
}
fmt.Println("RETURN2")
fmt.Println("RETURN3")
fmt.Println("RETURN4")
fmt.Println("RETURN5")
fmt.Println("RETURN6")
fmt.Println("RETURN7")
}
golang 语言 switch 总结
package main
import (
"fmt"
)
func main() {
//go 语言中 switch 匹配后不需要加 break 自动退出
var n1 int32 = 51
var n2 int32 = 20
switch n1 {
case n2, 10, 5: // case 后面可以有多个表达式
fmt.Println("ok1")
case 90:
fmt.Println("ok2~")
}
//switch 后也可以不带表达式,类似 if--else 分支来使用。【案例演示】
var age int = 10
switch {
case age == 10:
fmt.Println("age == 10")
case age == 20:
fmt.Println("age == 20")
default:
fmt.Println("没有匹配到")
}
//case 中也可以对 范围进行判断
var score int = 90
switch {
case score > 90:
fmt.Println("成绩优秀..")
case score >= 70 && score <= 90:
fmt.Println("成绩优良...")
case score >= 60 && score < 70:
fmt.Println("成绩及格...")
default:
fmt.Println("不及格")
}
//switch 后也可以直接声明/定义一个变量,分号结束,不推荐
switch grade := 90; { // 在golang中,可以这样写
case grade > 90:
fmt.Println("成绩优秀~..")
case grade >= 70 && grade <= 90:
fmt.Println("成绩优良~...")
case grade >= 60 && grade < 70:
fmt.Println("成绩及格~...")
default:
fmt.Println("不及格~")
}
//switch 的穿透 fallthrought
//在 case 语句块后添加 fallthrought 则会继续执行下一个 case
var num int = 10
switch num {
case 10:
fmt.Println("ok1")
fallthrough //默认只能穿透一层
case 20:
fmt.Println("ok2")
fallthrough
case 30:
fmt.Println("ok3")
default:
fmt.Println("没有匹配到..")
}
}
golang 语言 while 总结
package main
import "fmt"
func main() {
//使用while方式输出10句 "hello,world"
//循环变量初始化
var i int = 1
for {
if i > 10 { //循环条件
break // 跳出for循环,结束for循环
}
fmt.Println("hello,world", i)
i++ //循环变量的迭代
}
fmt.Println("i=", i)
//使用的do...while实现完成输出10句”hello,ok“
var j int = 1
for {
fmt.Println("hello,ok", j)
j++ //循环变量的迭代
if j > 10 {
break //break 就是跳出for循环
}
}
}