제네릭을 사용하여 Go에서 플래그 작업
19057 단어 gotutorialprogramming
GO-상태
개요
GO-STATUS
문제
Go에서 작은 상태 머신을 작성하는 동안 코드를 반복하지 않고는 열거형에 플래그 작업을 구현하는 명확한 방법을 찾을 수 없다는 점이 저를 괴롭혔습니다. 불과 몇 달 전에 Go를 사용하기 시작한 경험 부족과 관련이 있을 수 있지만 Go 버전 1.18부터 사용할 수 있는 제네릭 기능을 사용하여 "깨끗한"것으로 간주할 수 있는 방법을 찾았습니다. 이 게시물에서 관심 있는 분들과 기꺼이 공유하겠습니다.
설정
다음 열거형을 고려하십시오.
package status
// MyStatus is an enumeration that indicates my liveliness
type MyStatus int
const (
Unknown MyStatus = 1 << iota
Born MyStatus = 2
Living MyStatus = 4
Dead MyStatus = 8
)
var me MyStatus
func init() {
me = Unknown
}
테스트
package status
import (
"github.com/stretchr/testify/assert"
"testing"
)
func TestThatICanBeBorn(t *testing.T) {
// GIVEN
me = Unknown
assert.True(t, HasStatus(me, Unknown))
// WHEN
ForceStatus(&me, Born)
// THEN
assert.True(t, HasStatus(me, Born))
assert.True(t, NotHasStatus(me, Unknown))
}
func TestThatICanDie(t *testing.T) {
// GIVEN
me = Unknown
assert.True(t, HasStatus(me, Unknown))
// WHEN
SetStatus(&me, Born)
assert.True(t, HasStatus(me, Born))
// AND
SetStatus(&me, Living)
assert.True(t, HasStatus(me, Living))
// AND
UnsetStatus(&me, Born)
assert.True(t, NotHasStatus(me, Born))
// AND
ForceStatus(&me, Dead)
// THEN
assert.True(t, NotHasStatus(me, Born))
assert.True(t, NotHasStatus(me, Living))
assert.True(t, HasStatus(me, Dead))
}
func TestThatWeCanSetAndUnsetMultipleFlagsAtOnce(t *testing.T) {
// GIVEN
me = Unknown
assert.True(t, HasStatus(me, Unknown))
// WHEN
SetMulti(&me, Born, Living, Dead)
// THEN
assert.True(t, HasMulti(me, Born, Living, Dead))
// AND WHEN
UnsetMulti(&me, Born, Dead)
assert.True(t, !HasMulti(me, Born, Dead))
}
구현
package status
// HasStatus accepts an input status and will check if the flag is set using bitwise OR and return true if the flag is set.
func HasStatus[T ~int](status T, flag T) bool {
return status|flag == status
}
// NotHasStatus accepts an input status and will check if the flag is not set.
func NotHasStatus[T ~int](status T, flag T) bool {
return !HasStatus(status, flag)
}
// UnsetStatus accepts an input status reference and will unset the flag using bitwise AND NOT.
func UnsetStatus[T ~int](status *T, flag T) {
*status = *status &^ flag
}
// ForceStatus accepts an input status reference and will simply overwrite the status with the flag.
func ForceStatus[T ~int](status *T, flag T) {
*status = flag
}
// SetStatus accepts an input status reference and will set the flag to the status using bitwise OR.
func SetStatus[T ~int](status *T, flag T) {
*status = *status | flag
}
// SetMulti allows you to set multiple flags at once
func SetMulti[T ~int](status *T, flags ...T) {
if len(flags) == 0 {
return
}
for _, flag := range flags {
SetStatus[T](status, flag)
}
}
// HasMulti allows you to check for many flags at once.
func HasMulti[T ~int](status T, flags ...T) bool {
if len(flags) == 0 {
return false
}
for _, flag := range flags {
if NotHasStatus[T](status, flag) {
return false
}
}
return true
}
// UnsetMulti allows you to clear multiple flags at once.
func UnsetMulti[T ~int](status *T, flags ...T) {
if len(flags) == 0 {
return
}
for _, flag := range flags {
UnsetStatus[T](status, flag)
}
}
테스트 출력
/usr/local/go/bin/go test -json ./...
=== RUN TestThatICanBeBorn
--- PASS: TestThatICanBeBorn (0.00s)
=== RUN TestThatICanDie
--- PASS: TestThatICanDie (0.00s)
=== RUN TestWeCanSetAndUnsetMultipleFlagsAtOnce
--- PASS: TestWeCanSetAndUnsetMultipleFlagsAtOnce (0.00s)
PASS
ok <REDACTED>
0.003s
Process finished with the exit code 0
설치
go get github.com/discomco/go-status
결론
나는 이것이 Go에서 Flags로 작업하는 깔끔한 방법이라고 생각합니다. 물론 저는 아직 이 언어를 처음 접했고 이 모든 것을 구식으로 만들 내장 기능을 놓쳤을 수도 있습니다. 저에게는 Go 제네릭의 메커니즘을 조금 더 잘 배웠습니다. 이러한 메서드를 호출하는 데 명시적 형식 추론이 필요하지 않은 것 같습니다.
전문가의 의견과 더 많은 것을 배울 수 있는 기회를 기대합니다!
Reference
이 문제에 관하여(제네릭을 사용하여 Go에서 플래그 작업), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/discomco/setting-flags-in-go-using-generics-29p3텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)