当前位置: 首页 > news >正文

深入解析:go进阶语法

文章目录

  • 函数
    • 参数
    • 返回值
    • Go中的函数参数是传值传递,即在传递参数时会拷贝实参的值
    • defer
  • 方法
  • 接口
  • 泛型
  • 异常

函数

声明和定义:

//声明
var sum func(int,int) int
//定义并使用
func main() {
sum = func(a int, b int) int {
return a + b
}
fmt.Println(sum(1, 2))
}
//声明并定义
func main() {
fmt.Println(sum(1, 2))
}
func sum (a int,b int) int {
return a + b
}

参数

相同类型且相连的形参可以共用同一个类型

func main() {
fmt.Println(sum(1, 2, "1", "2"))
}
func sum(a, b int, c, d string) int {
return a + b
}

和java一样又一个变长参数

func main() {
fmt.Println(sumAll(1, 2, 1, 2))
}
func sumAll(nums ...int) int {
sum := 0
for i := range nums {
sum += i
}
return sum
}

返回值

在Go中,不支持函数重载。
普通返回值及返回多个:类型相同且相邻的参数而言,可以只声明一次类型

返回一个
func returnCal(a,b int) int {
return a + b
}
返回2func returnCal(a, b int) (int,int) {
return a + b,a-b
}
返回三个
func returnCal(a, b int) (int, int, int) {
return a + b, a - b, a / b
}

具名返回值

func returnCal(a, b int) (res int) {
res = a + b
return
}
相当于,就是把返回值的声明放到了函数声明里面
func returnCal(a, b int) (int) {
var res int;
res = a+b
return res
}
也可以声明多个,像下面这样
func returnCal(a, b int) (c, d int) {
c = a + b
b = a - b
return
}

Go中的函数参数是传值传递,即在传递参数时会拷贝实参的值

这里笔者花了很长时间才理解,总结如下:
Go 中的 slice、map、chan、string 本质上都是 带指针的结构体(header)
函数传参时 Go 总是 传值:它会把这个结构体整体 拷贝一份,但结构体内部的指针字段的值保持不变
因此 两个变量虽然是不同的结构体副本,却都指向同一块底层数据。
所以它们表现得像“引用传递”,但本质仍然是“值传递,只是值里包含指针”。

类比java中就是,java的所有引用类型都是一个类(相当于go中的结构体),但是类就是对象,只需要拷贝其在栈上的引用即可,但是go会拷贝除结构体中引用部分的整个结构体。

请添加图片描述

defer

在函数返回之前执行,类似于java中的finally

func test13() any {
defer fmt.Println(2)
return 1
}

但是:
defer 后面的函数参数会立即计算,不是等到执行时才计算。

注意:2两种情况
第一种:具名返回值

func test13() (x int) {
x = 10
defer func() {
x++ // 能改返回值
}()
return
}
//结果是11

第二种情况:匿名返回值

func test13() (int) {
x := 10
defer func() {
x++ // 能改返回值
}()
return x
}
// 结果是10

为什么呢,笔者这里详细解释下:
具名返回值 = 函数返回值本身是一个变量 → defer 能改它
匿名返回值 = return 的结果是一个值副本 → defer 改不到

方法

方法这个定义在go里面对应有java开发经验的人来说很不好理解:
笔者这里简单通俗易懂的解释下:
在java中方法是属于类的,只有类对象可以调用方法,如:obj.func()…,但是在go中是没有类的,但是我需要让我的自定义的类型拥有自定义的方法(这里可以理解为自定义的java类中自定义一些方法)

那怎么做呢?

那就先定义一个自定义的类型,再定义自定义的方法
再标识这些自定义的方法属于自定义的类型
这要就可以通过自定义的类型调用这些独属于自己自定义的方法了

例:

// 先定义一个自定义类型:
type NameSlice []string
// 定义一个i 是NameSlice 类型的变量理解为java中的this,标识这个方法属于i
func (i NameSlice) getByIndex(index int) string {
return i[index]
}
// 定义一个i 是NameSlice 类型的变量理解为java中的this,标识这个方法属于i
func (i NameSlice) setByIndex(index int, value string) {
i[index] = value
}
func main() {
nameSlice := NameSlice{"zs", "ls", "ww"}
nameSlice.setByIndex(0, "abc")
fmt.Println(nameSlice.getByIndex(0))
}
//输出abc

接口

其实这个接口和java中的接口差不多,也是一个interface,里面只写一个方法声明,留给其他结构体去继承
但是注意:go中的实现接口是隐式的。不会有特殊的关键字说明某个结构体实现了某个接口
所以判断结构体实现某个接口的方法:一个结构体(或任意类型)必须实现接口里的“全部方法”,一个都不能少,否则就不算实现接口
例:

func main() {
dog := Animal(Dog{name: "xww", legCount: 4})
dog.sayName()
fmt.Println(dog.getLegCount())
}
// 动物接口
type Animal interface {
sayName()
getLegCount() int
}
// 狗 结构体
type Dog struct {
name     string
legCount int
}
//实现 动物sayName方法
func (dog Dog) sayName() {
fmt.Println(dog.name)
}
//实现 动物getLegCount方法
func (dog Dog) getLegCount() int {
return dog.legCount
}

空接口:
空接口是一个特殊的接口:空接口中没有任何方法

type Any interface{}

一个类型只要实现了接口的所有方法,才算实现接口,所以空接口没有方法 → 所有类型都满足要求

看看下面这个

func main() {
x := any(1)
y := interface{}(1)
fmt.Println(x, y)
}
// 这2种写法是等价的,在go内部会声明type any = interface{}

接口内部可以看成是一个由(val,type)组成的元组,type是具体类型,在调用方法时会去调用具体类型的具体值。

泛型

Java中的泛型就是任意类型T,可以接受任意类型的变量,但是go中的泛型实际上是限制变量的类型范围
比如:
1.函数形参泛型

func sum[T int | float64](a, b T) T {
return a + b
}

类似于java的

public static <T extends Number> T sum(T a, T b)

2.结构体泛型

func main() {
student := Student[int]{
Name: "jack",
Id:   1024,
}
fmt.Println(student)
}
type Student[T int | string] struct {
Name string
Id   T
}

3.泛型接口

func main() {
child1 := Child[string]{
Msg: "呱呱呱",
}
fmt.Println(child1)
child2 := Child[int]{
Msg: 111122223333,
}
fmt.Println(child2)
}
type Say[T int | string] interface {
say() T
}
type Child[T int | string] struct {
Msg T
}
func (c Child[T]) say() T {
return c.Msg
}

异常

再java中异常处理就是throw或 try catch,再go中,异常不需要捕获,而是作为返回值传递给了调用方

file, err := os.Open("README.txt")
if err != nil {
fmt.Println("文件打不开:", err)
return
}
fmt.Println(file.Name())

手动创建异常:

err := errors.New("这是一个错误")
//得到一个格式化参数的error
err = fmt.Errorf("这是%d个格式化参数的的错误", 1)
fmt.Println(err)

打印异常:

// 没有包装异常,直接输出错误信息,把错误变成普通字符串
fmt.Printf("%v", errors.New("a"))
// 创建异常链,能追踪到原始错误
fmt.Printf("%w", errors.New("a"))

一般上面的输入都打印不了异常栈

使用"github.com/pkg/errors"打印异常栈:

import (
"fmt"
"strings"
"github.com/pkg/errors"
)
func main() {
fmt.Printf("%+v", getErr())
}
func getErr() error {
return errors.New("aabbcc")
}urn errors.New("aabbcc")
}
/**
输出
aabbcc
main.getErr
C:/dev/com/goTest/demoProject1/main.go:15
main.main
C:/dev/com/goTest/demoProject1/main.go:11
runtime.main
C:/dev/devtool/go/src/runtime/proc.go:285
runtime.goexit
C:/dev/devtool/go/src/runtime/asm_amd64.s:1693
*/

1.error:这是最标准的 Go 错误方式,用 errors.New 或 fmt.Errorf 创建,通过返回值往上层传递,完全等价于 Java 中 返回错误对象,而不是抛异常
2.panic(严重错误/不可恢复):用于 崩溃程序 的情况,例如:访问越界空指针(nil dereference)程序自身无法继续运行,对比 Java类似 try { … } catch(Exception e) {},但只能在 defer 中使用
常用于:防止 goroutine 崩掉整个程序
3.recover(从 panic 恢复):用于捕获 panic 让程序继续运行,只能在 defer 中使用。

如:

func run() {
defer func() {
if r := recover(); r != nil {
fmt.Println("捕获 panic:", r)
}
}()
panic("fatal")
}
http://www.jsqmd.com/news/316823/

相关文章:

  • 2026年垃圾压缩机厂家权威推荐榜:水平地埋式垃圾压缩机/移动一体式垃圾压缩机/三缸四柱直压式垃圾压缩机/垃圾压缩机安装/选择指南
  • 细聊驰创轴承评价如何,听听用户的真实声音
  • 前端倒计时活动,为什么不推荐直接用 setTimeout / setInterval?
  • 一张图看懂产品热设计全流程:从需求到验证的关键步骤与角色协作
  • 2026年福州靠谱阀门厂家排名,永园阀门名列前茅
  • 看懂风扇的“里外”:原理、构造、性能与计算的系统性解读
  • 聊聊智能型高压预付费装置供应商,哪家性价比高看这里
  • 2026年动物油设备排名,看看宏九动物油设备品牌在市场的影响力
  • 涛思数据库-数据源配置
  • 2026常州市英语雅思培训机构推荐,权威英语雅思课程学校排行榜
  • 2026年工业用彩漂液厂家五大年度榜:主打液体彩漂 粉体彩漂 彩漂液 彩漂粉 水洗厂彩漂液 洗涤剂彩漂液 主洗剂彩漂液 低温彩漂粉 速溶高效彩漂粉 27.5%彩漂液 35%彩漂液
  • 2026年正规垃圾压缩机优质公司推荐
  • 2026年著名除甲醛公司排名,长沙尚洁环保乐净石高性价比之选
  • 字符串专题 #1
  • 分析上海口碑好的代理记账企业,看看都有谁
  • 零基础PHP从零到一实现上一页和下一页的庖丁解牛
  • 2026景区游乐设备厂家选型参考:安全合规与场景融合的理性指南
  • 跳跃游戏 II | 贪心算法最优解(最少跳跃次数)
  • 深入剖析CVE-2025-20354:思科CCX系统高危RCE漏洞详解
  • AI生成测试用例的全面性优势:技术机理与实践验证
  • 我让AI读了1000个测试用例,总结出“好用例”的5个特征
  • 写论文软件哪个好?实测 10 款工具后,虎贲等考 AI 凭 “全流程闭环” 稳赢
  • 10个技巧:用AI自动生成测试报告
  • 【收藏必学】大模型技术全解析:从入门到实践的人工智能核心指南
  • 2026可靠伦茨减速机优质厂家推荐榜:伦茨制动器、伦茨变频器、伦茨控制器、伦茨直流调速器、伦茨维修、伦茨驱动器选择指南
  • 常州市英语雅思培训机构推荐,2026权威测评出国雅思辅导机构口碑榜单.
  • 终极预测:2030年,AI将自动编写测试用例?
  • 实时AI监控测试实战:从理论到落地的全面指南
  • AI创作避坑 学术党实测有效,免费搞定查重+绘图+改稿
  • 震惊!这3个VS Code插件让调试快如闪电:软件测试从业者的效率革命