【GO 开发系列 -- 基础】Go 基础简介

【1】Golang 语言简介

【1.1】GO 语言的定义

Go(又称Golang)是Google开发的一种静态强类型、编译型、并发型,并具有垃圾回收功能的编程语言。

go 语言基础镜像 go语言详解_go 语言基础镜像

【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循环
		}
	}
}