四.函数
1.函数是什么
函数是一块执行特定任务的代码。一个函数是在输入源基础上,通过执行一系列的算法,生成预期的输出。
2.声明函数的语法
通用语法
func functionname(parametername type) returntype {
// 函数体(具体实现的功能)
}
3.函数的几种类型
无参数函数
// 无参数
func test1() {
fmt.Println(123)
}
多参数函数
// 有两个参数
func test2(a int, b string) {
fmt.Println(a)
fmt.Println(b)
}
有返回值函数
// 有返回值
func test3(a , b int) int {
return a+b
}
多返回值函数
// 有多个返回值
func test4(a, b int) (int,string){
return a+b, "ok"
}
命名返回值函数
// 命名返回值
func test5(a,b int) (c int,d string) {
c = a+b
d = "ok"
return // python中return空返回的是None,而在go的命名返回值中return空,默认返回命名的值
}
可变长参数和任意类型的函数
// 可变长参数和任意类型的函数
func test6(a ...interface{}) {
fmt.Println(a)
}
注意:在go中没有关键字参数,只有位置参数,也没有默认参数
4.函数是一等公民
函数是一等公民即函数与字符串数组整型无异,它可以被命名可以被赋值可以当作参数被传进另一个函数也可以被另一个函数当作返回值可以放在任何位置
我们可以把函数赋值给一个变量
把函数赋值给一个变量
func main() {
//x = func(a int) int
//fmt.Println(x)
//x := test // 第三种
//var x = test // 第二种
//var x func(int) int = test // 第一种,定义变量的时候,函数的类型包括了他的参数和返回值
x(1)
}
func test(a int) int {
fmt.Println(123)
return a
}
五.函数高级
1.内层函数
内层函数:定义在函数内部的函数
// 内层函数
// go中函数内部定义的函数是不能有名的,需要定义匿名函数
func test1(){
func() {
fmt.Println("内层函数")
}()
}
2.闭包函数
闭包函数:定义在函数内部,并对外部作用域有引用。闭包函数可以为内层函数多一种传参方式
// 闭包函数,定义在函数内部,并对外部作用域有引用。闭包函数可以为内层函数多一种传参方式
func test2(a int) func(){
b := func() {
fmt.Println(a)
fmt.Println("闭包函数")
}
return b
}
闭包函数也是内层函数
使用闭包函数实现一个简单的装饰器
// 装饰器
func test3(a func() func()) func(c int) func(){
b := func(c int) func(){
fmt.Println("执行函数前")
res := a()
fmt.Println("执行函数之后")
return res
}
return b
}
func test4() func(){
fmt.Println("被装饰")
return func() {
fmt.Println("原函数")
}
}
再调用时装饰函数
func main() {
// 装饰的方法
test3(test4)(10)()
}
3.类型的重命名
重命名:给函数命别名
// 重命名
type MyFunc func(c int) func() // 给类型命别名,可以将一些复杂的类型,重命名为新的类型
func test3(a func() func()) (MyFunc){
b := func(c int) func(){
fmt.Println("执行函数前")
res := a()
fmt.Println("执行函数之后")
return res
}
return b
}
需要注意的是被命名后的函数类型跟原类型不是一个类型了,不能互相赋值
// 注意点
type MyInt int
func test5() {
var a MyInt = 10
var b int = 11
//a = b // 不同类型的不能直接转换
a = MyInt(b)
fmt.Println(a)
}
六.包
1.什么是包,为什么要使用包
到目前为止,我们看到的 Go 程序都只有一个文件,文件里包含一个 main 函数和几个其他的函数。在实际中,这种把所有源代码编写在一个文件的方法并不好用。以这种方式编写,代码的重用和维护都会很困难。而包(Package)解决了这样的问题。
包用于组织 Go 源代码,提供了更好的可重用性与可读性。由于包提供了代码的封装,因此使得 Go 应用程序易于维护。
2.如何使用
首先定义生成一个包
package mypackage // 通常情况下,包名就是文件夹名,在同一个文件夹下,包名必须一致
// 注意:在同一个包内,变量,函数都不能重复定义
// 在包内定义的函数小写字母开头只能在包内部使用
func test(a,b int) int{
return a+b
}
// 如果需要在外部使用,首字母必须大写
func Test1(a,b int) int{
return a+b
}
在需要使用的地方导入这个包并使用
package main
import "mypackage"
func main() {
// 使用mypackage包下面的test函数
a := mypackage.Test1(1,2)
print(a)
}
七.逻辑判断
1.if-else
if-else的语法
/*
语法:if 条件1{
执行1
}else if 条件2{
执行2
}else{
执行3
}
*/
具体使用的示例
if a>10{
fmt.Println("大于10")
}else if a<10{
fmt.Println("小于10")
}else{
fmt.Println("等于10")
}
注意点:在条件中可以定义变量,但是该变量只能在if判断内使用,外面不可以使用
if a := 90; a>90{
fmt.Println("大于90")
}else if a<90{
fmt.Println("小于90")
}else{
fmt.Println(a)
}
2.与或非逻辑
与:&&
或:||
非:!
// 与或非
// && || !
a := 1000
if !(a>10 && a<20 || a==10){
fmt.Println("哈哈哈")
}
八.for循环
1.简介
循环语句是用来重复执行某一段代码。
for是 Go 语言唯一的循环语句。Go 语言中并没有其他语言比如 C 语言中的 while
和 do while
循环。
2.循环的语法
for 变量初始化;条件判断;成功后执行的语句{
}
初始化语句只执行一次。循环初始化后,将检查循环条件。如果条件的计算结果为 true
,则 {}
内的循环体将执行,接着执行 post 语句。post 语句将在每次成功循环迭代后执行。在执行 post 语句后,条件将被再次检查。如果为 true
, 则循环将继续执行,否则 for 循环将终止。(译注:这是典型的 for 循环三个表达式,第一个为初始化表达式或赋值语句;第二个为循环条件判定表达式;第三个为循环变量修正表达式,即此处的 post )
代码示例
// 输出0-9的数字
for i:=0; i<10; i++{
fmt.Println(i)
}
3.三个组成部分都是可选的
// 三部分都可以省略
// 省略第一部分
i :=0
for ;i<10;i++{
fmt.Println(i)
}
// 省略第三部分
//for ;i<10; {
for i<10 { // ;分号可以省略,等同于其他语言的while i<10循环
fmt.Println(i)
i++
}
// 省略第二部分
//for ;; {
for { // 可以省略;,等同于while true
fmt.Println("死循环")
}
4.break和continue
// break和continue
for i:=0; i<10; i++{
if i==6{ // 遇到6的时候退出循环
break
}
fmt.Println(i)
}
for i:=0; i<10; i++{
if i==6{ // 遇到6的时候跳过当次循环
continue
}
fmt.Println(i)
}
九.switch语句
1.简介
switch 是一个条件语句,用于将表达式的值与可能匹配的选项列表进行比较,并根据匹配情况执行相应的代码块。它可以被认为是替代多个 if else
子句的常用方式。
2.基本用法
default,当所有条件都不成立时走default
a:=5
switch a {
case 1:
fmt.Println(1)
case 2:
fmt.Println(2)
case 3:
fmt.Println(3)
case 4:
fmt.Println(4)
case 5:
fmt.Println(5)
default: // 当匹配不到这个值时,走这儿
fmt.Println("没有这个值")
}
3.多值匹配,一个条件可以写多个值
// 多值匹配
a:=5
switch a {
case 1,4:
fmt.Println(1)
case 2,5:
fmt.Println(2)
case 3:
fmt.Println(3)
}
4.无表达式
// 无表达式的switch,表达式写在case内
a := 10
switch {
case a>10:
fmt.Println("大于10")
case a<10:
fmt.Println("小于10")
default:
fmt.Println("等于10")
}
5.fallthrough
fallthrough是穿透,当前条件匹配成功并执行后如果有穿透,那么下一个条件会无条件的执行
// fallthrough,穿透,无条件执行下一个case内容
a:=5
switch a {
case 1,4:
fmt.Println(1)
case 2,5:
fmt.Println(2)
// 穿透
fallthrough
case 3:
fmt.Println(3)
}
即上述代码中执行完第二个语句后会无条件的执行第三个语句
十.数组
1.什么是数组
数组是同一类型元素的集合。例如,整数集合 5,8,9,79,76 形成一个数组。Go 语言中不允许混合不同类型的元素,例如包含字符串和整数的数组。(译者注:当然,如果是 interface{} 类型数组,可以包含任意类型)
一个数组的表示形式为 [n]T
。n
表示数组中元素的数量,T
代表每个元素的类型。元素的数量 n
也是该类型的一部分(稍后我们将详细讨论这一点)。
2.声明一个基础的数组
var a [5]int // 定义一个长度为5的int类型数据
a[3] = 50
fmt.Println(a)
后面的类型必须写,否则就判断不了到底是什么类型了
//定义并赋初值
var a[4]int = [4]int{2,4,7} // 后面的类型必须写,不然就不能表明是什么类型
a[3] = 99
fmt.Println(a)
按索引赋值
// 按索引赋值,不支持负索引
a :=[100]int{1,5,7,9,98:99,49:50} // 在第99个位置赋值99
fmt.Println(a)
3.数组是值类型
// 数组是值类型
a := [4]int{1,2}
test9(a)
fmt.Println(a) // 在函数内部更改数组的值不会影响到真正的数组
定义的函数
// 所有函数的传参都是copy传参
func test9(a [4]int){
a[0] = 100
fmt.Println(a)
}
值类型:所以在函数中更改数组中的值,不会影响到外部的数组,而在python中的可变类型会被影响
4.数组的长度
使用内置函数len(数组)
// 数组的长度
a := [4]int{1,2}
fmt.Println(len(a))
5.数组的大小也是类型的一部分
在使用数组时,必须都写
// 数组的大小也是类型的一部分
a := [4]int{1,2,}
b := [4]int{4,5,}
c := [5]int{9,8,}
a = b // 类型一样时可以赋值
//a = c // 大小也是类型,所以类型不一样,不能赋值
fmt.Println(a)
6.数组的迭代
使用普通for循环方法
// 数组的迭代
a := [4]int{1,2,}
for i:=0;i<len(a);i++{
fmt.Println(a[i])
}
使用range方法
for i,v :=range a{
//for i :=range a{ // 因为range是关键字也可以只接收一个变量,默认是索引
fmt.Println("索引",i)
fmt.Println("值",v)
}
7.多维数组
103
// 多维数组
a := [9][2]int{} // 多维数组的声明
a[5][1] = 10000 // 多维数组的赋值
fmt.Println(a)