I'm trying to implement a default value according to the option 1 of the post Golang and default values. But when I try to do go install the following error pops up in the terminal:
not enough arguments in call to test.Concat1
have ()
want (string)
Code:
package test
func Concat1(a string) string {
if a == "" {
a = "default-a"
}
return fmt.Sprintf("%s", a)
}
// other package
package main
func main() {
test.Concat1()
}
Thanks in advance.
I don't think what you are trying to do will work that way. You may want to opt for option #4 from the page you cited, which uses variadic variables. In your case looks to me like you want just a string, so it'd be something like this:
func Concat1(a ...string) string {
if len(a) == 0 {
return "a-default"
}
return a[0]
}
Go does not have optional defaults for function arguments.
You may emulate them to some extent by having a special type
to contain the set of parameters for a function.
In your toy example that would be something like
type Concat1Args struct {
a string
}
func Concat1(args Concat1Args) string {
if args.a == "" {
args.a = "default-a"
}
return fmt.Sprintf("%s", args.a)
}
The "trick" here is that in Go each type has its respective
"zero value", and when producing a value of a composite type
using the so-called literal, it's possible to initialize only some of the type's fields, so in our example that would be
s := Concat1(Concat1Args{})
vs
s := Concat1(Concat1Args{"whatever"})
I know that looks clumsy, and I have showed this mostly for
demonstration purpose. In real production code, where a function
might have a dozen of parameters or more, having them packed
in a dedicate composite type is usually the only sensible way
to go but for a case like yours it's better to just explicitly
pass "" to the function.
Golang does not support default parameters. Accordingly, variadic arguments by themselves are not analogous. However, variadic functions with the use of error handling can 'resemble' the pattern. Try the following as a simple example:
package main
import (
"errors"
"log"
)
func createSeries(p ...int) ([]int, error) {
usage := "Usage: createSeries(<length>, <optional starting value>), length should be > 0"
if len(p) == 0 {
return nil, errors.New(usage)
}
n := p[0]
if n <= 0 {
return nil, errors.New(usage)
}
var base int
if len(p) == 2 {
base = p[1]
} else if len(p) > 2 {
return nil, errors.New(usage)
}
vals := make([]int, n)
for i := 0; i < n; i++ {
vals[i] = base + i
}
return vals, nil
}
func main() {
answer, err := createSeries(4, -9)
if err != nil {
log.Fatal(err)
}
log.Println(answer)
}
Default parameters work differently in Go than they do in other languages. In a function there can be one ellipsis, always at the end, which will keep a slice of values of the same type so in your case this would be:
func Concat1(a ...string) string {
but that means that the caller may pass in any number of arguments >= 0. Also you need to check that the arguments in the slice are not empty and then assign them yourself. This means they do not get assigned a default value through any kind of special syntax in Go. This is not possible but you can do
if a[0] == "" {
a[0] = "default value"
}
If you want to make sure that the user passes either zero or one strings, just create two functions in your API, e.g.
func Concat(a string) string { // ...
func ConcatDefault() string {
Concat("default value")
}
I have a fairly long else if chain looking for keys in a map and setting a specific value if found. The way I chose to do it with the least amount of code was this (m is a map[string]interface{})
var ok bool
var s interface{}
if s, ok = m["key1"]; ok {
} else if s, ok = m["key2"]; ok {
....
} else if s, ok = m["keyN"]; ok {
} else {
return RuhRohError
}
g.Id = s.(string)
This feels kinda clunky, I am doing all of these else if's to set a variable in the condition. Is there an idiomatic way to do this? I think this way doesn't make it immediately obvious what I am trying to do.
For example,
package main
import "fmt"
func findValue(m map[string]interface{}, keys []string) (interface{}, bool) {
for _, key := range keys {
if value, ok := m[key]; ok {
return value, true
}
}
return nil, false
}
func main() {
m := map[string]interface{}{"keyn": "valuen"}
keys := []string{"key1", "key2", "keyn"}
s, found := findValue(m, keys)
if !found {
return
}
id := s.(string)
fmt.Println(id)
}
Output:
valuen
Actually I think the code you provided is very easy to read and understand. It is a bit verbose but there is no magic ;). So if there is only one place where you have to write this code I would leave it as it is. If you need to write it a few times I would consider writing findValue function mentioned in another comment.
This question already has answers here:
What is the idiomatic Go equivalent of C's ternary operator?
(14 answers)
Closed 1 year ago.
Please see https://golangdocs.com/ternary-operator-in-golang as pointed by #accdias (see comments)
Can I write a simple if-else statement with variable assignment in go (golang) as I would do in php? For example:
$var = ( $a > $b )? $a: $b;
Currently I have to use the following:
var c int
if a > b {
c = a
} else {
c = b
}
Sorry I cannot remember the name if this control statement and I couldn't find the info in-site or through google search. :/
As the comments mentioned, Go doesn't support ternary one liners. The shortest form I can think of is this:
var c int
if c = b; a > b {
c = a
}
But please don't do that, it's not worth it and will only confuse people who read your code.
As the others mentioned, Go does not support ternary one-liners. However, I wrote a utility function that could help you achieve what you want.
// IfThenElse evaluates a condition, if true returns the first parameter otherwise the second
func IfThenElse(condition bool, a interface{}, b interface{}) interface{} {
if condition {
return a
}
return b
}
Here are some test cases to show how you can use it
func TestIfThenElse(t *testing.T) {
assert.Equal(t, IfThenElse(1 == 1, "Yes", false), "Yes")
assert.Equal(t, IfThenElse(1 != 1, nil, 1), 1)
assert.Equal(t, IfThenElse(1 < 2, nil, "No"), nil)
}
For fun, I wrote more useful utility functions such as:
IfThen(1 == 1, "Yes") // "Yes"
IfThen(1 != 1, "Woo") // nil
IfThen(1 < 2, "Less") // "Less"
IfThenElse(1 == 1, "Yes", false) // "Yes"
IfThenElse(1 != 1, nil, 1) // 1
IfThenElse(1 < 2, nil, "No") // nil
DefaultIfNil(nil, nil) // nil
DefaultIfNil(nil, "") // ""
DefaultIfNil("A", "B") // "A"
DefaultIfNil(true, "B") // true
DefaultIfNil(1, false) // 1
FirstNonNil(nil, nil) // nil
FirstNonNil(nil, "") // ""
FirstNonNil("A", "B") // "A"
FirstNonNil(true, "B") // true
FirstNonNil(1, false) // 1
FirstNonNil(nil, nil, nil, 10) // 10
FirstNonNil(nil, nil, nil, nil, nil) // nil
FirstNonNil() // nil
If you would like to use any of these, you can find them here https://github.com/shomali11/util
I often use the following:
c := b
if a > b {
c = a
}
basically the same as #Not_a_Golfer's but using type inference.
Thanks for pointing toward the correct answer.
I have just checked the Golang FAQ (duh) and it clearly states, this is not available in the language:
Does Go have the ?: operator?
There is no ternary form in Go. You may use the following to achieve the same result:
if expr {
n = trueVal
} else {
n = falseVal
}
additional info found that might be of interest on the subject:
Rosetta Code for Conditional Structures in Go
Ternary Operator in Go experiment from this guy
One possible way to do this in just one line by using a map, simple I am checking whether a > b if it is true I am assigning c to a otherwise b
c := map[bool]int{true: a, false: b}[a > b]
However, this looks amazing but in some cases it might NOT be the perfect solution because of evaluation order. For example, if I am checking whether an object is not nil get some property out of it, look at the following code snippet which will panic in case of myObj equals nil
type MyStruct struct {
field1 string
field2 string
}
var myObj *MyStruct
myObj = nil
myField := map[bool]string{true: myObj.field1, false: "empty!"}[myObj != nil}
Because map will be created and built first before evaluating the condition so in case of myObj = nil this will simply panic.
Not to forget to mention that you can still do the conditions in just one simple line, check the following:
var c int
...
if a > b { c = a } else { c = b}
A very similar construction is available in the language
**if <statement>; <evaluation> {
[statements ...]
} else {
[statements ...]
}*
*
i.e.
if path,err := os.Executable(); err != nil {
log.Println(err)
} else {
log.Println(path)
}
Use lambda function instead of ternary operator
Example 1
to give the max int
package main
func main() {
println( func(a,b int) int {if a>b {return a} else {return b} }(1,2) )
}
Example 2
Suppose you have this must(err error) function to handle errors and you want to use it when a condition isn't fulfilled.
(enjoy at https://play.golang.com/p/COXyo0qIslP)
package main
import (
"errors"
"log"
"os"
)
// must is a little helper to handle errors. If passed error != nil, it simply panics.
func must(err error) {
if err != nil {
log.Println(err)
panic(err)
}
}
func main() {
tmpDir := os.TempDir()
// Make sure os.TempDir didn't return empty string
// reusing my favourite `must` helper
// Isn't that kinda creepy now though?
must(func() error {
var err error
if len(tmpDir) > 0 {
err = nil
} else {
err = errors.New("os.TempDir is empty")
}
return err
}()) // Don't forget that empty parentheses to invoke the lambda.
println("We happy with", tmpDir)
}
Sometimes, I try to use anonymous function to achieve defining and assigning happen at the same line. like below:
a, b = 4, 8
c := func() int {
if a >b {
return a
}
return b
} ()
https://play.golang.org/p/rMjqytMYeQ0
Like user2680100 said, in Golang you can have the structure:
if <statement>; <evaluation> {
[statements ...]
} else {
[statements ...]
}
This is useful to shortcut some expressions that need error checking, or another kind of boolean checking, like:
var number int64
if v := os.Getenv("NUMBER"); v != "" {
if number, err = strconv.ParseInt(v, 10, 64); err != nil {
os.Exit(42)
}
} else {
os.Exit(1)
}
With this you can achieve something like (in C):
Sprite *buffer = get_sprite("foo.png");
Sprite *foo_sprite = (buffer != 0) ? buffer : donut_sprite
But is evident that this sugar in Golang have to be used with moderation, for me, personally, I like to use this sugar with max of one level of nesting, like:
var number int64
if v := os.Getenv("NUMBER"); v != "" {
number, err = strconv.ParseInt(v, 10, 64)
if err != nil {
os.Exit(42)
}
} else {
os.Exit(1)
}
You can also implement ternary expressions with functions like func Ternary(b bool, a interface{}, b interface{}) { ... } but i don't like this approach, looks like a creation of a exception case in syntax, and creation of this "features", in my personal opinion, reduce the focus on that matters, that is algorithm and readability, but, the most important thing that makes me don't go for this way is that fact that this can bring a kind of overhead, and bring more cycles to in your program execution.
You can use a closure for this:
func doif(b bool, f1, f2 func()) {
switch{
case b:
f1()
case !b:
f2()
}
}
func dothis() { fmt.Println("Condition is true") }
func dothat() { fmt.Println("Condition is false") }
func main () {
condition := true
doif(condition, func() { dothis() }, func() { dothat() })
}
The only gripe I have with the closure syntax in Go is there is no alias for the default zero parameter zero return function, then it would be much nicer (think like how you declare map, array and slice literals with just a type name).
Or even the shorter version, as a commenter just suggested:
func doif(b bool, f1, f2 func()) {
switch{
case b:
f1()
case !b:
f2()
}
}
func dothis() { fmt.Println("Condition is true") }
func dothat() { fmt.Println("Condition is false") }
func main () {
condition := true
doif(condition, dothis, dothat)
}
You would still need to use a closure if you needed to give parameters to the functions. This could be obviated in the case of passing methods rather than just functions I think, where the parameters are the struct associated with the methods.
As everyone else pointed out, there's no ternary operator in Go.
For your particular example though, if you want to use a single liner, you could use Max.
import "math"
...
c := math.Max(a, b)
Ternary ? operator alternatives | golang if else one line
You can’t write a short one-line conditional in Go language ; there is no ternary conditional operator.
Read more about if..else of Golang
I have some strings such E2 9NZ, N29DZ, EW29DZ . I need to extract the chars before the first digit, given the above example : E, N, EW.
Am I supposed to use regex ? The strings package looks really nice but just doesn't seem to handle this case (extract everything before a specific type).
Edit:
To clarify the "question" I'm wondering what method is more idiomatic to go and perhaps likely to provide better performance.
For example,
package main
import (
"fmt"
"unicode"
)
func DigitPrefix(s string) string {
for i, r := range s {
if unicode.IsDigit(r) {
return s[:i]
}
}
return s
}
func main() {
fmt.Println(DigitPrefix("E2 9NZ"))
fmt.Println(DigitPrefix("N29DZ"))
fmt.Println(DigitPrefix("EW29DZ"))
fmt.Println(DigitPrefix("WXYZ"))
}
Output:
E
N
EW
WXYZ
If there is no digit, example "WXYZ", and you don't want anything returned, change return s to return "".
Not sure why almost everyone provided answers in everything but Go. Here is regex-based Go version:
package main
import (
"fmt"
"regexp"
)
func main() {
pattern, err := regexp.Compile("^[^\\d]*")
if err != nil {
panic(err)
}
part := pattern.Find([]byte("EW29DZ"))
if part != nil {
fmt.Printf("Found: %s\n", string(part))
} else {
fmt.Println("Not found")
}
}
Running:
% go run main.go
Found: EW
Go playground
We don't need regex for this problem. You can easily walk through on a slice of rune and check the current character with unicode.IsDigit(), if it's a digit: return. If it isn't: continue the loop. If there are no numbers: return the argument
Code
package main
import (
"fmt"
"unicode"
)
func UntilDigit(r []rune) []rune {
var i int
for _, v := range r {
if unicode.IsDigit(v) {
return r[0:i]
}
i++
}
return r
}
func main() {
fmt.Println(string(UntilDigit([]rune("E2 9NZ"))))
fmt.Println(string(UntilDigit([]rune("N29DZ"))))
fmt.Println(string(UntilDigit([]rune("EW29DZ"))))
}
Playground link
I think the best option is to use the index returned from strings.IndexAny which will return the first index of any character in a string.
func BeforeNumbers(str string) string {
value := strings.IndexAny(str,"0123456789")
if value >= 0 && value <= len(str) {
return str[:value]
}
return str
}
Will slice the string and return the subslice up to (but not including) the first character that's in the string "0123456789" which is any number.
Way later edit:
It would probably be better to use IndexFunc rather than IndexAny:
func BeforeNumbers(str string) string {
indexFunc := func(r rune) bool {
return r >= '0' && r <= '9'
}
value := strings.IndexFunc(str,indexFunc)
if value >= 0 && value <= len(str) {
return str[:value]
}
return str
}
This is more or less equivalent to the loop version, and eliminates a search over a long string to check for a match every character from my previous answer. But I think it looks cleaner than the loop version, which is obviously a manner of taste.
The code below will continue grabbing characters until it reaches a digit.
int i = 0;
String string2test = "EW29DZ";
String stringOutput = "";
while (!Character.isDigit(string2test.charAt(i)))
{
stringOutput = stringOutput + string2test.charAt(i);
i++;
}