"Golang" Learning note 4-variables, constants, built-in types, and some tricks in go programming

Source: Internet
Author: User


Objective



This article will show you how to define variables, constants, go built-in types, and some of the techniques in Go programming. (The main content of this article is from the electronic book "GO Web Programming")



Defining variables



There are several ways to define variables in the go language.



Usingvarkeywords is the most basic way to define variables, unlike C, where go puts variable types behind variable names :


// Define a variable with the name "variableName" and type "type"
var variableName type
Define multiple variables:
// define three variables of type "type"
var vname1, vname2, vname3 type
Define variables and initialize values
// Initialize the variable of "variableName" to "value" value, the type is "type"
var variableName type = value
Initialize multiple variables at the same time
/ *
    Define three variables of type "type" and initialize them to the corresponding values
    vname1 is v1, vname2 is v2, and vname3 is v3
* /
var vname1, vname2, vname3 type = v1, v2, v3
Short declaration of variable
Do you find the definition above a bit cumbersome? It doesn't matter, because the designers of Go also found out that there is a way to make it a bit simpler. We can ignore the type declaration directly, so the above code becomes like this:

/ *
    Define three variables, each initialized to the corresponding value
    vname1 is v1, vname2 is v2, and vname3 is v3
    Go then initializes them for you based on the type of their corresponding values
* /
var vname1, vname2, vname3 = v1, v2, v3
What do you think is still a bit tedious? Okay, I think so. Let's keep it simple:

/ *
    Define three variables, each initialized to the corresponding value
    vname1 is v1, vname2 is v2, and vname3 is v3
    The compiler will automatically infer the corresponding type based on the initialized value
* /
vname1, vname2, vname3: = v1, v2, v3
Does it look terse now?

The: = symbol directly replaces var and type. This form is called a short declaration. However, it has a limitation, that is, it can only be used inside a function; it cannot be compiled and used outside the function, so var is generally used to define global variables.

Special variable "_"
Go will report errors during the compilation phase of declared but unused variables. For example, the following code will generate an error: i was declared but not used.

package main

func main () {
    var i int
}
At this time our special variable _ (underscore) comes in handy, any value assigned to it will be discarded. In this example, we assign the value 35 to b and discard 34 at the same time:

_, b: = 34, 35
constant
The so-called constant is the value determined during the program compilation phase, and the value cannot be changed while the program is running. In Go programs, constants can be defined as numeric, boolean, or string types.

Its syntax is as follows:

const constantName = value
// If needed, you can also explicitly specify the type of the constant:
const Pi float32 = 3.1415926
Here are some examples of constant declarations:

const Pi = 3.1415926
const i = 10000
const MaxThread = 10
const prefix = "astaxie_"
Go constants are different from general programming languages in that you can specify a considerable number of decimal places (for example, 200 digits).
If it is assigned to float32, it will be shortened to 32bit automatically. If it is assigned to float64, it will be shortened to 64bit automatically. For details, please refer to the link.

Built-in base types
Boolean
In Go, booleans are of type bool, the value is true or false, and the default is false.

// Sample code
var isActive bool // global variable declaration
var enabled, disabled = true, false // ignore type declaration
func test () {
    var available bool // general statement
    valid: = false // short declaration
    available = true // assignment
}
Numeric type
There are two types of integers: unsigned and signed. Go supports both int and uint. Both types have the same length, but the exact length depends on the implementation of different compilers. Go also has types that directly define the number of bits: rune, int8, int16, int32, int64 and byte, uint8, uint16, uint32, uint64. Where rune is another name for int32 and byte is another name for uint8.

It should be noted that these types of variables are not allowed to assign or manipulate each other, otherwise it will cause compiler errors during compilation.

The following code will generate an error: invalid operation: a + b (mismatched types int8 and int32)

var a int8
var b int32
c: = a + b
In addition, although the length of int is 32 bits, int and int32 are not interoperable.

There are two types of floating point numbers: float32 and float64 (no float type). The default is float64.

Is that all? No! Go also supports plural. Its default type is complex128 (64-bit real + 64-bit imaginary). If you need something smaller, there is also complex64 (32-bit real + 32-bit imaginary). The form of a complex number is RE + IMi, where RE is the real part, IM is the imaginary part, and the last i is the imaginary unit. Here is an example using plural numbers:

var c complex64 = 5 + 5i
// output: (5 + 5i)
fmt.Printf ("Value is:% v", c)
String
As we mentioned in the previous section, strings in Go are encoded in the UTF-8 character set. A string is defined by enclosing it in double quotes ("") or back quotes (``). Its type is string.

// Sample code
var frenchHello string // general method for declaring variables as strings
var emptyString string = "" // declares a string variable, initialized to an empty string
func test () {
    no, yes, maybe: = "no", "yes", "maybe" // short declaration, declare multiple variables at the same time
    japaneseHello: = "Konichiwa" // same as above
    frenchHello = "Bonjour" // regular assignment
}
Strings are immutable in Go. For example, the following code will give an error when compiled: cannot assign to s [0]

var s string = "hello"
s [0] = 'c'
But what if you really want to modify it? The following code can achieve this:

s: = "hello"
c: = [] byte (s) // convert string s to [] byte
c [0] = 'c'
s2: = string (c) // convert back to string
fmt.Printf ("% s \ n", s2)
You can use the + operator to concatenate two strings in Go:

s: = "hello,"
m: = "world"
a: = s + m
fmt.Printf ("% s \ n", a)
The modified string can also be written as:

s: = "hello"
s = "c" + s [1:] // string cannot be changed, but can be sliced
fmt.Printf ("% s \ n", s)
What if you want to declare a multi-line string? Can be declared with `

m: = `hello
        world`
`The enclosed string is a Raw string, that is, the form of the string in the code is the form at the time of printing, it has no character escape, and the newline is output as it is. For example, this example will output:

hello
        world
Error type
Go has a built-in error type, which is used to handle error messages. Go's package also has a package errors to handle errors:

err: = errors.New ("emit macho dwarf: elf header corrupted")
if err! = nil {
    fmt.Print (err)
}
Go data underlying storage
The following picture is from an article in the Russ Cox Blog that introduces the data structure of Go. You can see that the underlying types are all allocated a piece of memory and then store the corresponding values.

Go data format storage

Some tricks
Group statement
In Go, you can declare multiple constants, variables, or import multiple packages at the same time by grouping them.

For example, the following code:

import "fmt"
import "os"

const i = 100
const pi = 3.1415
const prefix = "Go_"

var i int
var pi float32
var prefix string
Can be grouped and written as follows:

import (
    "fmt"
    "os"
)

const (
    i = 100
    pi = 3.1415
    prefix = "Go_"
)

var (
    i int
    pi float32
    prefix string
)
iota enumeration
There is a keyword iota in Go. This keyword is used when declaring enum. It defaults to a starting value of 0 and adds 1 to each additional line in const:

package main

import (
    "fmt"
)

const (
    x = iota // x == 0
    y = iota // y == 1
    z = iota // z == 2
    w // When a constant declaration is omitted, the default is literally the same as the previous value. Here implicitly w = iota, so w == 3. In fact, the above y and z can also be used without "= iota"
)

const v = iota // Every time a const keyword is encountered, iota resets, at this time v == 0

const (
    h, i, j = iota, iota, iota // h = 0, i = 0, j = 0 iota has the same value in the same row
)

const (
    a = iota // a = 0
    b = "B"
    c = iota // c = 2
    d, e, f = iota, iota, iota // d = 3, e = 3, f = 3
    g = iota // g = 4
)

func main () {
    fmt.Println (a, b, c, d, e, f, g, h, i, j, x, y, z, w, v)
}
Unless explicitly set to another value or iota, the first constant of each const group is set to its 0 value by default, and the second and subsequent constants are set to the value of the previous constant by default. Is iota, it is also set to iota.

Some rules of Go programming
Go is so concise because it has some default behavior:

Variables that start with a capital letter are exportable, that is, other packages can read them, and are public variables; those that start with a lowercase letter are non-exportable, and are private variables.
The same is true for functions that start with a capital letter, which is equivalent to a public function in the class with the public keyword; a function that starts with a lowercase letter is a private function with the private keyword.
array, slice, map
array
array is an array, and it is defined as follows:

var arr [n] type
In [n] type, n represents the length of the array, and type represents the type of the storage element. Operations on arrays are similar to other languages. They are read or assigned by []:

var arr [10] int // declares an array of type int
arr [0] = 42 // array indexing starts from 0
arr [1] = 13 // assignment operation
fmt.Printf ("The first element is% d \ n", arr [0]) // Get data, return 42
fmt.Printf ("The last element is% d \ n", arr [9]) // Returns the last element without a value, which returns 0 by default
Since the length is also part of the array type, [3] int and [4] int are different types, and the array cannot change its length. Assignment between arrays is the assignment of values, that is, when an array is passed as a parameter When a function is passed, it is actually a copy of the array, not its pointer. If you want to use pointers, then you need to use the slice type described later.

Arrays can be declared using another: =

a: = [3] int {1, 2, 3} // declares an array of ints of length 3

b: = [10] int {1, 2, 3} // declares an int array of length 10, where the first three elements are initialized to 1, 2, 3, and the other defaults to 0

c: = [...] int {4, 5, 6} // You can omit the length and use `...`, Go will automatically calculate the length based on the number of elements
Maybe you would say, I think the value in the array is still an array, can it be achieved? Of course, Go supports nested arrays, that is, multidimensional arrays. For example, the following code declares a two-dimensional array:

// declares a two-dimensional array with two arrays as elements, each of which has 4 elements of type int
doubleArray: = [2] [4] int {[4] int {1, 2, 3, 4}, [4] int {5, 6, 7, 8}}

// The above declaration can be simplified, and the internal types are ignored directly
easyArray: = [2] [4] int {{1, 2, 3, 4}, {5, 6, 7, 8}}
The allocation of the array is as follows:

Multidimensional array mapping

slice
In many application scenarios, arrays cannot meet our needs. When the array was initially defined, we didn't know how big the array was, so we needed a "dynamic array". This data structure in Go is called slice

A slice is not really a dynamic array, but a reference type. A slice always points to an underlying array, and the slice declaration can also be like an array, but it doesn't need a length.


// same as declaring array, but with less length
var fslice [] int
Next we can declare a slice and initialize the data as follows:

slice: = [] byte {'a', 'b', 'c', 'd'}
A slice can be declared again from an array or an existing slice. A slice is obtained by array [i: j], where i is the start position of the array and j is the end position, but does not include array [j], and its length is j-i.

// declare an array containing 10 elements with element type byte
var ar = [10] byte {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'}

// declare two slices containing bytes
var a, b [] byte

// a points to the beginning of the third element of the array and ends at the fifth element,
a = ar [2: 5]
// The elements that a now contains: ar [2], ar [3], and ar [4]

// b is another slice of array ar
b = ar [3: 5]
// The elements of b are: ar [3] and ar [4]
Note the difference between slice and array when declaring: when declaring an array, the square brackets indicate the length of the array or use ... to automatically calculate the length, and when declaring slices, there are no characters in the square brackets.

Their data structure is shown below

Mapping between slices and arrays

Slice has some easy operations

The default start position of a slice is 0, ar [: n] is equivalent to ar [0: n]
The second sequence of the slice defaults to the length of the array, ar [n:] is equivalent to ar [n: len (ar)]
If you get slices directly from an array, you can do ar [:], because by default the first sequence is 0 and the second is the length of the array, which is equivalent to ar [0: len (ar)]
The following example shows more about slice operations:

// declare an array
var array = [10] byte {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'}
// declare two slices
var aSlice, bSlice [] byte

// Demonstrate some simple operations
aSlice = array [: 3] // equivalent to aSlice = array [0: 3] aSlice contains elements: a, b, c
aSlice = array [5:] // equivalent to aSlice = array [5:10] aSlice contains elements: f, g, h, i, j
aSlice = array [:] // equivalent to aSlice = array [0:10] so that aSlice contains all the elements

// get slice from slice
aSlice = array [3: 7] // aSlice contains elements: d, e, f, g, len = 4, cap = 7
bSlice = aSlice [1: 3] // bSlice contains aSlice [1], aSlice [2] also contains: e, f
bSlice = aSlice [: 3] // bSlice contains aSlice [0], aSlice [1], aSlice [2] which also contains: d, e, f
bSlice = aSlice [0: 5] // The slice of slice can be expanded within the range of cap. At this time, bSlice contains: d, e, f, g, h
bSlice = aSlice [:] // bSlice contains all the elements of aSlice: d, e, f, g
Slice is a reference type, so when a reference changes the value of an element, all other references will change the value, such as aSlice and bSlice above. If you modify the value of an element in aSlice, the corresponding value of bSlice will change.

Conceptually, a slice is like a structure. This structure contains three elements:

A pointer to the starting position specified by the slice in the array
Length, which is the length of the slice
Maximum length, which is the length from the beginning of the slice to the last position of the array
    Array_a: = [10] byte {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'}
    Slice_a: = Array_a [2: 5]
The actual storage structure of the above code is shown below


Information about slice corresponding array

There are several useful built-in functions for slices:

len gets the length of the slice
cap Get the maximum capacity of the slice
append appends one or more elements to the slice and returns a slice of the same type as the slice
The copy function copies elements from the src of the source slice to the target dst, and returns the number of elements copied
Note: the append function changes the contents of the array referenced by the slice, thereby affecting other slices that reference the same array.
But when there is no space left in the slice (ie (cap-len) == 0), a new array space is dynamically allocated at this time. The returned slice array pointer will point to this space, and the contents of the original array will remain unchanged; other slices that reference this array will not be affected.

Since Go 1.2, slices support three-slice slices. Previously, we have always used this method to obtain a slice based on a slice or an array.

var array [10] int
slice: = array [2: 4]
The capacity of the slice in this example is 8, which can be specified in the new version.

slice = array [2: 4: 7]
The capacity of the above one is 7-2, which is 5. This way the resulting new slice cannot access the last three elements.

If slice is of the form array [: i: j], that is, the first parameter is empty, the default value is 0.

map
map is the concept of a dictionary in Python, and its format is map [keyType] valueType

We look at the following code. The reading and setting of the map is similar to the slice, and it is operated by the key, but the index of the slice can only be of type ` int `, and the map has many types, which can be int, string, and all The types of == and! = Operations are fully defined.

// Declare a dictionary whose key is a string and whose value is int. This way of declaration needs to be initialized with make before use.
var numbers map [string] int
// Another way to declare maps
numbers = make (map [string] int)
numbers ["one"] = 1 // assign
numbers ["ten"] = 10 // assign
numbers ["three"] = 3

fmt.Println ("The third number is:", numbers ["three"]) // read data
// print it out as: the third number is: 3
This map is like the table we usually see. The left column is the key and the right column is the value.

Some points to note when using map:

The map is out of order, and the printed map will be different each time. It cannot be obtained by index, but must be obtained by key.
The length of the map is not fixed, that is, it is also a reference type like slice
The built-in len function is also applicable to maps, returning the number of keys owned by the map
The value of the map can be easily modified. It is easy to change the value of the dictionary whose key is one to 11 by numbers ["one"] = 11.
Map is different from other basic types. It is not thread-safe. When multiple go-routine accesses, the mutex lock mechanism must be used.
The initialization of the map can initialize the value by means of key: val. At the same time, the map has a built-in method to determine whether a key exists.

Delete elements of map by delete:

// initialize a dictionary
rating: = map [string] float32 {"C": 5, "Go": 4.5, "Python": 4.5, "C ++": 2}
// map has two return values, the second return value, if key does not exist, then ok is false, if exists, ok is true
csharpRating, ok: = rating ["C #"]
if ok {
    fmt.Println ("C # is in the map and its rating is", csharpRating)
} else {
    fmt.Println ("We have no rating associated with C # in the map")
}

delete (rating, "C") // delete the element with key C
As mentioned above, map is also a reference type. If two maps point to a bottom layer at the same time, one changes and the other changes accordingly:

m: = make (map [string] string)
m ["Hello"] = "Bonjour"
m1: = m
m1 ["Hello"] = "Salut" // The value of m ["hello"] is now Salut
make, new operation
make is used for memory allocation of built-in types (map, slice, and channel). new is used for various types of memory allocation.

make
The built-in function new is essentially the same as the function of the same name in other languages: new (T) allocates zero-filled T type memory space and returns its address, which is a * T type value. In Go's terms, it returns a pointer to the zero value of the newly allocated type T. One thing is very important:

new
new returns a pointer.

The built-in function make (T, args) and new (T) have different functions. Make can only create slices, maps, and channels, and returns a T type with an initial value (non-zero) instead of * T. Essentially, what makes these three types different is that references to data structures must be initialized before use. For example, a slice is a three-item descriptor containing a pointer to the data (internal array), length, and capacity; before these items are initialized, the slice is nil. For slices, maps, and channels, make initializes internal data structures and fills them with appropriate values.

make returns an initialized (non-zero) value.

The following figure explains the difference between new and make in detail.

make and new correspond to the underlying memory allocation

Zero value
Regarding "zero value", it is not a null value, but a default value of "before the variable is filled", usually 0.
Here are some types of "zero values"

int 0
int8 0
int32 0
int64 0
uint 0x0
rune 0 // The actual type of rune is int32
byte 0x0 // the actual type of byte is uint8
float32 0 // length is 4 byte
float64 0 // length is 8 byte
bool false
string ""
Disclaimer: The main content of this article 

The content comes from the e-book "GO web programming". The author has only done language fluency optimization and simple typographic adaptation.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.