函数与指针

01.函数定义

什么是函数?

从前,人们想要制作果汁,每次都用手捏,非常麻烦,后来有人发明了榨汁机,人们只要把水果放进去,榨汁机就会把果汁榨出来。函数的功能就像榨汁机一样,帮助人们重复的做任务。函数是组织好的、可重复使用的执行特定任务的代码块。它可以提高应用程序的模块性和代码的重复利用率。Go语言支持普通函数、匿名函数和闭包,从设计上对函数进行了优化和改进,让函数使用起来更加方便。函数本身可以作为值进行传递。

package main	//指定其所在的包
import "fmt"	//导入fmt包
func main()  {	//main()函数是程序的入口
    fmt.Println("不忘初心,牢记使命 ! ")	//Println()函数打印内容
}
  • Go语言程序中都有一个main()函数
  • 可以通过其他函数来实现不同功能,逻辑上每个函数执行的是指定的任务
  • Go语言标准库提供了多种可用的内置函数
  • 函数的基本组成
  1. 关键字func
  2. 函数名
  3. 参数列表
  4. 返回值
  5. 函数体
  6. 返回语句
  • 函数的特点
  1. Go语言的编译型语言,函数编写时顺序的无关紧要的
  2. 函数构成了代码执行的逻辑结构
  3. 函数是基本的代码块
  4. 将一个需要很多行代码的复杂问题分解为一系列简单的任务来解决
  5. 同一个任务(函数)可以被多次调用,有助于代码重用
package main
import "fmt"
func main() {
    fmt.Println(sum(1,2,3,4,5))
}
func sum(numbers ...int) int{
    s := 0
    for i := range numbers{
        s += numbers[i]
    }
    return s
}




//运行结果为:
15

  • 当函数执行到代码块最后一行 } 之前或者return语句的时候会退出
  • 其中return语句可以带有零个或者多个参数,这些参数将作为返回值供调用者使用
  • Go语言函数的支持特性

支持:

  1. 支持参数数量不固定
  2. 支持匿名函数及闭包
  3. 支持函数本身作为值传递
  4. 支持函数的延迟执行
  5. 支持函数作为接口调用
  6. 无须前置声明
  7. 支持多返回值
  8. 支持命名返回值

不支持:

  1. 不支持命名嵌套定义
  2. 不支持同名函数重载
  3. 不支持默认参数
  • Go语言里面拥有3种类型的函数

在这里插入图片描述
2.

在这里插入图片描述
3.

在这里插入图片描述

方法是*绑定到某种类型*的(通常是结构体)

普通函数:不与任何类型绑定,可以在任何地方调用,不需要依赖某个特定的类型。
方法: 与某个类型绑定,需要通过该类型的实例来调用,适合封装类型的行为和操作。

package main
import "fmt"
// 定义一个结构体
type Person struct {
    name string
    age  int
}
// 定义一个方法,接收者是Person类型
func (p Person) greet() {
    fmt.Println("Hello, my name is", p.name)
}

// 定义一个带指针接收者的方法,用于修改属性
func (p *Person) haveBirthday() {
    p.age += 1
    fmt.Println(p.name, "is now", p.age, "years old")
}
func main() {
    // 创建一个Person实例
    person := Person{name: "Alice", age: 30}
    person.greet()              
    person.haveBirthday()      }

02.函数创建

  • 函数的语法:

在这里插入图片描述

package main
import (
    "fmt"
    "math"
)
func main() {
    fmt.Println(hypot(3,4))
}
func hypot(x, y float64) float64 {
    return math.Sqrt(x*x + y*y)
}




//运行结果为:
5

在hypot函数中:x和y是形参名,3和4是调用时传入的实数,函数返回了一个float64类型的值,返回值也可以像形式参数一样被命名,在这种情况下,每个返回值被声明成一个局部变量,并根据该返回值的类型,将其初始化为0.

  • 函数的语法详解:
  • func:函数是以func为关键字;
  • 函数名:函数名由字母、数字和下划线构成,但是函数名不能以数字开头;在同一个包内函数名不可重复;
  • 参数列表:参数列表中的每个参数都由参数名称和参数类型两部分组成,参数变量为函数的局部变量。如果函数的参数数量不固定,Go语言还支持可变参数;
  • 返回参数列表:返回参数列表中的每个参数由返回的参数名称和参数类型组成,也可简写为返回值类型列表;
  • 函数体:函数体指函数的主体代码逻辑,若函数有返回参数列表,则函数体中必须有return语句返回值列表。
  • 参数:
  • 函数可以有一个或者多个参数。
  • 如果函数使用参数,则该参数被称为函数的形参。
  • 形参就像定义在函数体内的局部变量。

形参:在定义函数时,用于接受外部传入的数据被称为形式参数
实参:在调用函数时,传给形参的实际的数据被称为实际参数

Go函数还支持可变参数(简称“变参”)。接受变参的函数有着不定数量的参数。

  • Go语言函数中的传递方式:

值传递:

1.在调用函数时将实际参数复制一份传递到函数中
2.函数运行中如果对参数进行修改,将不会影响到实际参数

引用传递:

1.在调用函数时将实际参数的地址传递到函数中
2.函数运行中对参数所进行的修改,将影响到实际参数

package main
import "fmt"
func number1(num int){
    num = 2
}
func number2(num *int){
    *num = 2
}
func main(){
    a := 1
    number1(a)
    fmt.Println(a)//值传递
    number2(&a)
    fmt.Println(a)//引用传递
}




//运行结果为:
1
2

默认情况下,Go语言所使用的是值传递,即在调用过程中不会影响到实际参数
函数参数调用需遵守如下形式:
(a) 函数名称必须匹配;
(b)实参与形参必须一一对应:顺序、个数、类型。

03.函数变量

  • 函数变量的语法:
var 变量名称 func()
  • 函数变量:

Go语言中,函数也是一种类型,我们可以将其保存在变量中

  • 可以通过type定义这种变量的类型
  • 拥有相同参数和相同返回值的函数属于同一种类型
  • 其优点是:可以将函数作为值进行传递
package main
import "fmt"
func main() {
    a :=10
    b :=11
    var f1 func(x int,y int) (sum int,sub int)
    f1 = addSub
    sum ,sub := f1(a,b)
    fmt.Printf("%d+%d=%d\n", a,b,sum)
    fmt.Printf("%d-%d=%d\n", a,b,sub)
}
func addSub(x int,y int) (sum int,sub int) {
    sum = x+y
    sub = x-y
    return sum,sub
}




//运行结果为:
10+11=21
10-11=-1

var f1 func(x int,y int (sum int,sub int))中的 f1 为函数变量,声明后的 f1 可以被当成 函数类型的变量来使用。

04.指针创建

  • 1.指针(pointer),全称为指针变量,是用来存储内存地址的一种变量。

  • 2.程序中,一般通过指针来访问其指向的内存地址中的内容(数据)。
    以上,实实在在的变量,有自己的内存存储空间,它可以指向任何有效的变量。

  • 引用,是C++中提出的一种新的使用变量的方式,即给实际变量起个别名,通过这个别名来引用实际的变量。
    以上,没有自己的实际存储空间。

  • 指针声明:

var var_name *var_type
  • 语法含义:
  • var_name为指针变量名
  • var_type为指针类型
  • *用于指定变量是作为一个指针
  • 这里的类型可以是之前的变量与常量的类型,例如int,float等。
package main
import "fmt"
func main() {
    var a int= 1
    var b *int
    b = &a
    fmt.Printf("a变量地址: %x\n", &a  )
    fmt.Printf("b变量指针地址: %x\n", b )
    fmt.Printf("*b变量的值: %d\n", *b )
}




//运行结果为:
a变量地址: c00000a098
b变量指针地址: c00000a098
*b变量的值: 1

Go语言中的指针是一种地址值;
指针变量就是存放地址值的变量。

package main
import (
	"fmt"
)
func main() {
    var p *int
    fmt.Println(p)
}




//运行结果为:
<nil>

var p *int为指针类型的声明,由于变量 p 没有复制,所以打印为空。

  • 指针特点:
  1. 一个指针变量可以指向任何一个值的内存地址;
  2. 它所指向的值的内存地址在32和64位机器上分别占用4或8个字节;
  3. 占用字节的大小与所指向的值的大小无关;
  4. 当一个指针被定义后没有分配到任何变量时,它的默认值为nil;
  5. 指针变量通常缩写为ptr(指代point)。
  • 每个变量在运行时都有用一个地址,这个地址代表变量在内存中的位置,Go语言中使用**“&”**符号放在变量前面对变量进行“取地址”操作。
ptr := &v    // v的类型为T

//v代表被取地址的变量,
//变量ptr用于接收地址值,
//ptr的类型就为*T,
//称做T的指针类型,*代表指针。
package main
import (
	"fmt"
)
func main() {
        num :=1
        var p *int
        p = &num
        fmt.Println("num变量的地址为:",p)
        fmt.Println("指针变量p的地址为:"&p)
}



//运行结果为:
num变量的地址为: 0xc042066080
指针变量p的地址为: 0xc042086018

指针变量本身也有自己的地址。

  • 在对普通变量使用 & 操作符取地址获得这个变量的指针后,可以对指针使用 “*” 操作符,也就是指针取值。
var house = "Malibu Point 10880, 90265"
ptr := &house
fmt.Printf("ptr type: %T\n", ptr)
fmt.Printf("address: %p\n", ptr)
value := *ptr
fmt.Printf("value type: %T\n", value)
fmt.Printf("value: %s\n", value)




//运行结果
ptr type: *string
address: 0xc0420401b0
value type: string
value: Malibu Point 10880, 90265

取地址操作符 & 和取值操作符 * 是一对互补操作符,& 取出地址,* 根据地址取出地址指向的值。

  • 变量、指针地址、指针变量、取地址、取值和相互关系和特性

对变量进行取地址操作使用 &操作符,可以获得这个变量的地址值。
指针变量的值是地址值。
对指针变量进行取值操作使用*操作符,可以获得指针变量指向的原变量的值。

package main
import (
	"fmt"
)
func main() {
    num :=1
    var p *int
    p = &num
    fmt.Println("指针变量p的所指向的内容为:",*p)
}



//运行结果为:
指针变量p的所指向的内容为:1

在取出指针的地址值后,通过在前面加*可以打印指针所指向的内容。

package main
import "fmt"
func main() {
    // 定义局部变量
   var a int = 100
   var b int = 200
   swap(&a, &b);
   fmt.Printf("交换后 a 的值 : %d\n", a )
   fmt.Printf("交换后 b 的值 : %d\n", b )
}
//将指针作为函数参数
func swap(x *int, y *int){
    *x, *y = *y, *x
}



//运行结果为:
交换后 a 的值 : 200
交换后 b 的值 : 100

Go语言支持向函数传递指针,只需要将函数定义的参数,设置为指针类型即可。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值