diff options
author | Rob Pike <r@golang.org> | 2014-08-25 11:43:57 +1000 |
---|---|---|
committer | Andrew Gerrand <adg@golang.org> | 2014-08-25 11:43:57 +1000 |
commit | 01eb87f06aa87b7a2d11b8031f51649ba60375aa (patch) | |
tree | 1474aa10af024ca9cecf1251a92b1b6bcf30e461 | |
parent | f953585a9d3c25fcc30e6a0a3d26a0a70de73bcd (diff) |
go.blog: constants
LGTM=gri, adg, rsc
R=gri, adg, rsc
CC=golang-codereviews
https://golang.org/cl/125540043
30 files changed, 851 insertions, 0 deletions
diff --git a/content/constants.article b/content/constants.article new file mode 100644 index 0000000..fbbfbd8 --- /dev/null +++ b/content/constants.article @@ -0,0 +1,452 @@ +Constants +25 Aug 2014 +Tags: constants + +Rob Pike + +* Introduction + +Go is a statically typed language that does not permit operations that mix numeric types. +You can't add a `float64` to an `int`, or even an `int32` to an `int`. +Yet it is legal to write `1e6*time.Second` or `math.Exp(1)` or even `1<<('\t'+2.0)`. +In Go, constants, unlike variables, behave pretty much like regular numbers. +This post explains why that is and what it means. + +* Background: C + +In the early days of thinking about Go, we talked about a number of problems caused by the way C and its descendants let you mix and match numeric types. +Many mysterious bugs, crashes, and portability problems are caused by expressions that combine integers of different sizes and "signedness". +Although to a seasoned C programmer, the result of a calculation like + + unsigned int u = 1e9; + long signed int i = -1; + ... i + u ... + +may be familiar, it isn't _a_priori_ obvious. +How big is the result? +What is its value? +Is it signed or unsigned? + +Nasty bugs lurk here. + +C has a set of rules called "the usual arithmetic conversions" and it is an indicator of their subtlety that they have changed over the years (introducing yet more bugs, retroactively). + +When designing Go, we decided to avoid this minefield by mandating that there is _no_ mixing of numeric types. +If you want to add `i` and `u`, you must be explicit about what you want the result to be. +Given + + var u uint + var i int + +you can write either `uint(i)+u` or `i+int(u)`, with both the meaning and type of the addition clearly expressed, but unlike in C you cannot write `i+u`. +You can't even mix `int` and `int32`, even when `int` is a 32-bit type. + +This strictness eliminates a common cause of bugs and other failures. +It is a vital property of Go. +But it has a cost: it sometimes requires programmers to decorate their code with clumsy numeric conversions to express their meaning clearly. + +And what about constants? +Given the declarations above, what would make it legal to write `i` `=` `0` or `u` `=` `0`? +What is the _type_ of `0`? +It would be unreasonable to require constants to have type conversions in simple contexts such as `i` `=` `int(0)`. + +We soon realized the answer lay in making numeric constants work differently from how they behave in other C-like languages. +After much thinking and experimentation, we came up with a design that we believe feels right almost always, freeing the programmer from converting constants all the time yet being able to write things like `math.Sqrt(2)` without being chided by the compiler. + +In short, constants in Go just work, most of the time anyway. +Let's see how that happens. + +* Terminology + +First, a quick definition. +In Go, `const` is a keyword introducing a name for a scalar value such as `2` or `3.14159` or `"scrumptious"`. +Such values, named or otherwise, are called _constants_ in Go. +Constants can also be created by expressions built from constants, such as `2+3` or `2+3i` or `math.Pi/2` or `("go"+"pher")`. + +Some languages don't have constants, and others have a more general definition of constant or application of the word `const`. +In C and C++, for instance, `const` is a type qualifier that can codify more intricate properties of more intricate values. + +But in Go, a constant is just a simple, unchanging value, and from here on we're talking only about Go. + +* String constants + +There are many kinds of numeric constants—integers, floats, runes, signed, unsigned, imaginary, complex—so let's start with a simpler form of constant: strings. +String constants are easy to understand and provide a smaller space in which to explore the type issues of constants in Go. + +A string constant encloses some text between double quotes. +(Go has also has raw string literals, enclosed by backquotes ``````, but for the purpose of this discussion they have all the same properties.) +Here is a string constant: + + "Hello, 世界" + +(For much more detail about the representation and interpretation of strings, see [[//blog.golang.org/strings][this blog post]].) + +What type does this string constant have? +The obvious answer is `string`, but that is _wrong_. + +This is an _untyped_string_constant_, which is to say it is a constant textual value that does not yet have a fixed type. +Yes, it's a string, but it's not a Go value of type `string`. +It remains an untyped string constant even when given a name: + + const hello = "Hello, 世界" + +After this declaration, `hello` is also an untyped string constant. +An untyped constant is just a value, one not yet given a defined type that would force it to obey the strict rules that prevent combining differently typed values. + +It is this notion of an _untyped_ constant that makes it possible for us to use constants in Go with great freedom. + +So what, then, is a _typed_ string constant? +It's one that's been given a type, like this: + + const typedHello string = "Hello, 世界" + +Notice that the declaration of `typedHello` has an explicit `string` type before the equals sign. +This means that `typedHello` has Go type `string`, and cannot be assigned to a Go variable of a different type. +That is to say, this code works: + +.play -edit constants/string1.go /START/,/STOP/ + +but this does not: + +.play -edit constants/string2.go /START/,/STOP/ + +The variable `m` has type `MyString` and cannot be assigned a value of a different type. +It can only be assigned values of type `MyString`, like this: + +.play -edit constants/string3.go /START/,/STOP/ + +or by forcing the issue with a conversion, like this: + +.play -edit constants/string4.go /START/,/STOP/ + +Returning to our _untyped_ string constant, it has the helpful property that, since it has no type, assigning it to a typed variable does not cause a type error. +That is, we can write + + m = "Hello, 世界" + +or + + m = hello + +because, unlike the typed constants `typedHello` and `myStringHello`, the untyped constants `"Hello, 世界"` and `hello` _have_no_type_. +Assigning them to a variable of any type compatible with strings works without error. + +These untyped string constants are strings, of course, so they can only be used where a string is allowed, but they do not have _type_ `string`. + +* Default type + +As a Go programmer, you have certainly seen many declarations like + + str := "Hello, 世界" + +and by now you might be asking, "if the constant is untyped, how does `str` get a type in this variable declaration?" +The answer is that an untyped constant has a default type, an implicit type that it transfers to a value if a type is needed where none is provided. +For untyped string constants, that default type is obviously `string`, so + + str := "Hello, 世界" + +or + + var str = "Hello, 世界" + +means exactly the same as + + var str string = "Hello, 世界" + +One way to think about untyped constants is that they live in a kind of ideal space of values, a space less restrictive than Go's full type system. +But to do anything with them, we need to assign them to variables, and when that happens the _variable_ (not the constant itself) needs a type, and the constant can tell the variable what type it should have. +In this example, `str` becomes a value of type `string` because the untyped string constant gives the declaration its default type, `string`. + +In such a declaration, a variable is declared with a type and initial value. +Sometimes when we use a constant, however, the destination of the value is not so clear. +For instance consider this statement: + +.play -edit constants/default1.go /START/,/STOP/ + +The signature of `fmt.Printf` is + + func Printf(format string, a ...interface{}) (n int, err error) + +which is to say its arguments (after the format string) are interface values. +What happens when `fmt.Printf` is called with an untyped constant is that an interface value is created +to pass as an argument, and the concrete type stored for that argument is the default type of the constant. +This process is analogous to what we saw earlier when declaring an initialized value using an untyped string constant. + +You can see the result in this example, which uses the format '%v' to print the value and `%T` to print the type of the value being passed to `fmt.Printf`: + +.play -edit constants/default2.go /START/,/STOP/ + +If the constant has a type, that goes into the interface, as this example shows: + +.play -edit constants/default3.go /START/,/STOP/ + +(For more information about how interface values work, see the first sections of [[//blog.golang.org/laws-of-reflection][this blog post]].) + +In summary, a typed constant obeys all the rules of typed values in Go. +On the other hand, an untyped constant does not carry a Go type in the same way and can be mixed and matched more freely. +It does, however, have a default type that is exposed when, and only when, no other type information is available. + +* Default type determined by syntax + +The default type of an untyped constant is determined by its syntax. +For string constants, the only possible implicit type is `string`. +For [[http://golang.org/ref/spec#Numeric_types][numeric constants]], the implicit type has more variety. +Integer constants default to `int`, floating-point constants `float64`, rune constants to `rune` (an alias for `int32`), and imaginary constants to `complex128`. +Here's our canonical print statement used repeatedly to show the default types in action: + +.play -edit constants/syntax.go /START/,/STOP/ + +(Exercise: Explain the result for `'x'`.) + +* Booleans + +Everything we said about untyped string constants can be said for untyped boolean constants. +The values `true` and `false` are untyped boolean constants that can be assigned to any boolean variable, +but once given a type, boolean variables cannot be mixed: + +.play -edit constants/bool.go /START/,/STOP/ + +Run the example and see what happens, then comment out the "Bad" line and run it again. +The pattern here follows exactly that of string constants. + +* Floats + +Floating-point constants are just like boolean constants in most respects. +Our standard example works as expected in translation: + +.play -edit constants/float1.go /START/,/STOP/ + +One wrinkle is that there are _two_ floating-point types in Go: `float32` and `float64`. +The default type for a floating-point constant is `float64`, although an untyped floating-point +constant can be assigned to a `float32` value just fine: + +.play -edit constants/float2.go /START/,/STOP/ + +Floating-point values are a good place to introduce the concept of overflow, or the range of values. + +Numeric constants live in an arbitrary-precision numeric space; they are just regular numbers. +But when they are assigned to a variable the value must be able to fit in the destination. +We can declare a constant with a very large value: + +.code constants/float3.go /Huge/ + +—that's just a number, after all—but we can't assign it or even print it. This statement won't even compile: + +.play -edit constants/float3.go /Println/ + +The error is, "constant 1.00000e+1000 overflows float64", which is true. +But `Huge` might be useful: we can use it in expressions with other constants and use the value of those expressions if the result +can be represented in the range of a `float64`. +The statement, + +.play -edit constants/float4.go /Println/ + +prints `10`, as one would expect. + +In a related way, floating-point constants may have very high precision, so that arithmetic involving them is more accurate. +The constants defined in the [[//golang.org/pkg/math][math]] package are given with many more digits than are +available in a `float64`. Here is the definition of `math.Pi`: + + Pi = 3.14159265358979323846264338327950288419716939937510582097494459 + +When that value is assigned to a variable, some of the precision will be lost; the assignment will create the `float64` (or `float32`) +value closest to the high-precision value. This snippet + +.play -edit constants/float5.go /START/,/STOP/ + +prints `3.141592653589793`. + +Having so many digits available means that calculations like `Pi/2` or other more intricate evaluations can carry more precision +until the result is assigned, making calculations involving constants easier to write without losing precision. +It also means that there is no occasion in which the floating-point corner cases like infinities, +soft underflows, and `NaNs` arise in constant expressions. +(Division by a constant zero is a compile-time error, and when everything is a number there's no such thing as "not a number".) + +* Complex numbers + +Complex constants behave a lot like floating-point constants. +Here's a version of our now-familiar litany translated into complex numbers: + +.play -edit constants/complex1.go /START/,/STOP/ + +The default type of a complex number is `complex128`, the larger-precision version composed of two `float64` values. + +For clarity in our example, we wrote out the full expression `(0.0+1.0i)`, but this value can be shortened to `0.0+1.0i`, +`1.0i` or even `1i`. + +Let's play a trick. +We know that in Go, a numeric constant is just a number. +What if that number is a complex number with no imaginary part, that is, a real? +Here's one: + +.code constants/complex2.go /const Two/ + +That's an untyped complex constant. +Even though it has no imaginary part, the _syntax_ of the expression defines it to have default type `complex128`. +Therefore, if we use it to declare a variable, the default type will be `complex128`. The snippet + +.play -edit constants/complex2.go /START/,/STOP/ + +prints `complex128:` `(2+0i)`. +But numerically, `Two` can be stored in a scalar floating-point number, a `float64` or `float32`, with no loss of information. +Thus we can assign `Two` to a `float64`, either in an initialization or an assignment, without problems: + +.play -edit constants/complex3.go /START/,/STOP/ + +The output is `2` `and` `2`. +Even though `Two` is a complex constant, it can be assigned to scalar floating-point variables. +This ability for a constant to "cross" types like this will prove useful. + +* Integers + +At last we come to integers. +They have more moving parts—[[http://golang.org/ref/spec#Numeric_types][many sizes, signed or unsigned, and more]]—but they play by the same rules. +For the last time, here is our familiar example, using just `int` this time: + +.play -edit constants/int1.go /START/,/STOP/ + +The same example could be built for any of the integer types, which are: + + int int8 int16 int32 int64 + uint uint8 uint16 uint32 uint64 + uintptr + +(plus the aliases `byte` for `uint8` and `rune` for `int32`). +That's a lot, but the pattern in the way constants work should be familiar enough by now that you can see how things will play out. + +As mentioned above, integers come in a couple of forms and each form has its own default type: `int` for simple constants like `123` or `0xFF` or `-14` +and `rune` for quoted characters like 'a', '世' or '\r'. + +No constant form has as its default type an unsigned integer type. +However, the flexibility of untyped constants means we can initialize unsigned integer variables using simple constants as long as we are clear about the type. +It's analogous to how we can initialize a `float64` using a complex number with zero imaginary part. +Here are several different ways to initialize a `uint`; all are equivalent, but all must mention the type explicitly for the result to be unsigned. + + var u uint = 17 + var u = uint(17) + u := uint(17) + +Similarly to the range issue mentioned in the section on floating-point values, not all integer values can fit in all integer types. +There are two problems that might arise: the value might be too large, or it might be a negative value being assigned to an unsigned integer type. +For instance, `int8` has range -128 through 127, so constants outside of that range can never be assigned to a variable of type `int8`: + +.play -edit constants/int2.go /var/ + +Similarly, `uint8`, also known as `byte`. has range 0 through 255, so a large or negative constant cannot be assigned to a `uint8`: + +.play -edit constants/int3.go /var/ + +This type-checking can catch mistakes like this one: + +.play -edit constants/int4.go /START/,/STOP/ + +If the compiler complains about your use of a constant, it's likely a real bug like this. + +* An exercise: The largest unsigned int + +Here is an informative little exercise. +How do we express a constant representing the largest value that fits in a `uint`? +If we were talking about `uint32` rather than `uint`, we could write + + const MaxUint32 = 1<<32 - 1 + +but we want `uint`, not `uint32`. +The `int` and `uint` types have equal unspecified numbers of bits, either 32 or 64. +Since the number of bits available depends on the architecture, we can't just write down a single value. + +Fans of [[http://en.wikipedia.org/wiki/Two's_complement][two's-complement arithmetic]], +which Go's integers are defined to use, know that the representation of `-1` has all its bits set to 1, +so the bit pattern of `-1` is internally the same as that of the +largest unsigned integer. +We therefore might think we could write + +.play -edit constants/exercise1.go /const/ + +but that is illegal because -1 cannot be represented by an unsigned variable; `-1` is not in the range of unsigned values. +A conversion won't help either, for the same reason: + +.play -edit constants/exercise2.go /const/ + +Even though at run-time a value of -1 can be converted to an unsigned integer, the rules +for constant [[http://golang.org/ref/spec#Conversions][conversions]] forbid this kind of coercion at compile time. +That is to say, this works: + +.play -edit constants/exercise3.go /START/,/STOP/ + +but only because `v` is a variable; if we made `v` a constant, even an untyped constant, we'd be back in forbidden territory: + +.play -edit constants/exercise4.go /START/,/STOP/ + +We return to our previous approach, but instead of `-1` we try `^0`, the bitwise negation of an arbitrary number of zero bits. +But that fails too, for a similar reason: +In the space of numeric values, +`^0` represents an infinite number of ones, so we lose information if we assign that to any fixed-size integer: + +.play -edit constants/exercise5.go /const/ + +How then do we represent the largest unsigned integer as a constant? + +The key is to constrain the operation to the number of bits in a `uint` and avoiding +values, such as negative numbers, that are not representable in a `uint`. +The simplest `uint` value is the typed constant `uint(0)`. +If `uints` have 32 or 64 bits, `uint(0)` has 32 or 64 zero bits accordingly. +If we invert each of those bits, we'll get the correct number of one bits, which is the largest `uint` value. + +Therefore we don't flip the bits of the untyped constant `0`, we flip the bits of the typed constant `uint(0)`. +Here, then, is our constant: + +.play -edit constants/exercise6.go /START/,/STOP/ + +Whatever the number of bits it takes to represent a `uint` in the current execution environment +(on the [[http://blog.golang.org/playground][playground]], it's 32), +this constant correctly represents the largest value a variable of type `uint` can hold. + +If you understand the analysis that got us to this result, you understand all the important points about constants in Go. + +* Numbers + +The concept of untyped constants in Go means that all the numeric constants, whether integer, floating-point, complex, or even character values, +live in a kind of unified space. +It's when we bring them to the computational world of variables, assignments, and operations that the actual types matter. +But as long as we stay in the world of numeric constants, we can mix and match values as we like. +All these constants have numeric value 1: + + 1 + 1.000 + 1e3-99.0*10-9 + '\x01' + '\u0001' + 'b' - 'a' + 1.0+3i-3.0i + +Therefore, although they have different implicit default types, written as untyped constants they can be assigned to a variable of any integer type: + +.play -edit constants/numbers1.go /START/,/STOP/ + +The output from this snippet is: `1 1 1 1 1 (1+0i) 1`. + +You can even do nutty stuff like + +.play -edit constants/numbers2.go /START/,/STOP/ + +which yields 145.5, which is pointless except to prove a point. + +But the real point of these rules is flexibility. +That flexibility means that, despite the fact that in Go it is illegal in the same expression to mix floating-point and integer variables, +or even `int` and `int32` variables, it is fine to write + + sqrt2 := math.Sqrt(2) + +or + + const millisecond = time.Second/1e3 + +or + + bigBufferWithHeader := make([]byte, 512+1e6) + +and have the results mean what you expect. + +Because in Go, numeric constants work as you expect: like numbers. + + diff --git a/content/constants/bool.go b/content/constants/bool.go new file mode 100644 index 0000000..7578d4a --- /dev/null +++ b/content/constants/bool.go @@ -0,0 +1,18 @@ +// +build OMIT + +package main + +import "fmt" + +func main() { + // START OMIT + type MyBool bool + const True = true + const TypedTrue bool = true + var mb MyBool + mb = true // OK + mb = True // OK + mb = TypedTrue // Bad + fmt.Println(mb) + // STOP OMIT +} diff --git a/content/constants/complex1.go b/content/constants/complex1.go new file mode 100644 index 0000000..ea45921 --- /dev/null +++ b/content/constants/complex1.go @@ -0,0 +1,18 @@ +// +build OMIT + +package main + +import "fmt" + +func main() { + // START OMIT + type MyComplex128 complex128 + const I = (0.0 + 1.0i) + const TypedI complex128 = (0.0 + 1.0i) + var mc MyComplex128 + mc = (0.0 + 1.0i) // OK + mc = I // OK + mc = TypedI // Bad + fmt.Println(mc) + // STOP OMIT +} diff --git a/content/constants/complex2.go b/content/constants/complex2.go new file mode 100644 index 0000000..5dd4f73 --- /dev/null +++ b/content/constants/complex2.go @@ -0,0 +1,13 @@ +// +build OMIT + +package main + +import "fmt" + +func main() { + const Two = 2.0 + 0i + // START OMIT + s := Two + fmt.Printf("%T: %v\n", s, s) + // STOP OMIT +} diff --git a/content/constants/complex3.go b/content/constants/complex3.go new file mode 100644 index 0000000..95e9e41 --- /dev/null +++ b/content/constants/complex3.go @@ -0,0 +1,15 @@ +// +build OMIT + +package main + +import "fmt" + +func main() { + const Two = 2.0 + 0i + // START OMIT + var f float64 + var g float64 = Two + f = Two + fmt.Println(f, "and", g) + // STOP OMIT +} diff --git a/content/constants/default1.go b/content/constants/default1.go new file mode 100644 index 0000000..914e4b7 --- /dev/null +++ b/content/constants/default1.go @@ -0,0 +1,11 @@ +// +build OMIT + +package main + +import "fmt" + +func main() { + // START OMIT + fmt.Printf("Hello, 世界") + // STOP OMIT +} diff --git a/content/constants/default2.go b/content/constants/default2.go new file mode 100644 index 0000000..2183cf0 --- /dev/null +++ b/content/constants/default2.go @@ -0,0 +1,14 @@ +// +build OMIT + +package main + +import "fmt" + +const hello = "Hello, 世界" + +func main() { + // START OMIT + fmt.Printf("%T: %v\n", "Hello, 世界", "Hello, 世界") + fmt.Printf("%T: %v\n", hello, hello) + // STOP OMIT +} diff --git a/content/constants/default3.go b/content/constants/default3.go new file mode 100644 index 0000000..246ae45 --- /dev/null +++ b/content/constants/default3.go @@ -0,0 +1,15 @@ +// +build OMIT + +package main + +import "fmt" + +type MyString string + +const myStringHello MyString = "Hello, 世界" + +func main() { + // START OMIT + fmt.Printf("%T: %v\n", myStringHello, myStringHello) + // STOP OMIT +} diff --git a/content/constants/exercise1.go b/content/constants/exercise1.go new file mode 100644 index 0000000..881d1d0 --- /dev/null +++ b/content/constants/exercise1.go @@ -0,0 +1,9 @@ +// +build OMIT + +package main + +func main() { + // START OMIT + const MaxUint uint = -1 // Error: negative value + // STOP OMIT +} diff --git a/content/constants/exercise2.go b/content/constants/exercise2.go new file mode 100644 index 0000000..db7d8c1 --- /dev/null +++ b/content/constants/exercise2.go @@ -0,0 +1,9 @@ +// +build OMIT + +package main + +func main() { + // START OMIT + const MaxUint uint = uint(-1) // Error: negative value + // STOP OMIT +} diff --git a/content/constants/exercise3.go b/content/constants/exercise3.go new file mode 100644 index 0000000..dbe7595 --- /dev/null +++ b/content/constants/exercise3.go @@ -0,0 +1,12 @@ +// +build OMIT + +package main + +func main() { + // START OMIT + var u uint + var v = -1 + u = uint(v) + // STOP OMIT + _ = u +} diff --git a/content/constants/exercise4.go b/content/constants/exercise4.go new file mode 100644 index 0000000..3acc664 --- /dev/null +++ b/content/constants/exercise4.go @@ -0,0 +1,12 @@ +// +build OMIT + +package main + +func main() { + // START OMIT + var u uint + const v = -1 + u = uint(v) // Error: negative value + // STOP OMIT + _ = u +} diff --git a/content/constants/exercise5.go b/content/constants/exercise5.go new file mode 100644 index 0000000..2fca330 --- /dev/null +++ b/content/constants/exercise5.go @@ -0,0 +1,9 @@ +// +build OMIT + +package main + +func main() { + // START OMIT + const MaxUint uint = ^0 // Error: overflow + // STOP OMIT +} diff --git a/content/constants/exercise6.go b/content/constants/exercise6.go new file mode 100644 index 0000000..ce6478c --- /dev/null +++ b/content/constants/exercise6.go @@ -0,0 +1,12 @@ +// +build OMIT + +package main + +import "fmt" + +func main() { + // START OMIT + const MaxUint = ^uint(0) + fmt.Printf("%x\n", MaxUint) + // STOP OMIT +} diff --git a/content/constants/float1.go b/content/constants/float1.go new file mode 100644 index 0000000..96b3bb9 --- /dev/null +++ b/content/constants/float1.go @@ -0,0 +1,18 @@ +// +build OMIT + +package main + +import "fmt" + +func main() { + // START OMIT + type MyFloat64 float64 + const Zero = 0.0 + const TypedZero float64 = 0.0 + var mf MyFloat64 + mf = 0.0 // OK + mf = Zero // OK + mf = TypedZero // Bad + fmt.Println(mf) + // STOP OMIT +} diff --git a/content/constants/float2.go b/content/constants/float2.go new file mode 100644 index 0000000..f43feb6 --- /dev/null +++ b/content/constants/float2.go @@ -0,0 +1,17 @@ +// +build OMIT + +package main + +import "fmt" + +func main() { + const Zero = 0.0 + const TypedZero float64 = 0.0 + // START OMIT + var f32 float32 + f32 = 0.0 + f32 = Zero // OK: Zero is untyped + f32 = TypedZero // Bad: TypedZero is float64 not float32. + fmt.Println(f32) + // STOP OMIT +} diff --git a/content/constants/float3.go b/content/constants/float3.go new file mode 100644 index 0000000..d862acc --- /dev/null +++ b/content/constants/float3.go @@ -0,0 +1,12 @@ +// +build OMIT + +package main + +import "fmt" + +func main() { + const Huge = 1e1000 + // START OMIT + fmt.Println(Huge) + // STOP OMIT +} diff --git a/content/constants/float4.go b/content/constants/float4.go new file mode 100644 index 0000000..206d215 --- /dev/null +++ b/content/constants/float4.go @@ -0,0 +1,12 @@ +// +build OMIT + +package main + +import "fmt" + +func main() { + const Huge = 1e1000 + // START OMIT + fmt.Println(Huge / 1e999) + // STOP OMIT +} diff --git a/content/constants/float5.go b/content/constants/float5.go new file mode 100644 index 0000000..2d62872 --- /dev/null +++ b/content/constants/float5.go @@ -0,0 +1,15 @@ +// +build OMIT + +package main + +import ( + "fmt" + "math" +) + +func main() { + // START OMIT + pi := math.Pi + fmt.Println(pi) + // STOP OMIT +} diff --git a/content/constants/int1.go b/content/constants/int1.go new file mode 100644 index 0000000..913ad78 --- /dev/null +++ b/content/constants/int1.go @@ -0,0 +1,18 @@ +// +build OMIT + +package main + +import "fmt" + +func main() { + // START OMIT + type MyInt int + const Three = 3 + const TypedThree int = 3 + var mi MyInt + mi = 3 // OK + mi = Three // OK + mi = TypedThree // Bad + fmt.Println(mi) + // STOP OMIT +} diff --git a/content/constants/int2.go b/content/constants/int2.go new file mode 100644 index 0000000..0e974ef --- /dev/null +++ b/content/constants/int2.go @@ -0,0 +1,10 @@ +// +build OMIT + +package main + +func main() { + // START OMIT + var i8 int8 = 128 // Error: too large. + // STOP OMIT + _ = i8 +} diff --git a/content/constants/int3.go b/content/constants/int3.go new file mode 100644 index 0000000..c2cec6e --- /dev/null +++ b/content/constants/int3.go @@ -0,0 +1,10 @@ +// +build OMIT + +package main + +func main() { + // START OMIT + var u8 uint8 = -1 // Error: negative value. + // STOP OMIT + _ = u8 +} diff --git a/content/constants/int4.go b/content/constants/int4.go new file mode 100644 index 0000000..caff695 --- /dev/null +++ b/content/constants/int4.go @@ -0,0 +1,11 @@ +// +build OMIT + +package main + +func main() { + // START OMIT + type Char byte + var c Char = '世' // Error: '世' has value 0x4e16, too large. + // STOP OMIT + _ = c +} diff --git a/content/constants/numbers1.go b/content/constants/numbers1.go new file mode 100644 index 0000000..ea35a51 --- /dev/null +++ b/content/constants/numbers1.go @@ -0,0 +1,19 @@ +// +build OMIT + +package main + +import "fmt" + +func main() { + // START OMIT + var f float32 = 1 + var i int = 1.000 + var u uint32 = 1e3 - 99.0*10.0 - 9 + var c float64 = '\x01' + var p uintptr = '\u0001' + var r complex64 = 'b' - 'a' + var b byte = 1.0 + 3i - 3.0i + + fmt.Println(f, i, u, c, p, r, b) + // STOP OMIT +} diff --git a/content/constants/numbers2.go b/content/constants/numbers2.go new file mode 100644 index 0000000..33b7de0 --- /dev/null +++ b/content/constants/numbers2.go @@ -0,0 +1,12 @@ +// +build OMIT + +package main + +import "fmt" + +func main() { + // START OMIT + var f = 'a' * 1.5 + fmt.Println(f) + // STOP OMIT +} diff --git a/content/constants/string1.go b/content/constants/string1.go new file mode 100644 index 0000000..3b83851 --- /dev/null +++ b/content/constants/string1.go @@ -0,0 +1,15 @@ +// +build OMIT + +package main + +import "fmt" + +const typedHello string = "Hello, 世界" + +func main() { + // START OMIT + var s string + s = typedHello + fmt.Println(s) + // STOP OMIT +} diff --git a/content/constants/string2.go b/content/constants/string2.go new file mode 100644 index 0000000..362b484 --- /dev/null +++ b/content/constants/string2.go @@ -0,0 +1,16 @@ +// +build OMIT + +package main + +import "fmt" + +const typedHello string = "Hello, 世界" + +func main() { + // START OMIT + type MyString string + var m MyString + m = typedHello // Type error + fmt.Println(m) + // STOP OMIT +} diff --git a/content/constants/string3.go b/content/constants/string3.go new file mode 100644 index 0000000..72de35f --- /dev/null +++ b/content/constants/string3.go @@ -0,0 +1,17 @@ +// +build OMIT + +package main + +import "fmt" + +const typedHello string = "Hello, 世界" + +func main() { + type MyString string + var m MyString + // START OMIT + const myStringHello MyString = "Hello, 世界" + m = myStringHello // OK + fmt.Println(m) + // STOP OMIT +} diff --git a/content/constants/string4.go b/content/constants/string4.go new file mode 100644 index 0000000..4c35f29 --- /dev/null +++ b/content/constants/string4.go @@ -0,0 +1,16 @@ +// +build OMIT + +package main + +import "fmt" + +const typedHello string = "Hello, 世界" + +func main() { + type MyString string + var m MyString + // START OMIT + m = MyString(typedHello) + fmt.Println(m) + // STOP OMIT +} diff --git a/content/constants/syntax.go b/content/constants/syntax.go new file mode 100644 index 0000000..16e7e64 --- /dev/null +++ b/content/constants/syntax.go @@ -0,0 +1,14 @@ +// +build OMIT + +package main + +import "fmt" + +func main() { + // START OMIT + fmt.Printf("%T %v\n", 0, 0) + fmt.Printf("%T %v\n", 0.0, 0.0) + fmt.Printf("%T %v\n", 'x', 'x') + fmt.Printf("%T %v\n", 0i, 0i) + // STOP OMIT +} |