Перейти: проверить, соответствует ли каждый элемент в срезе условию

Какой самый элегантный способ проверить, соответствует ли каждый элемент в срезе некоторому условию? В моем конкретном сценарии у меня есть фрагмент байтов: [16] байт. Мне нужно проверить, все ли байты равны 0.

В JS, например, я бы сделал что-то вроде этого:

const uint8Array = new Uint8Array([0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0])//Can be thought of as an array of "bytes"

const isEmpty = uint8Array.every(byte=>byte === 0)//Check that every "byte" is zero

console.info(isEmpty)//false

Какой самый чистый и простой способ сделать это в Go?

🤔 А знаете ли вы, что...
В Go используется строгая статическая типизация.


81
3

Ответы:

Самый простой способ — использовать цикл for на основе диапазона, поскольку, насколько мне известно, в Go нет встроенной функции, подобной .ForEach.

Если вам не нужен индекс, вы можете опустить его из цикла, и у вас будет что-то похожее:

isEmpty := true
for _, val := range uint8Array {
    if val != 0 {
        isEmpty=false
        break
    }
}

fmt.Println(isEmpty)

Если вы используете функцию повторно, вы также можете определить ее как свою собственную отдельную функцию.

func IsEmpty(arr *[]any) bool {
    for _, val := range *arr {
        if val != 0 {
            return false
        }
    }
    
    return true
}

Хотя последний может вызвать проблемы для некоторых типов данных.


Решено

Для удобочитаемости и гибкости (например, если вам нужно работать с типами, отличными от byte), вам может быть полезно написать небольшую универсальную функцию All, которая

  • принимает срез и предикат типа элемента этого среза, и
  • возвращает true тогда и только тогда, когда предикат выполняется для всех элементов среза.

Затем вы сможете свободно использовать эту общую функцию с различными срезами и предикатами.

package main

import "fmt"

func main() {
    bs := []byte{15: 1} // slice of 16 bytes, all but the last one of which are zero
    isZero := func(b byte) bool { return b == 0 }
    fmt.Println(All(bs, isZero)) // false
}

func All[T any](ts []T, pred func(T) bool) bool {
    for _, t := range ts {
        if !pred(t) {
            return false
        }
    }
    return true
}

(Детская площадка)

Однако нет необходимости создавать библиотеку для этой функции All; немного копирования лучше, чем немного зависимости.


Было бы легко, если бы вы использовали пакет байтов, вот пример:

func main() {
    n := []byte{0,0,0,0,0,0,0}
    b := bytes.ContainsRune(n, 1)
    fmt.Println(b)
}

В пакете байтов есть несколько методов, которые вы можете вызвать для своего результата, например, проверка char или несколько содержит и т. д.