Herramientas de usuario

Herramientas del sitio


wiki2:go_basics

¡Esta es una revisión vieja del documento!


Go Basics

Basics

Program structure

package main
import "fmt"

func main() {
	fmt.Println("Hello world!")
}

You can write two types of programs: executable programs and shared libraries. When you write executable programs, you must give main as the package name to make the package an executable program. The executable programs in Go are often referred to as commands in the official Go documentation. The entry point of the executable program is the main function of the main package.

Commands

go run <codefile>

go build

go install

The following go get command fetches the third-part package negroni and installs it into the GOPATH location:
go get github.com/codegangsta/negroni

go fmt <code>
The Go tool provides the fmt command to format Go code. It is a good practice to format Go programs before committing source files into version control systems. The go fmt command applies predefined styles to the source code for format source files, which ensures the right placement of curly brackets, ensures the proper usage of tabs and spaces, and alphabetically sorts package imports. The go fmt command can be applied at the package level or on a specific source file.

godoc fmt
If you want to get documentation for the fmt package, type the following command in the terminal. The godoc tool also provides browsable documentation on a web interface. To access the documentation through a web-based interface, start the web server provided by the godoc tool. Type the following command in the terminal:
godoc -http=:3000

Packages

fmt to format and print data.

Tests

En una librería, pongamos “calc” añadimos el archivo calc_test.go con el siguiente contenido:

package calc

import "testing"

func TestAdd(t *testing.T) {
	var result = Add(3, 4)
	if result != 7 {
		t.Error("Expected 7, got", result);
	}
}

Para correr tests: go test.

Sintaxis

Variables

// `var` declares 1 or more variables.
var a string = "initial"
var b, c int = 1, 2
// Go will infer the type of initialized variables.
var d = true
// Variables declared without a corresponding
// initialization are _zero-valued_. For example, the
// zero value for an `int` is `0`.
var e int
// The `:=` syntax is shorthand for declaring and
// initializing a variable, e.g. for
// `var f string = "short"` in this case.
f := "short"

Constantes

const n = 500000000
const d = 3e20 / n

Imports and packages

import (
	"fmt"
	"./calc"
)

With package alias:

import (
  mongo "lib/mongodb/db"
  mysql "lib/mysql/db"
)
...
mongo.Get() //calling method of package "lib/mongodb/db"
mysql.Get() //calling method of package "lib/mysql/db"

The idiomatic way to provide a package name is to give short and simple lowercase names without underscores or mixed capital letters. The package names of the standard library are a great reference for naming packages.

You may need to provide some initialization logic for the packages, such as initializing package variables, initializing database objects, and providing some bootstrapping logic for the packages. The init function, which helps provide initialization logic into packages, is executed at the beginning of the execution.

package db
import (
  "gopkg.in/mgo.v2"
)
var Session *mgo.Session //Database Session object
func init() {
  // initialization code here
  Session, err := mgo.Dial("localhost")
}
func get() {
  //logic for get that uses Session object
}

In some scenarios, you may need to reference a package to invoke only its init method to execute the initialization logic in the referenced package, but not to use other identifiers. Suppose that you want the init function of package db (refer to Listing 2-3) to be invoked from the package main, but not use other functions. Keep in mind that you can’t directly call the init function by explicitly referencing it. If you want to reference a package only for invoking its init method, you can use a blank identifier (_) as the package alias name.

import (
"fmt"
  _ "lib/mongodb/db"
)

Go source files are organized into directories as packages that provide code reusability into other packages. If you want to reuse package code into other shared libraries and executable programs, you must import the packages into your programs.

When you import a package into a program, you can reuse all the exported identifiers of the referenced packages. If you want to export variables, constants, and functions to be used with other programs, the name of the identifier must start with an uppercase letter.

Collections

Array

Declaring an Integer Array of Five Elements

var x [5]int
x[0] = 10
x[1] = 20
x[2] = 30
x[3] = 40
x[4] = 50

x := [5]int{10, 20, 30, 40, 50}
// Initializing Values for Specific Elements
x := [5]int{2: 10, 4: 40}  // [0 0 10 0 40]

Slices

Slices are a data structure that is very similar to an array, but has no specified length. It is an abstraction built on top of an array type that provides a more convenient way of working with collections.

var x []int

The length of the slice is the number of elements referred to by the slice; the capacity is the number of elements in the underlying array. A slice can’t hold values beyond its capacity; if you try to add more elements, a runtime error will occur. A slice can be grown by using the append function.

When you declare a slice with the make function, you can explicitly specify the length and capacity of a slice. If the slice capacity is not specified, the capacity is the same as the length.

x := make([]int, 5,10)
x := []int{10,20,30}
y := append(x, 40, 50)
// y = [10 20 30 40 50]

x := []int{10, 20, 30}
y := make([]int, 2)
copy(y, x)
copy(y, x)
// y = [10 20]

Maps

dict := make(map[string]string)
dict["go"] = "Golang"
dict["cs"] = "CSharp"
for k, v := range dict {
  fmt.Printf("Key: %s Value: %s\n", k, v)
}

lan, ok := dict["go"]

Conditionals

if 7%2 == 0 {
    fmt.Println("7 is even")
} else {
    fmt.Println("7 is odd")
}

// You can have an `if` statement without an else.
if 8%4 == 0 {
    fmt.Println("8 is divisible by 4")
}

// A statement can precede conditionals; any variables
// declared in this statement are available in all
// branches.
if num := 9; num < 0 {
    fmt.Println(num, "is negative")
} else if num < 10 {
    fmt.Println(num, "has 1 digit")
} else {
    fmt.Println(num, "has multiple digits")
}
if lan, ok := dict["go"]; ok {
  fmt.Println(lan, ok)
}

Switch

i := 2
fmt.Print("Write ", i, " as ")
switch i {
case 1:
    fmt.Println("one")
case 2:
    fmt.Println("two")
case 3:
    fmt.Println("three")
}

switch time.Now().Weekday() {
case time.Saturday, time.Sunday:
    fmt.Println("It's the weekend")
default:
    fmt.Println("It's a weekday")
}

t := time.Now()
switch {
case t.Hour() < 12:
    fmt.Println("It's before noon")
default:
    fmt.Println("It's after noon")
}

whatAmI := func(i interface{}) {
    switch t := i.(type) {
    case bool:
        fmt.Println("I'm a bool")
    case int:
        fmt.Println("I'm an int")
    default:
        fmt.Printf("Don't know type %T\n", t)
    }
}
whatAmI(true)
whatAmI(1)
whatAmI("hey")

Loops

x := []int{10, 20, 30, 40, 50}
for k, v := range x {
  fmt.Printf("Index: %d Value: %d\n", k, v)
}

i := 1
for i <= 3 {
    fmt.Println(i)
    i = i + 1
}

// A classic initial/condition/after `for` loop.
for j := 7; j <= 9; j++ {
    fmt.Println(j)
}

// `for` without a condition will loop repeatedly
// until you `break` out of the loop or `return` from
// the enclosing function.
for {
    fmt.Println("loop")
    break
}

// You can also `continue` to the next iteration of
// the loop.
for n := 0; n <= 5; n++ {
    if n%2 == 0 {
        continue
    }
    fmt.Println(n)
}

Range

nums := []int{2, 3, 4}
sum := 0
for _, num := range nums {
    sum += num
}

for i, num := range nums {
    if num == 3 {
        fmt.Println("index:", i)
    }
}

kvs := map[string]string{"a": "apple", "b": "banana"}
for k, v := range kvs {
    fmt.Printf("%s -> %s\n", k, v)
}

for k := range kvs {
    fmt.Println("key:", k)
}

for i, c := range "go" {
    fmt.Println(i, c)
}

Functions

func vals() (int, int) {
    return 3, 7
}

func main() {
    a, b := vals()
    _, c := vals()
}
func sum(nums ...int) {
    fmt.Print(nums, " ")
    total := 0
    for _, num := range nums {
        total += num
    }
    fmt.Println(total)
}

func main() {

    // Variadic functions can be called in the usual way
    // with individual arguments.
    sum(1, 2)
    sum(1, 2, 3)

    // If you already have multiple args in a slice,
    // apply them to a variadic function using
    // `func(slice...)` like this.
    nums := []int{1, 2, 3, 4}
    sum(nums...)
}
func intSeq() func() int {
    i := 0
    return func() int {
        i += 1
        return i
    }
}

func main() {
    nextInt := intSeq()
    fmt.Println(nextInt())
    fmt.Println(nextInt())
    fmt.Println(nextInt())
    newInts := intSeq()
    fmt.Println(newInts())
}

Error handling

A defer statement pushes a function call (or a code statement) onto a list. The list of saved “function calls” is executed after the surrounding function returns. The last added functions are invoked first from the list of deferred functions. Using defer, you can implement cleanup code in Go, which is more efficient than using a finally block in other languages. Suppose you add function f1 first, then f2, and finally f3 onto the deferred list; the order of the execution will be f3, f2, and then f1. This code block creates a session object for a MongoDB database. In the next line, the code statement session.Close() is added onto the deferred list to clean up the resources of the database session object after returning the surrounding function. You can add any number of code statements and functions onto the deferred list.

session, err := mgo.Dial("localhost") //MongoDB Session object
defer session.Close()
c := session.DB("taskdb").C("categories")
//code statements using session object

The panic function is a built-in function that lets you stop the normal flow of control and panic a function. When you call panic from a function, it stops the execution of the function, any deferred functions are executed, and the caller function gets a panicking function. Keep in mind that all deferred functions are executed normally before the execution stops. When developing applications, you will rarely call the panic function because your responsibility is to provide proper error messages rather than stopping the normal control flow. But in some scenarios, you may need to call the panic function if there are no possibilities to continue the normal flow of control. For example, if you can’t connect to a database server, it doesn’t make any sense to continue executing the application.

session, err := mgo.Dial("localhost") // Create MongoDB Session object
if err != nil {
 panic(err)
}
defer session.Close()

The recover function is a built-in function that is typically used inside deferred functions that regain control of a panicking function. The recover function is useful only inside deferred functions because the differing statements are the only way to execute something when a function is panicking.

func doPanic() {
	defer func() {
		if e := recover(); e != nil {
			fmt.Println("Recover with: ", e)
		}
	}()
	panic("Just panicking for the sake of demo")
	fmt.Println("This will never be called")
}
func main() {
	fmt.Println("Starting to panic")
	doPanic()
	fmt.Println("Program regains control after panic recover")
}

Structured data

type Person struct {
	FirstName, LastName string
	Dob 				time.Time
	Email, Location		string
}

var p Person
p.FirstName="Shiju"
p.LastName="Varghese"
p.Dob= time.Date(1979, time.February, 17, 0, 0, 0, 0, time.UTC)
p.Email= "shiju@email.com"
p.Location="Kochi"

p:= Person {
	FirstName : "Shiju",
	LastName : "Varghese",
	Dob : time.Date(1979, time.February, 17, 0, 0, 0, 0, time.UTC),
	Email : "shiju@email.com",
	Location : "Kochi",
}

p:= Person {
	"Shiju",
	"Varghese",
	time.Date(1979, time.February, 17, 0, 0, 0, 0, time.UTC),
	"shiju@email.com",
	"Kochi",
}

//A person method
func (p Person) PrintName() {
	fmt.Printf("\n%s %s\n", p.FirstName, p.LastName)
}

p. PrintName()

If you want to modify the data of a receiver from the method, the receiver must be a pointer:

func (p *Person) ChangeLocation(newLocation string) {
	p.Location= newLocation
}

Because you want to call a pointer receiver method, you can create the Person type instance by providing the ampersand (&) operator.

p := &Person{
	"Shiju",
	"Varghese",
	time.Date(1979, time.February, 17, 0, 0, 0, 0, time.UTC),
	"shiju@email.com",
	"Kochi",
}
p.ChangeLocation("Santa Clara")
p.PrintName()

Type Embedding for Composition. The Person type is embedded into Admin and Member types so that all Person fields and methods will be available in these new types.

type Admin struct {
	Person //type embedding for composition
	Roles []string
}
type Member struct {
	Person //type embedding for composition
	Skills []string
}

alex := Admin{
	Person{
		"Alex",
		"John",
		time.Date(1970, time.January, 10, 0, 0, 0, 0, time.UTC),
		"alex@email.com",
		"New York"
	},
	[]string{"Manage Team", "Manage Tasks"},
}

//A person method
func (p Person) PrintDetails() {
	fmt.Printf("[Date of Birth: %s, Email: %s, Location: %s ]\n", p.Dob.String(), p.Email, p.Location)
}
func (a Admin) PrintDetails() {
	a.Person.PrintDetails()
	fmt.Println("Admin Roles:")
	for _, v := range a.Roles {
		fmt.Println(v)
	}
}
wiki2/go_basics.1513535643.txt.gz · Última modificación: 2020/05/09 09:24 (editor externo)