返回顶部
首页 > 资讯 > 后端开发 > GO >Go语言学习函数+结构体+方法+接口
  • 801
分享到

Go语言学习函数+结构体+方法+接口

2024-04-02 19:04:59 801人浏览 安东尼
摘要

目录1. 函数1.1 函数返回值同一种类型返回值带变量名的返回值函数中的参数传递函数变量1.2 匿名函数——没有函数名字的函数在定义时调用匿名函数将匿名函数赋

1. 函数

Go语言的函数属于“一等公民”(first-class),也就是说:

  • 函数本身可以作为值进行传递。
  • 支持匿名函数和闭包(closure)。
  • 函数可以满足接口。

1.1 函数返回值

同一种类型返回值

func typedTwoValues() (int, int) {
    return 1, 2
}
a, b := typedTwoValues()
fmt.Println(a, b)

带变量名的返回值

func named Ret Values() (a, b int) {
       a = 1
       b = 2
       return
}

函数使用命名返回值时,可以在return中不填写返回值列表,如果填写也是可行的

函数中的参数传递

Go语言中传入和返回参数在调用和返回时都使用 值传递 ,这里需要注意的是 指针、切片和map等引用型对象指向的内容在参数传递中不会发生复制,而是将指针进行复制,类似于创建一次引用。

函数变量

在Go语言中,函数也是一种类型,可以和其他类型一样被保存在变量中

func fire() {
	fmt.Println("fire")
}
func main() {
	var f func()  //将变量f声明为func()类型,此时f就被俗称为“回调函数”。此时f的值为nil。
	f = fire
	f()
}

1.2 匿名函数——没有函数名字的函数

Go语言支持匿名函数,即在需要使用函数时,再定义函数,匿名函数没有函数名, 只有函数体 ,函数可以被作为一种类型被赋值给函数类型的变量, 匿名函数也往往以变量方式被传递 。

在定义时调用匿名函数

匿名函数可以在声明后调用,例如:

func(data int) {
     fmt.Println("hello", data)
}(100)

将匿名函数赋值给变量

匿名函数体可以被赋值,例如:

// 将匿名函数体保存到f()中
f := func(data int) {
       fmt.Println("hello", data)
}
// 使用f()调用
f(100)

匿名函数用作回调函数

使用时再定义匿名函数,不使用先在被调用函数里面进行声明,这就是回调精髓

// 遍历切片的每个元素,通过给定函数进行元素访问
   func visit(list []int, f func(int)) {
        for _, v := range list {
              f(v)
        }
   }
   func main() {

       // 使用匿名函数打印切片内容
        visit([]int{1, 2, 3, 4}, func(v int) {
              fmt.Println(v)
        })
   }

可变参数——参数数量不固定的函数形式

所有参数都是可变参数:fmt.Println

func Println(a ...interface{}) (n int, err error) {
    return Fprintln(os.Stdout, a...)
}

fmt.Println在使用时,传入的值类型不受限制,例如:

fmt.Println(5, "hello", &struct{ a int }{1}, true)

当可变参数为 interface{} 类型时,可以传入任何类型的值

部分参数 是可变参数:fmt.Printf

fmt.Printf的第一个参数为参数列表,后面的参数是可变参数:

func Printf(fORMat string, a ...interface{}) (n int, err error) {
	return Fprintf(os.Stdout, format, a...)
}
------------------------------------------------------
fmt.Printf("pure string\n")
fmt.Printf("value: %v %f\n", true, math.Pi)

1.3 闭包

闭包可以理解成定义在函数内部的一个函数。本质上,闭包是函数内部和函数外部连接起来的桥梁。简单来说,闭包=函数+引用环境

func main() {
	var f = add()
	fmt.Printf("f(10): %v\n", f(10))
	fmt.Printf("f(20): %v\n", f(20))
	// f(10): 10
	// f(20): 30
}
func add() func(int) int {
	var x int
	return func(y int) int {
		x += y
		return x
	}
}

1.4 defer语句

defer语句将其后面跟随的语句进行延迟处理,被defer的语句按先进后出的方式执行(最先defer的语句最后执行,后被defer的语句先执行)。

特性:

  • 关键字defer用于注册延迟调用
  • 直到调用return之前才执行(故可用来作资源清理)
  • 多个defer语句,FILO方式执行
  • defer中的变量,在defer声明时就定义了

用途:

处理运行时发生的错误

Go语言的错误处理思想及设计包含以下特征:

  •  一个可能造成错误的函数,需要返回值中返回一个 错误接口(error )。如果调用是成功的,错误接口将返回nil,否则返回错误。
  • 在函数调用后需要检查错误,如果发生错误,进行必要的错误处理。

错误接口的定义格式

error是Go系统声明的接口类型,代码如下:

type error interface {
    Error() string    // 返回错误的具体描述.
}

所有符合Error() string格式的接口都能实现错误接口。

定义一个错误

在Go语言中,使用errors包进行错误的定义,格式如下:

var err = errors.New("this is an error")

错误字符串由于相对固定,一般在包作用域声明, 应尽量减少在使用时直接使用errors.New返回。

宕机(panic)——程序终止运行

手动触发宕机

Go语言可以在程序中手动触发宕机,让程序崩溃,这样开发者可以及时地发现错误,同时减少可能的损失。

Go语言程序在宕机时,会将堆栈和goroutine信息输出到控制台,所以宕机也可以方便地知晓发生错误的位置。

package main
func main() {
panic("crash")
}

panic()的参数可以是任意类型,

当panic()触发的宕机发生时,panic()后面的代码将不会被运行,但是在panic()函数前面已经运行过的defer语句依然会在宕机发生时发生作用,

1.5 宕机恢复(recover)——防止程序崩溃

无论是代码运行错误由Runtime层抛出的panic崩溃,还是主动触发的panic崩溃,都可以配合defer和recover实现错误捕捉和恢复,让代码在发生崩溃后允许继续运行。

Go没有异常系统,其使用panic触发宕机类似于其他语言的抛出异常,那么recover的宕机恢复机制就对应try/catch机制。

panic和recover的关系:

  • 有panic没recover,程序宕机。
  • 有panic也有recover捕获,程序不会宕机。执行完对应的defer后,从宕机点退出当前函数后继续执行。

提示:虽然panic/recover能模拟其他语言的异常机制,但并不建议代表编写普通函数也经常性使用这种特性。

2. 结构体

结构体成员是由一系列的成员变量构成,这些成员变量也被称为“字段”。

字段有以下特性:

  • 字段拥有自己的类型和值。
  • 字段名必须唯一。
  • 字段的类型也可以是结构体,甚至是字段所在结构体的类型。

Go语言中没有“类”的概念,也不支持“类”的继承等面向对象的概念。

Go语言的结构体与“类”都是复合结构体,但Go语言中结构体的内嵌配合接口比面向对象具有更高的扩展性和灵活性。

Go语言不仅认为结构体能拥有方法,且每种自定义类型也可以拥有自己的方法。

2.1 定义与给结构体赋值

基本形式:

type Point struct {
	X int
	Y int
}
var p Point
p.X = 10
p.Y = 20

结构体的定义只是一种内存布局的描述,只有当结构体实例化时,才会真正地分配内存

创建指针类型的结构体:

type Player struct {
	name string
	age int
}
p = new(Player)
p.name = "james"
p.age = 40

取结构体的地址实例化:

//使用结构体定义一个命令行指令(Command),指令中包含名称、变量关联和注释等
type Command struct {
	name string
	Var *int
	comment string
}
var version int = 1
cmd := &Command{}
cmd.name = "version"
cmd.Var = &version
cmd.comment = "show version"

使用键值对填充结构体:

type People struct {
	name string
	child *People
}
relation := &People{
	name: "爷爷"
	child: &People{
		name: "爸爸"
		child: &People{
			name: "我"
		},
	}
}

3. 方法

Go语言中的方法(Method)是一种作用于特定类型变量的函数。这种特定类型变量叫做接收器( Receiver )。

如果将特定类型理解为结构体或“类”时,接收器的概念就类似于其他语言中的 this 或者 self 。

3.1 结构体方法

创建一个背包 Bag 结构体为其定义把物品放入背包的方法 insert :

type Bag struct {
	items[] int
}
func (b *Bag) insert(itemid int) {
	b.items = append(b.items, itemid)
} 
func main() {
	b := new(Bag)
	b.insert(1001)
}

(b*Bag) 表示接收器,即 Insert 作用的对象实例。每个方法只能有一个接收器。

3.2 接收器

接收器是方法作用的目标

接收器根据接收器的类型可分:

  • 指针接收器
  • 非指针接收器
  • 两种接收器在使用时会产生不同的效果。根据效果的不同,两种接收器会被用于不同性能和功能要求的代码中。

指针接收器

由于指针的特性,调用方法时,修改接收器指针的任意成员变量,在方法结束后,修改都是有效的。

// 定义属性结构
type Property struct {
	value int
}
// 设置属性值方法
func (p *Property) setVal(val int) {
	p.value = val
}
// 获取属性值方法
func (p *Property) getVal() int {
	return p.value
}
func main() {
	p := new(Property)
	p.value = 123
	fmt.Println(p.getVal())
	p.setVal(666)
	fmt.Println(p.getVal())
}

非指针类型接收器

当方法作用于非指针接收器时,Go语言会在代码运行时 将接收器的值复制一份 。在非指针接收器的方法中可以获取接收器的成员值, 但修改后无效 。

type Point struct {
	x, y int
}
func (p Point) add(other Point) Point {
	return Point{p.x + other.x, p.y + other.y}
}
func main() {
	// 初始化点
	p1 := Point{1, 1}
	p2 := Point{2, 2}
	res := p1.add(p2)
	fmt.Println(res)

	p3 := Point{3, 3}
	p4 := p1.add(p2).add(p3)
	fmt.Println(p4)
}

指针接收器和非指针接收器的使用:

指针和非指针接收器的使用在计算机中, 小对象 由于值复制时的速度较快,所以适合使用非指针接收器。 大对象 因为复制性能较低,适合使用指针接收器,在接收器和参数间传递时不进行复制,只是传递指针。

4. 接口

接口是双方约定的一种合作协议。接口实现者不需要关心接口会被怎样使用,调用者也不需要关心接口的实现细节。 接口是一种类型,也是一种抽象结构,不会暴露所含数据的格式、类型及结构。

4.1 声明接口

type 接口类型名 interface {
	方法1(参数列表) 返回值
	...
}

Go语言的接口在命名时,一般会在单词后面添加er,如有写操作的接口叫Writer,有字符串功能的接口叫Stringer,有关闭功能的接口叫Closer等

方法名:当方法名首字母是大写时,且这个接口类型名首字母也是大写时,这个方法可以被接口所在的包(package)之外的代码访问。

io包中提供的Writer接口:

type Writer interface {
	Write(p []type) (n int, err error)
}

4.2 实现接口

实现接口的条件:

  • 接口的方法与实现接口的类型方法格式一致
  • 接口中所有方法均被实现

例:为了抽象数据写入的过程,定义Data Writer接口来描述数据写入需要实现的方法。

// 定义一个数据写入器接口
type DataWriter interface {
	WriteData(data interface{}) error
}
// 定义文件结构,用于实现DataWriter
type file struct {
}
// 实现DataWriter接口的方法
func (d *file) WriteData(data interface{}) error {
	// 模拟写入数据
	fmt.Println("Write Data:", data)
	return nil
}
func main() {
	// 实例化file
	f := new(file)
	// 声明一个DataWriter接口
	var writer DataWriter
	// 将接口赋值,也就是*file
	writer = f
	writer.WriteData("one line data")
}

Go语言的接口实现是隐式的,无须让实现接口的类型写出实现了哪些接口。这个设计被称为非侵入式设计。

到此这篇关于Go语言学习函数+结构体+方法+接口的文章就介绍到这了,更多相关Go 函数内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

您可能感兴趣的文档:

--结束END--

本文标题: Go语言学习函数+结构体+方法+接口

本文链接: https://lsjlt.com/news/149492.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • Go语言学习函数+结构体+方法+接口
    目录1. 函数1.1 函数返回值同一种类型返回值带变量名的返回值函数中的参数传递函数变量1.2 匿名函数——没有函数名字的函数在定义时调用匿名函数将匿名函数赋...
    99+
    2024-04-02
  • Go语言学习函数+结构体+方法+接口
    目录1. 函数1.1 函数返回值同一种类型返回值带变量名的返回值函数中的参数传递函数变量1.2 匿名函数——没有函数名字的函数在定义时调用匿名函数将匿名...
    99+
    2022-06-07
    GO 结构体 方法 学习 函数 go语言 接口
  • Go语言函数、结构体、方法和接口怎么用
    本篇内容介绍了“Go语言函数、结构体、方法和接口怎么用”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!1. 函数Go语言的函数属于“一等公民”...
    99+
    2023-06-30
  • Go语言学习之结构体和方法使用详解
    目录1. 结构体别名定义2. 工厂模式3. Tag 原信息4. 匿名字段5. 方法1. 结构体别名定义 变量别名定义 package main import "fmt" type...
    99+
    2024-04-02
  • Go语言结构体Gorange的学习教程
    目录正文Go Range正文 在前一篇博客我们学习了 Go 数组,其要求所有元素为同一数据类型,如果希望存储不同类型的数据,就要用到结构体相关知识。 结构体的定义:存储相同或不同类型...
    99+
    2024-04-02
  • Go语言之结构体与方法
    目录一、结构体1、结构体的定义与使用2、定义并赋初值3、匿名结构体(只使用一次,没有名字)4、结构体的零值5、结构体的指针6、匿名字段(字段没有名字,只有类型)7、嵌套结构体(结构体...
    99+
    2024-04-02
  • Go语言学习教程之结构体的示例详解
    目录前言可导出的标识符嵌入字段提升标签结构体与JSON相互转换结构体转JSONJSON转结构体练习代码步骤前言 结构体是一个序列,包含一些被命名的元素,这些被命名的元素称为字段(fi...
    99+
    2024-04-02
  • Go语言中如何使用结构体构造函数
    这篇文章将为大家详细讲解有关Go语言中如何使用结构体构造函数,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。Go语言的结构体 构造函数下面的代码就实现了一个P...
    99+
    2024-04-02
  • 深入学习Go语言数据结构的奥秘
    深入学习Go语言数据结构的奥秘,需要具体代码示例 Go语言作为一门简洁、高效的编程语言,在处理数据结构方面也展现出了其独特的魅力。数据结构是计算机科学中的基础概念,它旨在组织和管理数据...
    99+
    2024-04-02
  • go语言中结构体方法如何定义
    本篇内容主要讲解“go语言中结构体方法如何定义”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“go语言中结构体方法如何定义”吧!go语言中结构体方法的定义方法:1、定义一个结构体,语法“type ...
    99+
    2023-07-05
  • go语言结构体指针操作的方法
    本篇内容介绍了“go语言结构体指针操作的方法”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!指针指针是代表某个内存地址的值。内存地址储存另一个...
    99+
    2023-06-30
  • go语言结构体定义有哪些方法
    go语言结构体定义的方法有:1、直接定义结构体字段;2、使用嵌入结构体;3、定义带有方法的结构体;4、使用指针类型作为结构体字段;5、使用数组或切片作为结构体字段。在Go语言中,可以使用结构体来定义一组相关字段的集合,这些字段可以是基本数据...
    99+
    2023-12-12
    go语言 结构体
  • GO语言中接口和接口型函数的具体使用
    目录前言GO语言中的接口怎么用?使用函数类型实现接口有何好处?GO源码例子前言 今天在编码中,看到了一个非常经典的接口用法如下,于是查阅了相关资料,发现此种写法为接口型函数,本文对此...
    99+
    2023-03-09
    GO语言接口 GO语言接口型函数
  • Go语言基础语法之结构体及方法详解
    结构体类型可以用来保存不同类型的数据,也可以通过方法的形式来声明它的行为。本文将介绍go语言中的结构体和方法,以及“继承”的实现方法。 结构体类型 结构体类型(struct)在go语...
    99+
    2024-04-02
  • Go语言数据结构之双链表学习教程
    目录双链表创建节点双链表遍历扩展功能链表长度插入删除反转双链表总结双链表 双链表 (Doubly Linked List),每个节点持有一个指向列表前一个元素的指针,以及指向下一个元...
    99+
    2024-04-02
  • C语言中的结构体内嵌函数用法
    目录C语言的结构体内嵌函数1.内嵌函数定义举例:经过真实测试2.内嵌函数的个人理解结构体嵌套函数指针解释总结C语言的结构体内嵌函数 看门见山 1.内嵌函数定义举例:经过真实测试 在函...
    99+
    2023-02-24
    C语言结构体 C语言函数 结构体内嵌函数
  • 深入探究Go语言结构体方法的定义
    深入理解Go语言结构体定义的方法,需要具体代码示例 引言 Go语言是一门简洁高效的编程语言,在其核心特性中,结构体是一个非常重要的概念。与其他编程语言不同,Go语言的结构体不仅可以包含属性字段,还可以定义与结...
    99+
    2024-02-02
    方法 go语言 结构体定义
  • C语言新手练习之多维数组、结构体及函数
    1887 颜色精简 题目: 有一个颜色集合,里面有若干个颜色值(RBG系统表示)。现在有若干个颜色值需要映射到集合中的某个值。具体的映射方法是找到集合中和它的颜色距离最小的进行映射。...
    99+
    2024-04-02
  • Go语言学习之new函数的用法详解
    目录1、new函数介绍2、示例3、总结1、new函数介绍 在 Go 语言中,new 函数用于动态地分配内存,返回一个指向新分配的零值的指针。它的语法如下: func new(Type...
    99+
    2023-05-20
    Go new函数用法 Go new函数 Go new
  • C语言结构体的具体使用方法
    目录初识C语言结构体1.为什么要有结构体2.结构体的定义2.1结构体类型的定义2.2定义结构体普通变量及访问2.3定义结构体指针变量及访问初识C语言结构体 1.为什么要有结构体 (1...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作