1.fmt详解
package main
import "fmt"
func main() {
// 直接打印内容
fmt.Println("Hello World")
// Print 直接打印不换行
fmt.Print("还可以再打印1")
fmt.Print("还可以再打印2")
//格式化打印,%s字符串,%d是数字
fmt.Printf("我的年龄是%d: ",19)
//根据格式化参数生成格式化的字符串并返回该字符串
info := fmt.Sprintf("我的名字是:%s,我的年龄是:%d","中国",100)
fmt.Println(info)
}
2.变量和常量
package main
import (
"fmt"
"reflect"
)
func main() {
// go语言中定义变量
// 定义方法1: var:关键字 name:变量名 string:变量类型 =代表赋值
var name string = "egon"
fmt.Println("My English Name is:",name)
// 定义方法2: 语法糖 name:变量名 := 代表赋值
age := 18
b := true
f := 3.1415926
fmt.Println("我今年的年龄是: ",age)
fmt.Println(b,f)
// 查看变量的的类型
fmt.Println("age的类型是: ",reflect.TypeOf(age)) //int
fmt.Println("b的类型是: ",reflect.TypeOf(b)) //bool
fmt.Println("f的类型是: ",reflect.TypeOf(f)) //flout
//go语言中定义常量
const c1,c2,c3 = 1,2,3
const (
a1 = "a1"
a2 = "a2"
)
// 常量的值是无法修改的
fmt.Println("常量的值是:",c1,c2,c3 )
fmt.Println("a1的类型是: ",reflect.TypeOf(a1))
}
3.函数
函数是基本的代码块,用于执行一个任务。
Go 语言最少有个 main() 函数。
你可以通过函数来划分不同功能,逻辑上每个函数执行的是指定的任务。
函数声明告诉了编译器函数的名称,返回类型,和参数。
Go 语言标准库提供了多种可动用的内置的函数。例如,len() 函数可以接受不同类型参数并返回该类型的长度。如果我们传入的是字符串则返回字符串的长度,如果传入的是数组,则返回数组中包含的元素个数。
Go 语言函数定义格式如下:
func function_name( [parameter list] ) [return_types] {
函数体
}
函数定义解析:
func:函数由 func 开始声明
function_name:函数名称,参数列表和返回值类型构成了函数签名。
parameter list:参数列表,参数就像一个占位符,当函数被调用时,你可以将值传递给参数,这个值被称为实际参数。参数列表指定的是参数类型、顺序、及参数个数。参数是可选的,也就是说函数也可以不包含参数。
return_types:返回类型,函数返回一列值。return_types 是该列值的数据类型。有些功能不需要返回值,这种情况下 return_types 不是必须的。
函数体:函数定义的代码集合。
实例
以下实例为 max() 函数的代码,该函数传入两个整型参数 num1 和 num2,并返回这两个参数的最大值:
package main
import "fmt"
func max(num1, num2 int) int {
var result int
if num1 > num2 {
result = num1
} else {
result = num2
}
return result
}
func main() {
ret := max(12212, 888)
fmt.Println("最大值是: ",ret)
}
作用域:
作用域为已声明标识符所表示的常量、类型、变量、函数或包在源代码中的作用范围。
Go 语言中变量可以在三个地方声明:
函数内定义的变量称为局部变量
函数外定义的变量称为全局变量
函数定义中的变量称为形式参数
局部变量:在函数体内声明的变量称之为局部变量,它们的作用域只在函数体内,参数和返回值变量也是局部变量。
全局变量:
在函数体外声明的变量称之为全局变量,全局变量可以在整个包甚至外部包(被导出后)使用。
package main
import "fmt"
//在func之外定义一个全局变量,不可以用语法糖定义
var gloabalName string = "小涛童鞋"
func printAd() {
fmt.Println("我是杨老师")
fmt.Println("我教授的课程主要有: Go、PHP、Java、Vue、HTML、CSS、K8S")
fmt.Println("课程永久免费更新")
fmt.Println("欢迎大家积极订购")
// 能不能在printAd里面调用name变量?
// fmt.Println("我的名字是: ",name) //我们不能调用其他函数的变量
fmt.Println("全局变量的值是:",gloabalName)
}
func main() {
var name string = "dot"
fmt.Println("my name is: ",name)
fmt.Println("程序正在运行中...")
printAd()
fmt.Println("在main函数内全局变量的值:",gloabalName)
fmt.Println("程序运行结束...")
}
4.数值及字符串运算
package main
import (
"fmt"
"reflect"
)
// 数值运算
func numOperations(a,b int) {
fmt.Println("a + b 的值是: ", a + b)
fmt.Println("a - b 的值是: ", a - b)
fmt.Println("a * b 的值是: ", a * b)
fmt.Println("a / b 的值是: ", a / b)
fmt.Println("a % b 的值是: ", a % b)
}
func stringOperations(a,b string) {
fmt.Println("a和b拼接后的值是:",a+b)
ab := a + b
fmt.Printf("ab的值是: %s,类型是:%s",ab,reflect.TypeOf(ab))
}
// fmt.Sprintf
func stringSprintf(firstName,secondName string) {
fullName := fmt.Sprintf("%s %s",secondName,firstName)
fmt.Println("全名是: ",fullName)
}
func main() {
numOperations(23,98) //数值运算
stringOperations("hello","xiaoming") //字符串运算
stringSprintf("明","小")
//自增和自减
p := 8
p++
fmt.Println("p自增的值是:",p)
p--
p--
fmt.Println("p自减的值是:",p)
}
5.数值类型详解
package main
import (
"fmt"
"reflect"
)
func main() {
// 数值类型: int int8 int16 int32 int64 uint
// int:正负数 unit:不带符号的数值 ,推荐使用int
defaultIntType := 1
fmt.Println("默认的数值类型是:",reflect.TypeOf(defaultIntType))
// int和操作系统是有关系的
var int64Num int64 = 1
fmt.Println("int64Num的数值类型是:",reflect.TypeOf(int64Num))
var unitNum uint = 1
fmt.Println("unitNum的数值类型是:",reflect.TypeOf(unitNum))
// float float32和float64,推荐用float64
var floatNum1 float64 = 3.14
var floatNum2 float32 = 3.15
fmt.Println(floatNum1, floatNum2)
}
6.关系和逻辑运算符
package main
import (
"fmt"
"reflect"
)
func main() {
// 大于,小于
fmt.Println(72787 > 72789)
fmt.Println(72787 < 72799)
// 是否相等 ,=和==的区别
fmt.Println("a" == "b") //false
fmt.Println(3.14 == 3.14)
s1 := "dukuan"
s2 := "dotablo"
fmt.Println("s1和s2相等: ",s1 == s2)
fmt.Println("s1和s2不相等: ",s1 != s2)
fmt.Println("s1 > s2",s1 > s2)
fmt.Println("s1 < s2", s1 < s2) //字符串是可以比较大小的,ASCII
// 逻辑与 && 逻辑或 ||
n1 := 1
n2 := 1
n3 := 2
// 与: 所有的表达式都为true,最终的结果就会true
fmt.Println(n1 == n2 && n2 == n3) //false
// 或:任意一个为true,最终结果就为true
fmt.Println(n1 == n2 || n2 > n3) // true
fmt.Println(n1 != n2 || reflect.TypeOf(n3).Kind() == reflect.String)
fmt.Println(n3 > n2 && n1 == n2 )
}
7. 条件语句
条件语句需要开发者通过指定一个或多个条件,并通过测试条件是否为 true 来决定是否执行指定语句,并在条件为 false 的情况在执行另外的语句。
package main
import "fmt"
func printPrice(weacher string) {
defaultPrice := 10
if weacher == "sunny" {
fmt.Println("今天是晴天,雨伞的价钱是: ",defaultPrice)
} else {
// 如果不成立执行else后面的代码,然后else可以没有
fmt.Println("今天不是晴天,雨伞的价钱是:",defaultPrice +5)
}
}
func printPriceWithWeacher(weacher string) {
defaultPrice := 10
// 小雨涨5块
// 大雨涨10块
// 暴雨涨15块
// 其他天气原价
if weacher == "lightRain" {
fmt.Println("下小雨了,雨伞的价钱是: ",defaultPrice +5)
} else if weacher == "heavyRain" {
fmt.Println("下大雨了,雨伞的价钱是: ",defaultPrice + 10)
} else if weacher == "stormRain" {
fmt.Println("下暴雨了,雨伞的价钱是: ",defaultPrice +15)
} else {
fmt.Println("我也不知道今天是什么天气,雨伞的价钱是: ",defaultPrice)
}
}
func main() {
// 晴天
// printPrice("sunny")
// 不是晴天
// printPrice("")
printPriceWithWeacher("lightRain")
printPriceWithWeacher("heavyRain")
printPriceWithWeacher("stormRain")
printPriceWithWeacher("")
}
switch 语句用于基于不同条件执行不同动作。
package main
import "fmt"
func printPrice(weacher string) {
defaultPrice := 10
if weacher == "sunny" {
fmt.Println("今天是晴天,雨伞的价钱是: ",defaultPrice)
} else {
// 如果不成立执行else后面的代码,然后else可以没有
fmt.Println("今天不是晴天,雨伞的价钱是:",defaultPrice +5)
}
}
func printPriceWithWeacher(weacher string) {
defaultPrice := 10
// 小雨涨5块
// 大雨涨10块
// 暴雨涨15块
// 其他天气原价
//
switch weacher {
case "lightRain":
fmt.Println("下小雨了,雨伞的价格是: ",defaultPrice +5)
case "heavyRain":
fmt.Println("下大雨了,雨伞的价格是: ",defaultPrice + 10)
case "stormRain":
fmt.Println("下暴雨了,雨伞的价格是: ",defaultPrice + 15)
case "sunny","snowing":
fmt.Println("晴天或者雪天,雨伞的价格是: ",defaultPrice)
default:
fmt.Println("我也不知道是什么天气,雨伞不卖了~")
}
}
func main() {
printPriceWithWeacher("lightRain")
printPriceWithWeacher("heavyRain")
printPriceWithWeacher("stormRain")
printPriceWithWeacher("")
}
8.循环语句
在不少实际问题中有许多具有规律性的重复操作,因此在程序中就需要重复执行某些语句。
package main
import "fmt"
func main() {
count := 0
for num := 1; num <= 100; num++ {
if num%2 == 0 {
fmt.Println("发现一个偶数:",num)
count++
}
}
fmt.Printf("1-100之间有偶数:%d个",count)
// 计算奇数
num2 := 1
for num2 <= 100 {
if num2 %2 != 0 {
fmt.Println("发现一个奇数:",num2)
}
num2++
}
}
实现无限循环:
package main
import (
"fmt"
"time"
)
func main() {
for {
timeNow := time.Now()
// 2006-01-02 15:04:05 go语言诞生时间
fmt.Println("当前时间是: ",timeNow.Format("2006-01-02 15:04:05"))
fmt.Println("我错了,原谅我吧~")
time.Sleep(time.Second * 3)
}
}
break和continue
package main
import "fmt"
func main() {
// break: 终止循环
// continue: 终止本次循环,继续下一次循环
for i := 0; i < 100; i++ {
if i == 88 {
fmt.Println("我找到了88")
break
}
fmt.Println("现在的数值是: ",i)
}
// continue
for i := 0; i < 10; i++ {
if i == 8 {
fmt.Println("我找到了8")
continue
}
fmt.Println("现在的数值是: ",i)
}
}
9.数组
数组是具有相同唯一类型的一组已编号且长度固定的数据项序列,这种类型可以是任意的原始类型例如整型、字符串或者自定义类型。
相对于去声明 number0, number1, …, number99 的变量,使用数组形式 numbers[0], numbers[1] …, numbers[99] 更加方便且易于扩展。
数组元素可以通过索引(位置)来读取(或者修改),索引从 0 开始,第一个元素索引为 0,第二个索引为 1,以此类推。
声明数组
Go 语言数组声明需要指定元素类型及元素个数,语法格式如下
var arrayName [size]dataType
//其中,arrayName是数组的名称,size是数组的大小,dataType是数组中元素的数据类型。
// 以下定义了数组balancer 长度为10,类型为float32
var balance [10]float32
声明并初始化数组
package main
import "fmt"
func main() {
var teacherNameArray = [3]string{"马云", "刘强东", "刘敏"}
fmt.Println("数组是:",teacherNameArray)
fmt.Println("第一位老师的名字是: ",teacherNameArray[0])
fmt.Println("第二位老师的名字是: ",teacherNameArray[1])
fmt.Println("第三位老师的名字是: ",teacherNameArray[2])
// 语法糖定义数组
teacherAgeArray := [3]int{18, 19, 20}
fmt.Println("第一位老师的年龄是: ",teacherAgeArray[0])
fmt.Println("第二位老师的年龄是: ",teacherAgeArray[1])
fmt.Println("第三位老师的年龄是: ",teacherAgeArray[2])
// 修改数据
teacherNameArray[2] = "张三"
fmt.Println("数组是: ",teacherNameArray[2])
//试着修改数组的长度,不能修改
// teacherNameArray[3] = "李四"
// 获取数组的长度
fmt.Println("数组的长度是: ",len(teacherNameArray))
// 获取数组的所有数据
for k , v := range teacherNameArray {
fmt.Printf("第%d位老师的姓名是:%s\n",k+1,v)
}
//如果数组长度不确定,可以使用 ... 代替数组的长度,编译器会根据元素个数自行推断数组的长度:
array1 := [...]int{1,2,3,21,34,8,100}
fmt.Println("array1数组的长度是: ",len(array1))
}
10 切片
Go 数组的长度不可改变,在特定场景中这样的集合就不太适用,Go 中提供了一种灵活,功能强悍的内置类型切片(“动态数组”),与数组相比切片的长度是不固定的,可以追加元素,在追加时可能使切片的容量增大。
定义切片
package main
import "fmt"
func main() {
//切片的长度是不固定的,并且可以扩容
// 定义: var 切片名称 []数据类型
var s1 []string
fmt.Println("最初的切片的数据: ",s1)
// 默认的两个属性,一个是切片的长度,表示这个切片中有多少个元素
// 容量:表示这个切片可以放入多少个元素
fmt.Println("切片的默认长度是: ",len(s1))
fmt.Println("切片的默认容量是: ",cap(s1))
// 写入数据
s1 = append(s1, "张三","李四","王五")
fmt.Println("数据是: ",s1)
//第二种声明切片的方式,指定长度,容量 ,其中容量是可选的
// 5是长度,10是容量
s2 := make([]string, 5,10)
fmt.Println("切片的默认长度是: ",len(s2))
fmt.Println("切片的默认容量是: ",cap(s2))
s2= append(s2, "鸡","鸭","鱼","猪","羊")
fmt.Println("s2数据是: ",s2)
// 长度会发生变化,容量是原来容量的* 2
fmt.Println("长度是: ",len(s2))
fmt.Println("容量是: ",cap(s2))
// 数据的修改
s2[1] = "小樱桃"
s2[9] = "test"
fmt.Println("s2修改后的数据是: ",s2)
// 查询所有数据
for k , v := range s2 {
fmt.Printf("第%d位的数据是: %s\n",k+1, v)
}
}
切片的截取和删除
package main
import "fmt"
func main() {
var s = []int{1, 10, 20, 90, 50, 88}
fmt.Println("最初的数据是: ",s)
//切片的截取
fmt.Println("切片s的前4位数据是: ",s[:4])
fmt.Println("切片3-4位的数据是: ",s[2:4])
fmt.Println("切片从第4位开始的数据是: ",s[3:])
//切片数据的删除
fmt.Println("现在的数据是: ",s)
// 删除第一个元素
s = s[1:]
fmt.Println("删除元素后的数据: ",s)
// 删除最后一个元素
s = s[:len(s)-1]
fmt.Println("删除最后一个元素的数据:",s)
// 删除90 指定数据的元素
s = append(s[0:2],s[3:]...)
fmt.Println("删除90这个元素后的数据是: ",s)
}
切片的拷贝
package main
import (
"fmt"
"unsafe"
)
func main() {
//
/*
深拷贝:复制一个变量时,会创建一个全新的变量,并且将原始的数据复制给新变量,
新变量在内存中会是一个新的地址,并且两个变量修改时不会影响其他变量。
浅拷贝:复制一个变量时,也会创建一个新的变量,但是两个变量共享底层的数据,
也就是新旧变量会指向同一个数据的内存地址,实际上算是引用同一个数据,也就意味着任意一个变量发生变更,
其他变量也会被修改。
*/
// 引用类型 值类型
/*
值类型:复制变量的时候是深拷贝,值类型包括:int、float、string、struct、array、bool
引用类型:复制变量的时候是浅拷贝,引用类型包括:slice、map、channel、interface
*/
s1 := "dk"
s2 := s1
fmt.Println("s1和s2:",s1,s2)
s2 = "dot"
fmt.Println("s1和s2:",s1,s2)
slice1 :=[]int{1,2,3,4,5}
slice2 := slice1 // 浅拷贝
fmt.Println("slice1",slice1)
fmt.Println("slice2",slice2)
slice2[1] = 88
fmt.Println("修改后的slice1",slice1) // slice1和slice2 都发生了变化;浅拷贝
fmt.Println("修改后的slice2",slice2)
// 打印内存地址
fmt.Println("slice1的内存地址是: ",unsafe.Pointer(&slice1))
fmt.Println("slice2的内存地址是: ",unsafe.Pointer(&slice2))
fmt.Println("slice1的第一个元素的内存地址: ",unsafe.Pointer(&slice1[0])) //元素值的内存地址相同
fmt.Println("slice2的第一个元素的内存地址: ",unsafe.Pointer(&slice2[0])) //元素值的内存地址相同
}
package main
import (
"fmt"
"unsafe"
)
func main() {
//深拷贝
slice1 := []int{1, 2, 3, 4, 5}
slice3 := make([]int, len(slice1), cap(slice1))
copy(slice3,slice1)
fmt.Println("slice1: ",slice1)
fmt.Println("slice3: ",slice3)
slice3[1] = 88
fmt.Println("修改后的slice1: ",slice1)
fmt.Println("修改后的slice3: ",slice3)
//打印某个值的内存地址
fmt.Println("slice1的内存地址: ",unsafe.Pointer(&slice1))
fmt.Println("slice3的内存地址: ",unsafe.Pointer(&slice3))
fmt.Println("slice1的第一个元素的内存地址: ",unsafe.Pointer(&slice1[0]))
fmt.Println("slice3的第一个元素的内存地址: ",unsafe.Pointer(&slice3[0]))
}