Astro Orbis
Astro Orbis

Reputation: 77

Golang | How would I check if multiple boolean values are true in a single if statement?

I'm making a program in Golang using the flag package, and I'm trying to check if more than one flag in a specific list is true. Right now, this is my solution:

List := 0

if *md5flag {
    List++
}
if *sha1flag {
    List++
}
if *sha256flag {
    List++
}
if *sha512flag {
    List++
}

if List > 1 {
    // Do stuff
    os.Exit(1)  
}

Would there be an easier way to do this, and by using a single if statement?

Upvotes: 3

Views: 5935

Answers (3)

bereal
bereal

Reputation: 34252

If all you need is to check that at most one flag is set and exit immediately in that case, you can use a loop with short circuiting, though I'm not sure if it's more readable for just 4 values:

flags := []*bool{md5flag, sha1flag, sha256flag, sha512flag}
seenSetFlag := false
for _, f := range flags {
    if *f {
        if seenSetFlag {
            os.Exit(1)
        }
        seenSetFlag = true
    }
}

Upvotes: 4

blackgreen
blackgreen

Reputation: 44587

You can use a bitmask. But the bitmask approach is more effective if you set up your flags to be a bitmask to begin with, i.e. the flags should be integers that can be OR'ed together. bool in Go doesn't support | operator.

With a bitmask, to check if more than one bit is set you can use the trick x & (x - 1) != 0. This checks if x is a power of two, when it is not, more than one bit is set. (source)

type alg int

const (
    md5flag alg = 1 << iota
    sha1flag 
    sha256flag
    sha512flag
)

func main() {
    // clients can initialize the value with bitwise-OR
    supportedAlgos := md5flag | sha256flag

    // check if more than one is set
    if supportedAlgos & (supportedAlgos - 1) != 0 {
        // do stuff
    }
}

If you can't refactor your code to use a bitmask you may still construct it from the individual bool pointers. But then the approach isn't much different than the one you have right now.

func toBitmask(bs ...*bool) int {
    bitmask := 0
    for i, b := range bs {
        if b != nil && *b {
            bitmask |= 1 << i
        }
    }
    return bitmask
}

func main() {
    list := toBitmask(md5flag, sha1flag, sha256flag, sha512flag)

    if list & (list - 1) != 0 {
        // do stuff
    }
}

Playground: https://play.golang.org/p/PXK_1sS5ZxI

Upvotes: 0

super
super

Reputation: 12928

Go doesn't have any conversion from bool to int, so you need to use an if-statement in some way.

I would do something like this

package main

import (
    "fmt"
)

func boolsToInt(flags... bool) int {
    value := 0
    for _, flag := range flags {
        if flag {
            value++
        }
    }
    return value
}

func main() {
    b1, b2, b3, b4 := false, true, true, false
    fmt.Println(boolsToInt(b1, b2, b3, b4))
}

Upvotes: 0

Related Questions