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])) 
}
文档更新时间: 2023-11-13 16:32   作者:xtyang