ethan

ethan

新知,热爱生活,码农,读书
twitter
email
github

Go Language Basics

Basics of Go Language: Variables and Constants#

Variables and constants are essential parts of programming and are also quite easy to understand.

Identifiers and Keywords#

Identifiers#

In programming languages, an identifier is a word defined by the programmer that has a special meaning, such as variable names, constant names, function names, etc. In Go language, identifiers consist of alphanumeric characters and underscores (_), and they can only start with a letter or an underscore.

Keywords#

Keywords refer to identifiers that are predefined in the programming language with special meanings. It is not recommended to use keywords and reserved words as variable names. There are 25 keywords in Go language:

break default func interface select 
case defer go map struct
chan else goto package switch
const fallthrough if range type
continue for import return var

Additionally, there are 37 reserved words in Go language.

Constants: true false iota nil
Types: int int8 int16 int32 int64
        uint uint8 uint16 uint32 uint64 uintptr
        float32 float64 complex128 complex64
        bool byte rune string error
Functions: make len cap new append copy close delete
            complex real imag
            panic recover

Variables#

Origin of Variables#

Data during program execution is stored in memory. When we want to manipulate a certain piece of data in the code, we need to find this variable in memory. However, if we directly manipulate variables through memory addresses in the code, the readability of the code will be very poor and prone to errors. Therefore, we use variables to save the memory address of this data, allowing us to find the corresponding data in memory directly through this variable later.

Variable Types#

The function of a variable is to store data. Different variables may store different types of data. Every variable in Go language has its own type, and a variable must be declared before it can be used.

Variable Declaration#

In Go language, variables need to be declared before they can be used, and duplicate declarations are not supported within the same scope. Moreover, variables in Go language must be used after declaration.

Standard Declaration#

The format for declaring a variable in Go language is:

var variableName variableType

Variable declarations start with the keyword var, and the variable type is placed after the variable name, with no semicolon needed at the end of the line.

Type Inference#

Sometimes we may omit the type of a variable; in this case, the compiler will infer the variable's type based on the value on the right side of the equals sign to complete the initialization.

var name = "Q1mi"
var age = 18

Short Variable Declaration#

Inside a function, a more concise := syntax can be used to declare and initialize variables.

package main
import (
    "fmt"
)
// Global variable m
var m = 10

func main() {
    n := 10
    m := 200 // Here, a local variable m is declared
    fmt.Println(m, n)
}

Anonymous Variables#

When using multiple assignments, if you want to ignore a certain value, you can use an anonymous variable. Anonymous variables are represented by an underscore (_).

func foo() (int, string) {
    return 10, "Q1mi"
}
func main() {
    x, _ := foo()
    _, y := foo()
    fmt.Println("x=", x)
    fmt.Println("y=", y)
}

Anonymous variables do not occupy namespace and do not allocate memory, so there is no duplicate declaration between anonymous variables. Notes:

  1. Every statement outside of a function must start with a keyword (var, const, func, etc.)
  2. := cannot be used outside of a function.
  3. _ is often used as a placeholder to indicate an ignored value.

Constants#

Compared to variables, constants are values that remain unchanged and are often used to define values that will not change during the program's execution. The declaration of constants is very similar to that of variables, except that var is replaced with const, and constants must be assigned a value at the time of definition. Their values cannot change throughout the program's execution.

Iota#

iota is a constant counter in Go language that can only be used in constant expressions. iota is reset to 0 when the const keyword appears. Each new line of constant declaration in const increments the iota count (it can be understood as the line index in the const statement block). Using iota simplifies definitions and is useful when defining enumerations.

Logical Operators#

OperatorDescription
&&Logical AND operator. True if both operands are True
||Logical OR operator
!Logical NOT operator

Variable Scope#

Global variables start with an uppercase letter and can be accessed everywhere; accessing across packages requires the package name. Global variables starting with a lowercase letter can be accessed within the same package. Local variables can only be accessed within their own function. Internally declared variables can conflict with externally declared variables, with the internal one taking precedence. Access is limited to the scope defined by {}, and conflicts with external variables can occur.

Variable Lifetime#

The lifetime of a variable refers to the duration during which it exists and is valid during program execution. For variables declared at the package level, their lifetime is consistent with the entire program's runtime. In contrast, the lifetime of local variables is dynamic: it starts from the declaration statement that creates a new variable and lasts until the variable is no longer referenced, after which the variable's storage space may be reclaimed. Notes:

  • Since a variable's effective period only depends on reachability, the lifetime of a local variable inside a loop iteration may exceed its local scope. Additionally, local variables may still exist after the function returns.

Basics of Go Language: Basic Data Types and Comments#

Go language has a rich set of data types, including basic types such as integers, floating-point numbers, booleans, and strings, as well as arrays, slices, structs, functions, maps, channels, etc. The basic types in Go language are similar to those in other languages.

Basic Data Types#

Integer Types#

Integer types are divided into two main categories: by length: int8, int16, int32, int64, and their corresponding unsigned integer types: uint8, uint16, uint32, uint64. Among these, uint8 is the byte type we are familiar with. Int16 corresponds to the short type in C language, and Int64 corresponds to the long type in C language.

TypeDescription
uint8Unsigned 8-bit integer (0-255)
uint16Unsigned 16-bit integer (0-65535)
uint32Unsigned 32-bit integer (0-4294967295)
uint64Unsigned 64-bit integer (0-18446744073709551615)
int8Signed 8-bit integer (-128-127)
int16Signed 16-bit integer (-32768 to 32767)
int32Signed 32-bit integer

Boolean Values#

In Go language, boolean data is declared using the bool type, which can only have two values: true and false. Notes:

  1. The default value of a boolean type variable is false.
  2. Go language does not allow implicit conversion from integer types to boolean types.
  3. Boolean types cannot participate in numerical operations and cannot be converted to other types.

Strings#

Strings in Go language are treated as a native data type, and using strings is similar to using other native data types (int, bool, float32, float64, etc.). The internal implementation of strings in Go language uses UTF-8 encoding. The value of a string is the content within double quotes ("), and you can directly add non-ASCII characters in Go language, for example:

s1 := "hello"

Common String Operations#

MethodDescription
len(str)Get length
+ or fmt.SprintfConcatenate strings
strings.SplitSplit
strings.ContainsCheck if contains
strings.HasPrefix, strings.HasSuffixPrefix/Suffix check
strings.Index(), strings.LastIndex()Position of substring
strings.Join(a[] string, sep string)Join operation

Byte and Rune Types#

The elements that make up each string are called "characters," which can be obtained by iterating or accessing individual string elements. Characters are wrapped in single quotes ('), for example:

var a = ''
var b = 'x'
// byte is equivalent to uint8, rune is equivalent to int32
// rune can represent any Unicode character

Composite Data Types#

TypeDefault ValueDescription
arrayValue type
structValue type
string""UTF-8 string
slicenilReference type
mapnilReference type
channelnilReference type
interfacenilInterface
functionnilFunction

Arrays#

An array is a block of contiguous memory space, and its length must be specified at the time of declaration, which cannot be changed. Thus, the memory space can be allocated and initialized with default values at the time of declaration.

Initializing Arrays#

var arr [5]int = [5]int{} // Arrays must specify length and type, and these cannot change after specification
var arr2 = [5]int{}
var arr3 = [5]int{3, 2} // Assign values to the first two elements
var arr4 = [5]int{2: 15, 4: 30} // Specify index for assignment
var arr5 = [...]int{3, 2, 6, 5, 4} // Infer array length based on the number of elements in {}
var arr6 = [...]struct {
    name string
    age  int
}{{"Tome", 18}, {"Jim", 20}} // The element type of the array is defined by an anonymous struct

Accessing Elements in an Array#

  • Access by index

    • First element: arr[0]
    • Last element: arr[len(arr)-1]
  • Accessing elements in a two-dimensional array

    • The element in the third row and fourth column: arr[2][3]

      // Iterate through elements in an array
      for i, ele := range arr {
          fmt.Printf("index=%d, element=%d\n", i, ele)
      }
      // Iterate through a two-dimensional array
      for row, array := range arr {
          for col, ele := range array {
              fmt.Printf("arr[%d][%d]=%d\n", row, col, ele)
          }
      }
      

      Cap and Len#

  • Cap represents capacity

  • Len represents length

  • len represents the number of elements currently in the array, while cap represents how many elements the allocated memory space can hold.

  • Since arrays do not change after initialization, there is no need to reserve memory space for them, so len(arr) = cap(arr).

    Passing Arrays as Parameters#

  • The length and type of an array are part of the array type, and both must match when passing an array type to a function.

  • Go language does not pass by reference; all parameters are passed by value, meaning that passing an array actually sends a copy of the array. When the array length is large, the overhead of passing parameters can be significant.

  • If you want to modify an array outside the function, pass its pointer (the address of the array in memory).

Slices#

type slice struct {
    array unsafe.Pointer
    len   int
    cap   int 
}

Initializing Slices#

var s []int // Slice declaration, len=cap=0
s = []int{} // Initialization, len=cap=0
s = make([]int, 3) // Initialization, len=cap=3
s = make([]int, 3, 5) // Initialization, len=3, cap=5
s = []int{11, 2, 3, 4, 5} // Initialization, len=cap=5
s2d := [][]int {
    {1}, {2, 3},  // Each row of a two-dimensional array has the same number of columns, but the lengths of each row in a two-dimensional slice can vary.
}

Append#

  • The biggest feature of slices compared to arrays is that they can append elements and automatically expand.

  • The appended elements are placed in the reserved memory space, and len increases by 1.

  • If the reserved space is exhausted, a larger memory space will be requested, with capacity becoming double the previous size (if cap<1024) or 1.25 times the previous size (if cap>1024). The data from the original memory space is copied over, and the append operation is executed in the new memory space.

    Slicing Sub-slices#

  • s := make([]int, 3, 5) // len=3, cap=5

  • sub_slice = s[1:3] // len = 2, cap=4

  • Initially, the sub-slice and the parent slice share the underlying memory space; modifying the sub-slice will reflect in the parent slice. Executing append on the sub-slice will place new elements in the reserved memory space of the parent slice.

  • When the sub-slice continuously executes append and exhausts the reserved memory space of the parent slice, the sub-slice will separate from the parent slice, and the two slices will have no relation.

Passing Slices as Parameters#

  • In Go language, parameters are passed by value, meaning that passing a slice will copy the three fields {arrayPointer, len, cap}.

  • Since the pointer to the underlying array is passed, you can directly modify the elements in the underlying array.

    Maps#

    A map is an unordered collection of key/value pairs, where all keys are unique, and you can retrieve, update, or delete the corresponding value in constant time complexity using a given key.

Pointers#

Definition#

Custom Types and Strings#

  • Type alias

    • Type byte = uint8
    • Type rune = int32
  • Custom types

    • type signal uint8

    • Type ms map[string]string

    • Type add func(a, b int) int

    • Type user struct {name string; age int}

      Type Conversion#

      var i int = 9
      var by byte = byte(i)  // Convert int to byte
      i = int(by)  // Convert byte to int
      fmt.Printf("i=%d\n", i)
      
  • Byte and int can be converted to each other.

  • Float and int can be converted to each other, with decimal places lost.

  • Bool and int cannot be converted to each other.

  • Integers or floats of different lengths can be converted to each other.

  • String can be converted to []byte or []rune types, and byte or rune can be converted to string.

  • Converting from lower precision to higher precision is fine, but converting from higher precision to lower precision will lose bits.

  • Converting from unsigned to signed will consider the highest bit as the sign bit.

    Comments#

  • Single-line comments start with //.

  • Multi-line comments can be written continuously with //, or use /* at the beginning of the block and */ at the end.

  • No empty lines can appear between multi-line comments.

  • NOTE: Attention needed, TODO: Needs optimization in the future, Deprecated: Variables or functions are strongly discouraged from being used.

  • Indentation can be added before comment lines to write Go code.

  • Package comments are placed above the package declaration (package xxx). A package only needs one package comment, typically written in a doc.go file, which contains only one line of package declaration and comments about the package.

  • Struct comments are placed above the type declaration (type xxx struct).

  • Function comments are placed above the function declaration (func xxx()).

  • Line comments can be placed above or to the right of a line.

    Godoc#

  • Go doc is a command that comes with Go.

  • Go doc entrance class/util

  • Go doc can export web-based documentation for project code.

  • You need to install it first using go get golang.org/x/tools/cmd/godoc.

  • Start with http: godoc -http:6060.

  • Access it via the browser: http://127.0.0.1:6060/pkg/go-course/entrans_class

Packages and Tools#

Packages#

Package Overview#

  • All imported packages must be explicitly declared at the beginning of each file.

  • Circular dependencies between packages are prohibited, as there are no circular dependencies; the dependencies of packages form a directed acyclic graph, allowing each package to be compiled independently and likely concurrently.

  • The target files of compiled packages not only record the exported information of the package itself but also record the package's dependencies.

    Import Paths#

    Each package is identified by a globally unique string known as the import path. The import path appearing in the import statement is also a string. The Go language specification does not specify the exact meaning of the import path string; the specific meaning of the import path is interpreted by the build tools.

    Package Declaration#

    Each Go language source file must have a package declaration statement at the beginning. The main purpose of the package declaration statement is to determine the default identifier (also known as the package name) when the current package is imported by other packages.

    Package Naming#

  • Avoid using names that may frequently be used for local variables as package names, as this may lead users to rename the imported package.

  • Package names are generally in singular form. Standard library packages like bytes, errors, and strings use plural forms to avoid conflicts with predefined types, and similarly, go/types is used to avoid conflicts with the type keyword.

    Tools#

    The Go language toolbox is a collection of functional command sets. It can be seen as a package manager for querying packages, calculating package dependencies, downloading them from remote version control systems, etc. It also serves as a build system, calculating file dependencies, and then invoking compilers, assemblers, and linkers to build programs, as well as a driver for unit testing and benchmarking.

Downloading Packages#

Using the Go language toolbox's go command, you can not only find local workspace packages based on the package import path but also find and update packages from the internet.

The command go get can download a single package or use ... to download every package in a subdirectory. The Go language toolbox's go command also calculates and downloads each package it depends on.

Once the go get command downloads a package, it then installs the package or the corresponding executable program.

Building Packages#

The go build command compiles each package specified by the command line arguments. If the package is a library, the output result is ignored; this can be used to check if the package can compile correctly. If the package name is main, go build will call the linker to create an executable program in the current directory, using the last segment of the import path as the executable program's name.

Since each directory contains only one package, each corresponding executable program, or what is called a package in Unix terminology, must be placed in a separate directory.

Interfaces#

The interface type is an abstraction and generalization of the behavior of other types; because the interface type is not bound to specific implementation details, this abstraction allows our functions to be more flexible and adaptable. The unique aspect of interface types in Go language is that they satisfy implicit implementation. This means that we do not need to define all the specific types that satisfy a given concrete type, and we do not have to change the definitions of these types.

Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.