Unit3-构建块

1、函数

1.1、函数声明

image-20240328101948245

  • 声明函数时使用形参;调用函数时使用实参

  • 首字母小写的函数只能在声明该函数的包中使用,而首字母大写的函数会被导出并为其他包所用

  • 函数声明中带省略号...代表该函数是一个可变参数函数,可以接受任意多个实参

  • 函数声明时参数可以是多个:

    • func Unix(sec int64, nsec int64) Time 如果多个参数类型相同,则该类型只写一次即可:func Unix(sec, nsec int64) Time
    • 调用:func := time.Unix(12622780800, 0)
  • 函数声明时返回值可以是多个:

  • func Atoi(i string)(i int, err error)

  • 函数的多个返回值需要用括号括起来,每个返回值名字在前,类型在后。声明函数时可以把名字去掉,只保留类型:

  • func Atoi(i string)(int, error)

  • 可变参数函数:例如Println

    • 该函数声明为:func Println(a ...interface{})(n int,err error)
    • ...表示函数参数的数量是可变的
    • 参数a的类型为interface{},是一个空接口

小测验:温度单位转换

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package main
import "fmt"

// 开氏度转为摄氏度
func kelvinToCelsius(k float64) float64 {
k -= 273.15
return k
}
// 摄氏度转为华氏度
func celsiusToFahrenheit(c float64) float64 {
c = (c * 9.0 / 5.0) + 32.0
return c
}
// 开氏度转为华氏度
func kelvinToFahrenheit(k float64) float64 {
return celsiusToFahrenheit(kelvinToCelsius(k))
}
func main() {
kelvin := 0.0
celsius := kelvinToCelsius(kelvin)
fahrenheit := celsiusToFahrenheit(celsius)
fahrenheit1 := kelvinToFahrenheit(kelvin)
fmt.Printf("%f° K is %.2f° C and is %.2f° F\n", kelvin, celsius, fahrenheit)
fmt.Printf("%f° K is %.2f° F\n", kelvin, fahrenheit1)
}

2、方法

2.1、声明新类型

  • 关键字type可以用来声明新类型
    • type celsius float64
    • var temp celsius = 20

2.2、通过方法添加行为

  • 在Go里,提供了方法,但没有提供类和对象

image-20240328154509000

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
type kelvin float64	//声明类型
type celsius float64
// 函数
func kelvinToCelsius(k,kelvin) celsius{
return celsius(k - 273.15)
}
// kelvin类型的 celsius 方法
func (k,kelvin) celsius() celsius{
return celsius(k - 273.15)
}
// 调用方式
var k kelvin = 294.0
var c celsius

c = kelvinToCelsius(k) //调用函数
c = k.celsius() //调用方法
  • 方法就像跟特定类型相关联的函数,其中被关联的类型将通过方法名前面的接收者来指定。

练习:编写一个程序,使它带有celsius、fahrenheit和kelvin这三种类型以及在这三种温度类型间相互转换的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
package main

import "fmt"

type celsius float64
type fahrenheit float64
type kelvin float64

func (c celsius) fahrenheit() fahrenheit {
return fahrenheit((c * 9.0 / 5.0) + 32.0)
} // celsius转fahrenheit
func (c celsius) kelvin() kelvin {
return kelvin(c + 273.15)
} // celsius转kelvin
func (f fahrenheit) celsius() celsius {
return celsius((f - 32.0) * 0.5 / 9.0)
} // fahrenheit转celsius
func (f fahrenheit) kelvin() kelvin {
return f.celsius().kelvin()
} // fahrenheit转kelvin
func (k kelvin) celsius() celsius {
return celsius(k - 273.15)
} // kelvin转celsius
func (k kelvin) fahrenheit() fahrenheit {
return k.celsius().fahrenheit()
} // kelvin转fahrenheit
func main() {
var k kelvin = 294.0
c := k.celsius()
fmt.Println(k, "°k is ", c, "°C")
}

3、一等函数

在Go里,函数是头等的,它可以用在整数、字符串或其他类型能用的地方:

  • 将函数赋给变量
  • 将函数作为参数传递给函数
  • 将函数作为函数的返回类型

3.1、将函数赋给变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package main

import (
"fmt"
"math/rand"
)

type kelvin float64

func fakeSensor() kelvin {
return kelvin(rand.Intn(151) + 150)
}
func realSensor() kelvin {
return 0
}
func main() {
sensor := fakeSensor
fmt.Println(sensor())
sensor = realSensor
fmt.Println(sensor())
}
  • 变量sensor是一个函数,而不是函数执行的结果
  • 无论sensor的值是fakeSensor还是realSensor,都可以通过sensor()来调用
  • sensor这个变量的类型是函数,该函数没有参数,返回一个kelvin类型的值

3.2、将函数传递给其它函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package main

import (
"fmt"
"math/rand"
"time"
)

type kelvin float64

func messTemp(samples int, sensor func() kelvin) {
for i := 0; i < samples; i++ {
k := sensor()
fmt.Printf("%v°K\n", k)
time.Sleep(time.Second)
}
}
func fakeSensors() kelvin {
return kelvin(rand.Intn(151) + 150)
}
func main() {
messTemp(3, fakeSensors)
}
  • messTemp函数接受两个形参,其中第二个形参的类型为func() kelvin

3.3、声明函数类型

  • 为函数声明类型有助于精简和明确调用者的代码
    • 例如:type sensor func() kelvin
    • 所以:func meaTemp(samples int, s func() kelvin)
    • 可以精简为:func meaTemp(samples int, s sensor)

3.4、闭包和匿名函数

  • 匿名函数就是没有名字的函数,在Go里也称作函数字面值

  • 匿名函数三种类型:

    • var f = func(){
          fmt.Println("kkkkk")
      }
      func main(){
          f()		// 加小括号执行函数
      }
      
      1
      2
      3
      4
      5
      6
      7
      8

      - ```go
      func main(){
      f := func(message string){ //匿名函数赋值给变量
      fmt.Println(message)
      }
      f("kkkkkkk")
      }
    • //匿名函数声明后立即执行
      func main(){
          func(){
              fmt.Println("kkkkk")
          }()	//直接加小括号执行
      }
      
  • 闭包:参考视频:https://www.bilibili.com/video/BV1Vx4y1u7YX/?spm_id_from=333.337.search-card.all.click&vd_source=0f4e5d2dc04b3347f8ccfee59f6b22fa

  • 闭包现象:内层函数里面用到了它上一层函数里面的变量或一些东西,这个内层函数就叫做闭包函数