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

4 回复

谢谢,我现在明白了。问题在于,当我阅读代码时,没有注意到那是一个匿名函数,结果把我搞糊涂了。

更多关于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) })

分解理解:

  1. 方法签名
func (i Ints) Discard(strainer func(int) bool) Ints
  • 接收器:i Ints(要处理的整数切片)
  • 参数:strainer func(int) bool(判断函数)
  • 返回值:Ints(过滤后的整数切片)
  1. 实现逻辑
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
}

关键点总结:

  1. Discard 利用了 Keep 的现有逻辑
  2. 通过传递一个取反的判断函数Keep,实现了相反的功能
  3. 这是一种常见的函数式编程模式,避免了代码重复
  4. 匿名函数 func(n int) bool { return !strainer(n) } 创建了一个新的判断函数,它总是返回原始判断函数的相反结果

这种设计体现了Go语言的简洁性和函数作为一等公民的特性,通过组合现有函数来创建新功能,而不是重复实现相似的逻辑。

回到顶部