[Go语言快速上手]函数和包

目录

一、Go中的函数

函数声明

 多个返回值

可变参数

匿名函数

值传递和地址传递

函数执行顺序(init函数)

二、Go中的包

基本语法

主要包(main package)

导入其他包

包的作用域

包的使用

包名别名

小结


一、Go中的函数

        Go中的函数与其他函数中功能大差不差,只是格式不同,当然也更加简便,从中可以看到其他语言的影子,但是开发效率会高上不少。

函数声明

  • 函数签名:函数的声明包括函数名、参数列表和返回类型。
  • 参数:可以在函数定义中指定参数的名字和类型。
  • 返回值:可以指定函数返回的类型。如果函数不需要返回任何值,可以使用 () 表示无返回值。

一个简单的Go函数定义如下:

package main

import "fmt"

// 定义一个名为 add 的函数,接受两个 int 参数,返回一个 int 结果
func add(a int, b int) int {
    return a + b
}

func main() {
    // 调用 add 函数
    result := add(2, 3)
    fmt.Println("结果是:", result)
}

 多个返回值

我们的返回值列表也可以设置多返回值,这个C++中可能就要设置自定义数据类型或者模板来实现,而Go提供了很便捷的方法,直接定义返回值列表返回即可

func divide(a int, b int) (int, error) {
    if b == 0 {
        return 0, fmt.Errorf("除数不能为零")
    }
    return a / b, nil
}

func main() {
    result, err := divide(10, 2)
    if err != nil {
        fmt.Println("错误:", err)
    } else {
        fmt.Println("结果是:", result)
    }
}

可变参数

如果你想要传递可变数量的参数给一个函数,可以使用 ... 操作符

func sum(nums ...int) int {
    total := 0
    for _, num := range nums {
        total += num
    }
    return total
}

func main() {
    result := sum(1, 2, 3, 4, 5)
    fmt.Println("总和是:", result)
}

匿名函数

你也可以定义匿名函数,并将其赋值给一个变量或立即调用:

func main() {
    sum := func(nums ...int) int {
        total := 0
        for _, num := range nums {
            total += num
        }
        return total
    }

    result := sum(1, 2, 3, 4, 5)
    fmt.Println("总和是:", result)
}

我们来看这一种情况,将函数赋值给一个变量,这个变量就是一个函数,和我们之前学习的函数指针非常像,回调函数的场景应用非常多


func test(args ...int) {
	//函数内部处理可变参数,将可变参数当作切片来处理
	for i := 0; i < len(args); i++ {
		fmt.Println(args[i])
	}
}
func test2(num1 int, num2 int, funct func(args ...int)) {
	funct(num1, num2)
}
func main() {
	//var a = 10
	//var b = 20
	//exchange(&a, &b)
	//fmt.Println(a)
	//fmt.Println(b)
	test(1, 2, 3, 4, 5, 6, 7, 8, 6, 55)
	c := test
	fmt.Printf("c:%T,test:%T\n", c, test)
	c(1, 2, 3, 5, 6, 7, 8)
	test2(1, 2, test) //test和C是完全一样的
	test2(1, 2, c)
}

 可以看到c和test的类型没有任何区别

值传递和地址传递

在C语言中我们直到形参的改变不会引起实参的改变,所以我们需要传递实参的地址 

package main

import "fmt"

func exchange(num1 *int, num2 *int) {
	var tmp int = *num1
	*num1 = *num2
	*num2 = tmp
}

func test(args ...int) {
	//函数内部处理可变参数,将可变参数当作切片来处理
	for i := 0; i < len(args); i++ {
		fmt.Println(args[i])
	}
}
func test2(num1 int, num2 int, funct func(args ...int)) {
	funct(num1, num2)
}
func main() {
	var a = 10
	var b = 20
	exchange(&a, &b)
	fmt.Println(a)
	fmt.Println(b)
	test(1, 2, 3, 4, 5, 6, 7, 8, 6, 55)
	//c := test
	fmt.Printf("c:%T,test:%T", c, test)
	c(1, 2, 3, 5, 6, 7, 8)
	//test2(1, 2, test)
	//test2(1, 2, c)
}

函数执行顺序(init函数)

全局变量初始化:全局变量的初始化按其声明顺序进行。

包级别的 init 函数:每个包中的 init 函数按包的依赖顺序执行。

main 函数:一旦所有初始化完成,程序进入 main 包的 main 函数。

 下面是一个综合示例,展示了全局变量初始化、包级别的 init 函数和 main 函数的执行顺序

// pkg1/init.go
package pkg1

var x = initX()

func initX() int {
    println("初始化 pkg1.x")
    return 10
}

func init() {
    println("pkg1 的 init 函数")
}

// pkg2/init.go
package pkg2

var y = initY()

func initY() int {
    println("初始化 pkg2.y")
    return 20
}

func init() {
    println("pkg2 的 init 函数")
}

// main/main.go
package main

import (
    "pkg1"
    "pkg2"
)

func main() {
    println("main 函数开始")
    println("pkg1.x 的值:", pkg1.x)
    println("pkg2.y 的值:", pkg2.y)
}

输出是

初始化 pkg1.x

pkg1 的 init 函数

初始化 pkg2.y

pkg2 的 init 函数

main 函数开始

pkg1.x 的值: 10

pkg2.y 的值: 20 

二、Go中的包

        在 Go 语言中,包(package)是一个重要的概念,用于组织和复用代码。通过使用包,你可以将相关的函数、类型、变量等组织在一起,从而提高代码的可维护性和可读性。

基本语法

每个 Go 文件必须属于一个包。包的声明位于文件的顶部:

package mypackage

其中 mypackage 是包的名称。通常,包名会反映其功能或用途(一般建议包名和文件夹名称相同)

主要包(main package)

一个特殊的包是 main 包,它是程序的入口点。当编译和运行一个 Go 程序时,默认情况下会编译 main 包。main 包中的 main 函数是程序执行的起点:

package main

import "fmt"

func main() {
    fmt.Println("Hello, world!")
}

导入其他包

你可以通过 import 语句来导入其他包。导入语句通常位于包声明之后,但在任何其他代码之前

如果导入多个包,可以使用这种写法更为便捷

import (
    "fmt"      // 标准库包
    "mypackage" // 自定义包
)

包的作用域

在 Go 中,包内的标识符(如变量、函数、类型等)默认具有包级作用域,这意味着它们只能在同一包内访问。为了使一个标识符在其他包中也能访问,需要将其首字母大写

package common

// 大写的标识符在其他包中可访问
func Add(a int, b int) int {
    return a + b
}

// 小写的标识符只在当前包中可访问
func add(a int, b int) int {
    return a + b
}

包的使用

我们来看一下下图,如果将所有函数都写在一个文件里那么会很难阅读,同时模块划分也会很混乱,所以我们可以把一些工具函数写在其他包中,在需要使用的地方导入包即可。

 我们可以使用这样一个简单的结构来测试

在main中调用common中的Add和db中的Getconn

package db

func Getconn() {
	println("数据库连接")
	println("dbutil函数执行")
}
package aaa

func Add(a int, b int) int {
	println("common_________")
	return a + b
}

main.go

package main

import (
	"fmt"
	"gocode/test_10_2/common"
	"gocode/test_10_2/db"
)

func main() {
	fmt.Println("main函数执行")
	db.Getconn()
	var c int = aaa.Add(1, 5)
	println(c)
	
}

运行输出如下

那同名函数会冲突吗

 

我们在db中也定义一个Add调用,其实也不会冲突,因为需要使用导入的包名作为前缀来调用函数。//在 main 函数中,我们使用 aaa.Add 来调用 Add 函数。这里 aaa 是包名,Add 是函数名。

包名别名

如果导入的包名较长,或者为了避免与其他包名冲突,可以给包起一个别名,比如下面的例子我们就使用了test来当作包名,但是使用了test后就不能再使用原来的包名了

package main

import (
	"fmt"
	test "gocode/test_10_2/common"
	"gocode/test_10_2/db"
)

func main() {
	fmt.Println("main函数执行")
	db.Getconn()
	var c int = test.Add(1, 5)
	println(c)
	var d int = db.Add(3, 4)
	println(d)
}

小结

        以上就是Go中一些函数和包的简单使用,在实际应用场景中可能更多的用法,就需要我们在这些基础上进行操作。函数是 Go 语言中非常灵活的构造,可以用来实现各种复杂的逻辑。合理地组织和使用包,可以使 Go 程序更加模块化和易于维护。确保遵循 Go 的最佳实践,如使用简洁的包名、导出必要的标识符等,可以使代码更加健壮和易用。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/886853.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

[C++]使用纯opencv部署yolov11目标检测onnx模型

yolov11官方框架&#xff1a;https://github.com/ultralytics/ultralytics 【算法介绍】 在C中使用纯OpenCV部署YOLOv11进行目标检测是一项具有挑战性的任务&#xff0c;因为YOLOv11通常是用PyTorch等深度学习框架实现的&#xff0c;而OpenCV本身并不直接支持加载和运行PyTor…

使用python基于DeepLabv3实现对图片进行语义分割

DeepLabv3 介绍 DeepLabv3 是一种先进的语义分割模型&#xff0c;由 Google Research 团队提出。它在 DeepLab 系列模型的基础上进行了改进&#xff0c;旨在提高图像中像素级分类的准确性。以下是 DeepLabv3 的详细介绍&#xff1a; 概述DeepLabv3 是 DeepLab 系列中的第三代…

设计模式-策略模式-200

优点&#xff1a;用来消除 if-else、switch 等多重判断的代码&#xff0c;消除 if-else、switch 多重判断 可以有效应对代码的复杂性。 缺点&#xff1a;会增加类的数量&#xff0c;有的时候没必要为了消除几个if-else而增加很多类&#xff0c;尤其是那些类型又长又臭的 原始代…

基于vue框架的大学生四六级学习网站设计与实现i8o8z(程序+源码+数据库+调试部署+开发环境)系统界面在最后面。

系统程序文件列表 项目功能&#xff1a;学生,训练听力,学习单词,单词分类,阅读文章,文章类型,学习课程 开题报告内容 基于Vue框架的大学生四六级学习网站设计与实现开题报告 一、研究背景与意义 随着全球化进程的加速和国际交流的日益频繁&#xff0c;英语作为国际通用语言…

【前端开发入门】html快速入门

目录 引言一、html基础模板内容二、html文档流三、html 标签1.块级元素2.行内元素3.功能性元素4.标签嵌套 四、html编码习惯五、总结 引言 本系列教程旨在帮助一些零基础的玩家快速上手前端开发。基于我自学的经验会删减部分使用频率不高的内容&#xff0c;并不代表这部分内容不…

vue.js 原生js app端实现图片旋转、放大、缩小、拖拽

效果图&#xff1a; 旋转 放大&#xff1a;手机上可以双指放大缩小 拖拽 代码实现&#xff1a; html <div id"home" class"" v-cloak><!-- 上面三个按钮 图片自己解决 --><div class"headImage" v-if"showBtn">&l…

数据订阅与消费中间件Canal 服务搭建(docker)

MySQL Bin-log开启 进入mysql容器 docker exec -it mysql5.7 bash开启mysql的binlog cd /etc/mysql/mysql.conf.dvi mysqld.cnf #在文件末尾处添加如下配置&#xff08;如果没有这个文件就创建一个&#xff09; [mysqld] # 开启 binlog log-binmysql-bin #log-bin/var/lib/mys…

Linux集群部署RabbitMQ

目录 一、准备三台虚拟机&#xff0c;配置相同 1、所有主机都需要hosts文件解析 2、所有主机安装erLang和rabbitmq 3、修改配置文件 4、导入rabbitmq 的管理界面 5、查看节点状态 6、设置erlang运行节点 7、rabitmq2和rabbitmq3重启服务 8、查看各个节点状态 二、添加…

LC刷题专题:二叉树;迭代;递归(897、1372、208)

文章目录 897.递增顺序搜索树1372. 二叉树中的最长交错路径208. 实现 Trie (前缀树) 897.递增顺序搜索树 https://leetcode.cn/problems/increasing-order-search-tree/description/ 这道题目本身就是一个简单题&#xff1a;非常容易实现&#xff1a;只需要在递归或者迭代中序…

基于spring boot的篮球论坛系统

作者&#xff1a;计算机搬砖家 开发技术&#xff1a;SpringBoot、php、Python、小程序、SSM、Vue、MySQL、JSP、ElementUI等&#xff0c;“文末源码”。 专栏推荐&#xff1a;SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏&#xff1a;Java精选实战项…

每日一练:地下城游戏

174. 地下城游戏 - 力扣&#xff08;LeetCode&#xff09; 题目要求&#xff1a; 恶魔们抓住了公主并将她关在了地下城 dungeon 的 右下角 。地下城是由 m x n 个房间组成的二维网格。我们英勇的骑士最初被安置在 左上角 的房间里&#xff0c;他必须穿过地下城并通过对抗恶魔…

telnet发送邮件教程:安全配置与操作指南?

telnet发送邮件的详细步骤&#xff1f;怎么用telnet命令发邮件&#xff1f; 尽管现代邮件客户端和服务器提供了丰富的功能和安全性保障&#xff0c;但在某些特定场景下&#xff0c;了解如何使用telnet发送邮件仍然是一项有价值的技能。AokSend将详细介绍如何安全配置和操作tel…

数字电路week1

数字电路学习 一.电路基础 1.数字电路仿真软件-digital digital官网&#xff1a;https://github.com/hneemann/Digital?tabreadme-ov-file 建议使用红绿色盲模式 2.异或门 输入1输入2输出000011101110 简单来说就是判断两个输入是否相同 异或门的组成&#xff1a; 异或…

C语言 动态数据结构的C语言实现内存映像

C程序的内存映像 C程序中变量的内存分配方式  C程序中变量的内存分配方式  从静态存储区分配  全局变量和静态变量 C程序中变量的内存分配方式  从静态存储区分配  全局变量和静态变量  在栈上分配  存放函数参数值&#xff0c;局部变量值等  …

国外电商系统开发-运维系统功能清单开发

一、最终效果图 二、功能清单 功能 描述 自定义日志绘图 根据Nginx、Apache登录日志文件绘图&#xff0c;绘图数据包括&#xff1a;访问量走势&#xff0c;500错误&#xff0c;200正确百分比等 创建服务器 加入服务器 主机状态自动检查 加入主机到系统后&#xff0c;系统…

机器学习:opencv--摄像头OCR

目录 前言 一、三个函数 1.显示图像 2.点排序 3.透视变换 二、代码实例 1.打开摄像头 2.图像预处理 3.检测特定轮廓 4.对轮廓进行处理 5.释放资源 前言 摄像头OCR指的是利用摄像头捕捉图像中的文字信息&#xff0c;并通过光学字符识别&#xff08;OCR&#xff09;技…

深度学习----------------------------编码器、解码器架构

目录 重新考察CNN重新考察RNN编码器-解码器架构总结编码器解码器架构编码器解码器合并编码器和解码器 重新考察CNN 编码器&#xff1a;将输入编码成中间表达形式&#xff08;特征&#xff09; 解码器&#xff1a;将中间表示解码成输出。 重新考察RNN 编码器&#xff1a;将文…

CSS 盒子属性

1. 盒子模型组成 1.1 边框属性 1.1.1 四边分开写 1.1.2 合并线框 1.1.3 边框影响盒子大小 1.2 内边距 注意&#xff1a; 1.3 外边距 1.3.1 嵌套块元素垂直外边距的塌陷 1.4 清除内外边距 1.5 总结

EasyExcel使用介绍

EasyExcel使用 1、EasyExcel介绍 1.1 官网介绍 传统操作Excel大多都是利用Apach POI进行操作的&#xff0c;但是POI框架并不完善&#xff0c;使用过程非常繁琐且有较多的缺陷&#xff1a; 动态操作Excel非常繁琐,对于新手来说&#xff0c;很难在短时间内上手;读写时需要占用…

二叉树深度学习——将二叉搜索树转化为排序的双向链表

1.题目解析 题目来源&#xff1a;LCR 155.将二叉搜索树转化为排序的双向链表 测试用例 2.算法原理 首先题目要求原地进行修改并且要求左指针代表前驱指针&#xff0c;右指针代表后继指针&#xff0c;所以思路就是 1.使用前序遍历创建两个指针cur、prev代表当前节点与前一个节点…