go语言使用总结(持续更新)

server/2024/11/14 20:01:17/

整理后的内容如下:


1. 先了解函数签名,再了解传入参数以及调用

  • 函数签名是函数的声明部分,包括函数名、参数列表和返回值列表。理解函数签名是理解函数行为的第一步,尤其是在了解参数类型、参数数量和返回值类型等方面。
  • 通过了解函数签名,可以确定函数在调用时需要什么样的输入(参数类型和数量)以及函数会返回什么样的结果。

示例

func add(a int, b int) int {return a + b
}
  • 函数 add 的签名 func add(a int, b int) int 表示它接收两个 int 类型的参数并返回一个 int 类型的结果。
  • 在使用一个函数前,了解其签名有助于确定如何传递参数和如何处理返回值。

2. 传入参数是某种类型,只要有变量实现了这个类型,那么这个变量就可以作为参数传入

  • 在 Go 语言中,如果一个参数类型是接口类型,只要一个变量实现了该接口中的方法,那么该变量就可以作为这个接口类型的参数传入。
  • 这就是 Go 中的接口的实现方式:只要类型实现了接口的所有方法,那么这个类型自动满足该接口,无需显式声明实现。

示例

type Speaker interface {Speak() string
}type Dog struct{}func (d Dog) Speak() string {return "Woof!"
}func MakeNoise(s Speaker) {fmt.Println(s.Speak())
}func main() {d := Dog{}MakeNoise(d)  // d 是 Dog 类型,但它实现了 Speak 方法,因此满足 Speaker 接口
}
  • Dog 类型实现了 Speaker 接口的方法 Speak,因此可以作为 Speaker 类型的参数传入 MakeNoise 函数。

3. 构造函数返回值一般都是指针类型有什么问题吗

  • 在 Go 中,构造函数返回指针类型(如 *Type)是常见的设计模式。返回指针类型的构造函数有几个优点:
    • 效率:对于大型结构体,返回指针避免了结构体数据的拷贝,提升了效率。
    • 易于修改:返回指针类型允许调用者对返回对象进行修改,而不会影响原有的对象。
    • 方法调用:如果方法是定义在指针类型上(如 func (t *Type) Method()),那么必须返回一个指针,才能调用这些方法。

可能的问题

  • 内存管理:返回指针会在堆上分配内存,可能增加垃圾回收的负担。因此对于小型的不可变结构体,直接返回值类型更合适。
  • 不可变性:指针类型的返回值可以被外部修改,可能导致不安全的状态变更。如果不希望对象被外部修改,返回值类型会更合适。

示例

type Config struct {URL string
}func NewConfig(url string) *Config {return &Config{URL: url}  // 返回指针类型
}func main() {config := NewConfig("http://localhost")fmt.Println(config.URL)  // 直接使用指针调用字段
}

在 Go 中,返回指针类型通常用于允许共享对象状态,但根据实际需求,可以选择返回值类型或指针类型。


4. 使用 Go Modules 的注意点

在使用 Go Modules 时,如果 main.gogeecache/ 在同级目录下,不能再使用 import 相对路径进行模块引用。为了在 Go Modules 中正确引入本地模块,可以在 go.mod 中声明模块替换:

require geecache v0.0.0
replace geecache => ./geecache

通过 replace 指令将 geecache 映射为本地路径 ./geecache,可以在项目中以模块方式正确引用本地包。

这是 Go 语言中的接口实现语法,具体而言,它利用了 隐式接口实现 的特性。

5. 隐式接口实现

在 Go 语言中,如果一个类型(例如 ByteView)实现了某个接口(例如 Value)的所有方法,那么它就自动满足该接口,无需显式声明“实现了”这个接口。这种机制称为 隐式接口实现。因此,在 Go 中,接口是通过结构体的方法集合来判断是否满足接口的,而不是通过显式声明。

示例解释
type Value interface {Len() int
}type ByteView struct {b []byte
}func (v ByteView) Len() int {return len(v.b)
}

在上面的代码中:

  • Value 接口定义了一个 Len() 方法。
  • ByteView 类型实现了 Len() 方法,因此满足了 Value 接口的要求。
  • Go 编译器会自动将 ByteView 视为 Value 类型,因为它实现了接口所要求的全部方法。
接口变量的多态性

因为 ByteView 实现了 Value 接口,所以可以将 ByteView 的实例赋值给一个 Value 类型的变量。这种用法允许 Go 语言的接口具有多态性

var v Value
v = ByteView{b: []byte("Hello, World!")}
fmt.Println(v.Len())  // 输出: 13

在这里:

  • v 是一个 Value 类型的接口变量,可以接受任何满足 Value 接口的类型。
  • ByteView 实现了 Len() 方法,因此可以赋值给 v
  • 调用 v.Len() 时,实际上会调用 ByteView.Len() 方法。
接口解耦

Go 的接口实现方式使得代码的模块化和解耦更加灵活:

  • Cache 可以依赖 Value 接口,而不是依赖具体的 ByteView 类型。
  • 这样一来,只要其他类型实现了 Len() 方法,也可以被 Cache 使用,具有更好的扩展性。

6. 函数式接口作用

函数式接口在 Go 中的意义主要体现在简化代码结构增强代码灵活性提高复用性方面。Go 语言中的函数式接口通常是通过类型别名实现的,允许将函数作为参数传递,使得代码更具模块化和扩展性。以下是函数式接口的核心意义和应用场景:

提高代码的灵活性

  • 函数式接口使得代码可以接受行为(函数)作为参数,这样可以根据上下文动态地改变函数的行为,而不需要创建大量的具体实现。
  • 例如,假设有一个缓存系统,需要从数据源加载数据,可以通过函数式接口将数据源的加载逻辑作为参数传入,从而实现不同数据源的适配。

示例

type LoaderFunc func(key string) ([]byte, error)func LoadData(loader LoaderFunc, key string) ([]byte, error) {return loader(key)
}

在使用时,可以传入不同的 LoaderFunc 实现,使 LoadData 能够适配不同的加载逻辑。

减少冗余代码

  • 函数式接口避免了为简单的功能创建单独的结构体和实现方法。对于那些功能性较强但实现相对简单的行为,函数式接口能让代码更加简洁。
  • 在没有函数式接口的情况下,开发者可能需要为每个行为编写一个结构体实现接口,但函数式接口可以避免这种代码膨胀。

增强代码的复用性

  • 使用函数式接口,可以将通用的逻辑和策略抽象出来,赋予代码更高的复用性。例如,数据处理、过滤器、回调处理等场景都可以利用函数式接口,使通用的逻辑可以在不同场景下复用。
  • 例如,可以定义一个泛型的排序逻辑,接受一个比较函数,实现不同的排序策略。

示例

type CompareFunc func(a, b int) boolfunc Sort(data []int, compare CompareFunc) {// 使用 compare 函数进行排序
}

简化依赖注入和测试

  • 函数式接口使得依赖注入更为简便,例如在测试时,可以传入特定的函数来替换真实的服务。这在需要模拟特定行为、简化测试环境设置时特别有用。
  • 例如,可以用一个简单的函数替换数据库查询,使测试代码不依赖于实际的数据库连接。

示例

func MockLoader(key string) ([]byte, error) {return []byte("mock data"), nil
}data, _ := LoadData(MockLoader, "test-key")

http://www.ppmy.cn/server/141617.html

相关文章

ubuntu2204部署RAGFlow(非docker)

安装 Poetry curl -sSL https://install.python-poetry.org | python3 -##下载源代码并安装 Python 依赖 git clone https://github.com/infiniflow/ragflow.git cd ragflow/ export POETRY_VIRTUALENVS_CREATEtrue POETRY_VIRTUALENVS_IN_PROJECTtrue ~/.local/bin/poetry i…

【大数据学习 | HBASE高级】region split机制和策略

1. region split机制 ​ HRegionServer拆分region的步骤是,先将该region下线,然后拆分,将其子region加入到hbase:meta表中,再将他们加入到原本的HRegionServer中,最后汇报Master。 split前:hbase:meta表有…

Chromium 中chrome.webRequest扩展接口定义c++

一、chrome.webRequest 注意 :从 Manifest V3 开始,"webRequestBlocking" 权限不再适用于大多数扩展程序。以 "declarativeNetRequest" 为例,它允许使用 declarativeNetRequest API。除了 "webRequestBlocking&quo…

【HAProxy06】企业级反向代理HAProxy调度算法之其他算法

HAProxy 调度算法 HAProxy通过固定参数 balance 指明对后端服务器的调度算法,该参数可以配置在listen或backend选项中。 HAProxy的调度算法分为静态和动态调度算法,但是有些算法可以根据不同的参数实现静态和动态算法 相互转换。 官方文档&#xff1…

前端页面性能优化的常见问题与解决方案

在当今互联网高速发展的时代,前端页面的性能对于用户体验至关重要。一个加载缓慢、交互卡顿的页面很可能会导致用户流失。本文将深入探讨前端页面性能优化中常见的问题以及相应的解决方案。 一、常见问题 (一)资源加载问题 文件体积过大 …

解决vite项目tailwindcss不生效!!(Vue3、tailwindcss失效)

安装tailwindcss vite自带安装了postcss,只需要安装tailwindcss;没有postcss需要安装!! npm install -D tailwindcss自动创建tailwind.config.js npx tailwindcss init -p/** type {import(tailwindcss).Config} */ module.expor…

已解决:spark代码中sqlContext.createDataframe空指针异常

这段代码是使用local模式运行spark代码。但是在获取了spark.sqlContext之后,用sqlContext将rdd算子转换为Dataframe的时候报错空指针异常 Exception in thread "main" org.apache.spark.sql.AnalysisException: java.lang.RuntimeException: java.lang.Nu…

RandomWords随机生成单词

from random_words import RandomWords rw RandomWords() r rw.random_word() print(r) 更多How to use — random_words documentation (randomwords.readthedocs.io) li LoremIpsum()# 这行代码创建了一个 LoremIpsum 类的实例。li.get_sentence()# 这个方法返回一个随机…