There are boolean constants, rune constants, integer constants, floating-point constants, complex constants, and string constants. Rune, integer, floating-point, and complex constants are collectively called numeric constants.
A constant value is represented by a rune, integer, floating-point, imaginary, or string literal, an identifier denoting a constant, a constant expression, a conversion with a result that is a constant, or the result value of some built-in functions such as unsafe.Sizeof applied to any value, cap or len applied to some expressions, real and imag applied to a complex constant and complex applied to numeric constants. The boolean truth values are represented by the predeclared constants true and false. The predeclared identifier iota denotes an integer constant.
In general, complex constants are a form of constant expression and are discussed in that section.
Numeric constants represent exact values of arbitrary precision and do not overflow. Consequently, there are no constants denoting the IEEE-754 negative zero, infinity, and not-a-number values.
Constants may be typed or untyped. Literal constants, true, false, iota, and certain constant expressions containing only untyped constant operands are untyped.
A constant may be given a type explicitly by a constant declaration or conversion, or implicitly when used in a variable declaration or an assignment or as an operand in an expression. It is an error if the constant value cannot be represented as a value of the respective type.
An untyped constant has a default type which is the type to which the constant is implicitly converted in contexts where a typed value is required, for instance, in a short variable declaration such as i := 0 where there is no explicit type. The default type of an untyped constant is bool, rune, int, float64, complex128 or string respectively, depending on whether it is a boolean, rune, integer, floating-point, complex, or string constant.
Implementation restriction: Although numeric constants have arbitrary precision in the language, a compiler may implement them using an internal representation with limited precision. That said, every implementation must:
- Represent integer constants with at least 256 bits.
- Represent floating-point constants, including the parts of a complex constant, with a mantissa of at least 256 bits and a signed binary exponent of at least 16 bits.
- Give an error if unable to represent an integer constant precisely.
- Give an error if unable to represent a floating-point or complex constant due to overflow.
- Round to the nearest representable constant if unable to represent a floating-point or complex constant due to limits on precision.
Round to the nearest representable constant if unable to represent a floating-point or complex constant due to limits on precision.
Round to the nearest representable constant if unable to represent a floating-point or complex constant due to limits on precision.
Variables can be initialized just like constants but the
initializer can be a general expression computed at run time.
var (
home = os.Getenv("HOME")
user = os.Getenv("USER")
gopath = os.Getenv("GOPATH")
)
In Go a simple if looks like this:
if x > 0 {
return y
}
Mandatory braces encourage writing simple if statements on
multiple lines. It's good style to do so anyway, especially when
the body contains a control statement such as a return or break.
Since if and switch accept an initialization statement, it's
common to see one used to set up a local variable.
if err := file.Chmod(0664); err != nil {
log.Print(err)
return err
}
In the Go libraries, you'll find that when an if statement doesn't
flow into the next statement—that is, the body ends in break,
continue, goto, or return—the unnecessary else is omitted.
f, err := os.Open(name)
if err != nil {
return err
}
codeUsing(f)
This is an example of a common situation where code must guard
against a sequence of error conditions. The code reads well if the
successful flow of control runs down the page, eliminating error
cases as they arise. Since error cases tend to end in return
statements, the resulting code needs no else statements.
f, err := os.Open(name)
if err != nil {
return err
}
d, err := f.Stat()
if err != nil {
f.Close()
return err
}
codeUsing(f, d)
The Go for loop is similar to—but not the same as—C's. It unifies
for and while and there is no do-while. There are three forms,
only one of which has semicolons.
// Like a C for
for init; condition; post { }
// Like a C while
for condition { }
// Like a C for(;;)
for { }
Short declarations make it easy to declare the index variable
right in the loop.
sum := 0
for i := 0; i < 10; i++ {
sum += i
}
If you're looping over an array, slice, string, or map, or reading
from a channel, a range clause can manage the loop.
for key, value := range oldMap {
newMap[key] = value
}
If you only need the first item in the range (the key or index),
drop the second:
for key := range m {
if key.expired() {
delete(m, key)
}
}
If you only need the second item in the range (the value), use the
blank identifier, an underscore, to discard the first:
sum := 0
for _, value := range array {
sum += value
}
For strings, the range does more work for you, breaking out
individual Unicode code points by parsing the UTF-8. Erroneous
encodings consume one byte and produce the replacement rune
U+FFFD. (The name (with associated builtin type) rune is Go
terminology for a single Unicode code point. See the language
specification for details.) The loop
for pos, char := range "日本\x80語" { // \x80 is an illegal UTF-8 encoding
fmt.Printf("character %#U starts at byte position %d\n", char, pos)
}
prints
character U+65E5 '日' starts at byte position 0
character U+672C '本' starts at byte position 3
character U+FFFD '�' starts at byte position 6
character U+8A9E '語' starts at byte position 7
Go's switch is more general than C's. The expressions need not be
constants or even integers, the cases are evaluated top to bottom
until a match is found, and if the switch has no expression it
switches on true. It's therefore possible—and idiomatic—to write
an if-else-if-else chain as a switch.
func unhex(c byte) byte {
switch {
case '0' <= c && c <= '9':
return c - '0'
case 'a' <= c && c <= 'f':
return c - 'a' + 10
case 'A' <= c && c <= 'F':
return c - 'A' + 10
}
return 0
}
There is no automatic fall through, but cases can be presented in
comma-separated lists.
func shouldEscape(c byte) bool {
switch c {
case ' ', '?', '&', '=', '#', '+', '%':
return true
}
return false
}
Although they are not nearly as common in Go as some other C-like
languages, break statements can be used to terminate a switch
early. Sometimes, though, it's necessary to break out of a
surrounding loop, not the switch, and in Go that can be
accomplished by putting a label on the loop and "breaking" to that
label. This example shows both uses.
Loop:
for n := 0; n < len(src); n += size {
switch {
case src[n] < sizeOne:
if validateOnly {
break
}
size = 1
update(src[n])
case src[n] < sizeTwo:
if n+1 >= len(src) {
err = errShortInput
break Loop
}
if validateOnly {
break
}
size = 2
update(src[n] + src[n+1]<<shift)
}
}
Of course, the continue statement also accepts an optional label
but it applies only to loops.
To close this section, here's a comparison routine for byte slices
that uses two switch statements:
// Compare returns an integer comparing the two byte slices,
// lexicographically.
// The result will be 0 if a == b, -1 if a < b, and +1 if a > b
func Compare(a, b []byte) int {
for i := 0; i < len(a) && i < len(b); i++ {
switch {
case a[i] > b[i]:
return 1
case a[i] < b[i]:
return -1
}
}
switch {
case len(a) > len(b):
return 1
case len(a) < len(b):
return -1
}
return 0
}
One of Go's unusual features is that functions and methods can
return multiple values. This form can be used to improve on a
couple of clumsy idioms in C programs: in-band error returns such
as -1 for EOF and modifying an argument passed by address.
In C, a write error is signaled by a negative count with the error
code secreted away in a volatile location. In Go, Write can return
a count and an error: “Yes, you wrote some bytes but not all of
them because you filled the device”. The signature of the Write
method on files from package os is:
func (file *File) Write(b []byte) (n int, err error)
and as the documentation says, it returns the number of bytes
written and a non-nil error when n != len(b). This is a common
style; see the section on error handling for more examples.
A similar approach obviates the need to pass a pointer to a return
value to simulate a reference parameter. Here's a simple-minded
function to grab a number from a position in a byte slice,
returning the number and the next position.
func nextInt(b []byte, i int) (int, int) {
for ; i < len(b) && !isDigit(b[i]); i++ {
}
x := 0
for ; i < len(b) && isDigit(b[i]); i++ {
x = x*10 + int(b[i]) - '0'
}
return x, i
}
You could use it to scan the numbers in an input slice b like
this:
for i := 0; i < len(b); {
x, i = nextInt(b, i)
fmt.Println(x)
}