Golang代码理解求助:这段Go代码该如何解读?
Golang代码理解求助:这段Go代码该如何解读? 我是Go语言的新手,为了练习,我在Exercism上做一些编码练习。我遇到了一个特定的练习,其中我很难理解其解决方案。以下是代码:
// Ints 定义了一个整数值的集合
type Ints []int
// Lists 定义了一个整数数组的集合
type Lists [][]int
// Strings 定义了一个字符串的集合
type Strings []string
// Keep 过滤一个整数集合,只保留使提供的函数返回 true 的成员。
func (i Ints) Keep(strainer func(int) bool) (o Ints) {
for _, v := range i {
if strainer(v) {
o = append(o, v)
}
}
return
}
// Discard 过滤一个集合,只保留使提供的函数返回 false 的成员。
func (i Ints) Discard(strainer func(int) bool) Ints {
return i.Keep(func(n int) bool { return !strainer(n) })
}
我的问题在于 Discard 方法。我们返回一个调用 Keep 方法的 Ints 类型值,但我不理解后面花括号内的返回语句。既然 Keep 函数应该返回一个 Ints 类型的值,为什么函数内部会有一个布尔语句。如果有人能为我分解一下 Discard 函数,我将不胜感激。
谢谢
更多关于Golang代码理解求助:这段Go代码该如何解读?的实战教程也可以访问 https://www.itying.com/category-94-b0.html
Discard 通过一个取反的谓词调用 Keep。
这就是技巧所在。
“丢弃所有偶数值”意味着“保留所有奇数值”,Discard 的实现正是使用了这一点。
嗨 Rachid,
Discard 方法可以这样写:
func (i Ints) Discard(strainer func(int) bool) Ints {
myStrainer:= func(n int) bool { return !strainer(n)}
return i.Keep(myStrainer)
}
我希望这能清楚地解释为什么这个方法可以编译通过:它返回的是对 i.Keep() 调用的返回值,也就是 Ints 类型。而 bool 值是由传递给 i.Keep() 的函数返回的。
这段代码中的 Discard 方法实现得很巧妙,它通过调用 Keep 方法并反转判断逻辑来实现过滤功能。让我详细解释一下:
代码解读
Discard 方法的核心是这一行:
return i.Keep(func(n int) bool { return !strainer(n) })
分解理解:
- 方法签名:
func (i Ints) Discard(strainer func(int) bool) Ints
- 接收器:
i Ints(要处理的整数切片) - 参数:
strainer func(int) bool(判断函数) - 返回值:
Ints(过滤后的整数切片)
- 实现逻辑:
i.Keep(func(n int) bool { return !strainer(n) })
- 这里创建了一个匿名函数作为参数传递给
Keep方法 - 匿名函数的逻辑:
return !strainer(n) - 这意味着:对于每个元素
n,先调用原始的strainer(n),然后取反(!)
具体示例:
假设我们有一个整数切片和判断函数:
numbers := Ints{1, 2, 3, 4, 5}
isEven := func(n int) bool { return n%2 == 0 }
使用 Keep 方法:
evens := numbers.Keep(isEven) // 结果为 [2, 4]
// 因为 isEven(2)=true, isEven(4)=true
使用 Discard 方法:
odds := numbers.Discard(isEven) // 结果为 [1, 3, 5]
// 实际执行:numbers.Keep(func(n int) bool { return !isEven(n) })
// !isEven(1)=true, !isEven(3)=true, !isEven(5)=true
等价的手动实现:
如果不使用 Keep 方法,Discard 可以这样实现:
func (i Ints) Discard(strainer func(int) bool) (o Ints) {
for _, v := range i {
if !strainer(v) { // 注意这里的取反操作
o = append(o, v)
}
}
return
}
关键点总结:
Discard利用了Keep的现有逻辑- 通过传递一个取反的判断函数给
Keep,实现了相反的功能 - 这是一种常见的函数式编程模式,避免了代码重复
- 匿名函数
func(n int) bool { return !strainer(n) }创建了一个新的判断函数,它总是返回原始判断函数的相反结果
这种设计体现了Go语言的简洁性和函数作为一等公民的特性,通过组合现有函数来创建新功能,而不是重复实现相似的逻辑。


