Go true或false应该终止回调迭代吗?

Go true或false应该终止回调迭代吗?,go,foreach,callback,iteration,termination,Go,Foreach,Callback,Iteration,Termination,在某些语言中,通过提供一个回调函数来进行迭代是必要的,或者更简洁,该函数接收项目并返回一个布尔值,指示是继续还是停止迭代 哪一个是表示希望停止/继续的首选值?为什么?有哪些先例 围棋的例子: func IntSliceEach(sl []int, cb func(i int) (more bool)) (all bool) { for _, i := range sl { if !cb(i) { return false }

在某些语言中,通过提供一个回调函数来进行迭代是必要的,或者更简洁,该函数接收项目并返回一个布尔值,指示是继续还是停止迭代

哪一个是表示希望停止/继续的首选值?为什么?有哪些先例

围棋的例子:

func IntSliceEach(sl []int, cb func(i int) (more bool)) (all bool) {
    for _, i := range sl {
        if !cb(i) {
            return false
        }
    }
    return true
}
哪一个是表示希望停止/继续的首选值

“继续”为true

为什么?

例1:

func example(i interface{}) {
    if w, ok := i.(io.Writer); ok {
        // do something with your writer, ok indicates that you can continue
    }
}
例2:

var sum int = 0
it := NewIntStatefulIterator(int_data)
for it.Next() {
    sum += it.Value()
}

在这两种情况下,true(确定)表示您应该继续。因此,我假设在您的示例中,这将是一种方式。

前言:以下答案适用于回调函数,该函数根据当前项决定循环是否应提前终止-这就是您提出的问题

这不应与在有更多元素需要处理时进行处理和报告的函数混淆,其中
true
返回值通常被接受以表示有更多元素(这是一个很好的示例),其典型用途是:

scanner := bufio.NewScanner(input)
for scanner.Scan() {
    // Process current item (line):
    line := scanner.Text()
    fmt.Println(line) // Do something with line
}

坚持
bool
返回类型 通常返回
true
,以指示终止结果的代码更易于阅读。这是由于
for
的性质造成的:如果您什么也不做,
for
将继续,因此如果您想提前终止,您必须明确地
中断
,因此更常见的是干净的终止条件

但这是品味的问题。您可以选择任何您喜欢的方法,但重要的是以一种有意义的方式命名回调函数,它将清楚地说明其返回值的含义,因此查看代码(使用它的条件)将很容易理解

例如,以下名称是好的,返回值是明确的:

// A return value of true means to terminate
func isLast(item Type) bool
func terminateAfter(item Type) bool
func abort(item Type) bool

// A return value of true means to continue (not to terminate)
func keepGoing(item Type) bool
func carryOn(item Type) bool
func processMore(item Type) bool
在易于理解的代码中使用这些结果:

for i, v := range vals {
    doSomeWork()
    if terminateAfter(v) {
        break // or return
    }
}

for i, v := range vals {
    doSomeWork()
    if !keepGoing(v) {
        break // or return
    }
}

// Or an alternative to the last one (subjective which is easier to read):

for i, v := range vals {
    doSomeWork()
    if keepGoing(v) {
        continue
    }
    break
}
作为反面示例,以下回调函数名称很糟糕,因为您无法猜测它们的返回值的含义:

// Bad: you can't tell what return value of true means just by its name:
func test(item Type) bool
func check(item Type) bool
错误
返回类型 回调不仅要测试,还要处理传递的项,这也是很常见的。在这些情况下,返回
错误而不是
bool
是有意义的。这样做,显然
nil
返回值表示成功(并继续),而非
nil
值表示错误,处理应该停止

func process(item Type) error

for i, v := range vals {
    if err := process(v); err != nil {
        // Handle error and terminate
        break
    }
}
具有类似枚举的返回值 此外,如果多个返回值有意义,您可以选择为返回值定义常量,您可以对其进行有意义的命名

type Action int
const (
    ActionContinue Action = iota
    ActionTerminate
    ActionSkip
)

func actionToTake(item Type) Action

for i, v := range vals {
    switch actionToTake(v) {
    case ActionSkip:
        continue
    case ActionTerminate:
        return
    }
    doSomeWork()
}

您的示例1不是回调函数(而是类型断言),您的示例2也不接受任何项,因此它不是测试函数,而是不断发展的功能。imho独立于具体实现是一个普遍的问题。顺便说一句,这种回调风格在大多数情况下并不惯用。实际上,这里真正重要的是函数的命名,它需要自我解释,以便读者理解返回值的含义。另一种方法是使用enum作为返回值,正如@icza在他的回答中所建议的那样。这些似乎是Go语言中支持true for continue的好例子。您描述的错误返回案例与我的要求最为接近。回调函数还处理该项。例如,请参见Javascript中iterable类型上使用的每个函数。