Какой самый элегантный способ проверить, соответствует ли каждый элемент в срезе некоторому условию? В моем конкретном сценарии у меня есть фрагмент байтов: [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?
Самый простой способ — использовать цикл 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 или несколько содержит и т. д.
Придирка:
[16]byte
в Go — это массив, а не срез. Относительно вопроса: простой циклfor
, который устанавливает флаг и сразу же выходит, как только условие не выполняется.for … range
у нас обычно самые простые. И нет, в Go нет примитивов языкового уровня для написания неразборчивых однострочников, чтобы делать то, что вам нужно.