运行go程序

go install

learngo/main.go

package main
import "fmt"
func main(){
    fmt.Println("Hello,World.")
}

运行go install进行编译,可能会报错

go install: no install location for directory /home/naveen/Documents/learngo outside GOPATH
For more details see: ‘go help gopath’

原因是go找不到编译文件存放位置,解决办法

export GOBIN=~/go/bin/  

表示编译后文件存放在~/go/bin/,这个路径可以随时更改。重新执行go install发现不会报错了,而且在该目录下生成了和项目同名的二进制文件。
运行

~/go/bin/learngo

添加PATH

可以避免每次编译时提示二进制文件位置找不到

~/.bash_profile

export PATH=$PATH:~/go/bin  

go build

在项目根目录生成编译后的二进制文件

go build

运行

./learngo

go run

go run main.go

go run后面必须是一个后缀为.go的文件名,该命令将编译后文件放在临时位置,可以通过以下命令查看

go run --work main.go  

package main
每个go文件都必须以package name开头。包用于提供代码分隔和可重用性。main方法必须始终声明在main
import "fmt"
用于向控制台输出信息
func main(){}
程序入口

包(package)

每个Go程序都是由组成的。程序入口在名为main中的包。按照约定,包名称与导入路径的最后一个单词相同。例如,import ( "fmt" "math/rand" )导入了以rand开头的包。

package main

import (
    "fmt"
    "math/rand"
)

func main() {
    fmt.Println("My favorite number is", rand.Intn(10))
}

import

import可以分多行写

package main

import "fmt"
import "math"

func main() {
    fmt.Printf("Now you have %g problems.n", math.Sqrt(7))
}

export name

在go中,如果名称以大写字母开头,则默认会被导出。例如,Pizza是导出名称,Pi是从math导出的名称

package main

import (
    "fmt"
    "math"
)

func main() {
    fmt.Println(math.Pi)
}
// 3.141592653589793

没有被导出名称不能通过import进来

变量

变量作用域可以是函数级或包级

变量声明

package main

import "fmt"

var c, python, java bool

func main() {
    var i int
    fmt.Println(i, c, python, java)
}
// 0 false false false

int类型默认初始化为0

变量在声明时赋值

var name type = initialvalue

类型推断

如果一个变量没有声明类型,go会进行类型推断。可以用%T查看变量类型:fmt.Printf(“v is of type %Tn”, v)

package main

import "fmt"

func main() {  
    var age = 29 // type will be inferred
    j := age // j is an int

    fmt.Println("my age is", age)
}

多变量声明

var name1, name2 type = initialvalue1, initialvalue2

也可以不指定变量类型

package main

import "fmt"

func main() {  
    var width, height = 100, 50 //"int" is dropped

    fmt.Println("width is", width, "height is", height)
}
// width is 0 height is 0  
// new width is 100 new height is  50  

用一条语句声明多个变量

var (
name1 = initialvalue1
name2 = initialvalue2
)

package main

import "fmt"

func main() {  
    var (
        name   = "naveen"
        age    = 29
        height int
    )
    fmt.Println("my name is", name, ", age is", age, "and height is", height)
}
// naveen , age is 29 and height is 0

声明变量便捷方式

:=可以用来声明隐式类型变量,但不能在函数外使用

package main

import "fmt"

func main() {  
    name, age := "naveen", 29 //short hand declaration

    fmt.Println("my name is", name, "age is", age)
}
// my name is naveen age is 29

使用这种方式赋值时,左边的变量至少有一个从未声明过,以下例子中a, b := 40, 50之前都声明了,运行会报错

package main

import "fmt"

func main() {  
    a, b := 20, 30 //a and b declared
    fmt.Println("a is", a, "b is", b)
    a, b := 40, 50 //error, no new variables
    a, c := 40, 50 // 0 error
}

基本类型变量

bool
string
int int8 int16 int32 int64
uint uint8 uint16 uint32 uint64 uintptr
byte // alias for uint8
rune // alias for int32
// represents a Unicode code point
float32 float64
complex64 complex128

package main

import (
    "fmt"
    "math/cmplx"
)

var (
    ToBe   bool       = false
    MaxInt uint64     = 1

zero值

对于没有显示赋值的变量,系统会自动赋zero值
整数是0,布尔类型是false,字符串类型是””

package main

import "fmt"

func main() {
    var i int
    var f float64
    var b bool
    var s string
    fmt.Printf("%v %v %v %qn", i, f, b, s)
}
// 0 0 false ""

类型转化

T(v)可以把v转化为T类型,go没有隐式类型转化,不同类型变量不能赋值

package main

import (
    "fmt"
    "math"
)

func main() {
    var x, y int = 3, 4
    var f float64 = math.Sqrt(float64(x*x + y*y))
    var z uint = uint(f)
    fmt.Println(x, y, z)
}
// 3 4 5

常量

常量用const关键字声明,常量可以是字符、字符串、布尔值和数字类型。常量不可以用:=声明

package main

import "fmt"

const Pi = 3.14

func main() {
    const World = "世界"
    fmt.Println("Hello", World)
    fmt.Println("Happy", Pi, "Day")

    const Truth = true
    fmt.Println("Go rules?", Truth)
}
// Hello 世界
// Happy 3.14 Day
// Go rules? true

数值型常量

数字型常量具有很高精度,没有显示声明类型的常量可以在不同场景变为不同类型

package main

import "fmt"

const (
    // Create a huge number by shifting a 1 bit left 100 places.
    // In other words, the binary number that is 1 followed by 100 zeroes.
    Big = 1 > 99
)

func needInt(x int) int { return x*10 + 1 }
func needFloat(x float64) float64 {
    return x * 0.1
}

func main() {
    fmt.Println(needInt(Small))
    fmt.Println(needFloat(Small))
    fmt.Println(needFloat(Big))
}
// 21
// 0.2
// 1.2676506002282295e+29

函数

函数声明

函数有0个或多个参数,参数的变量名在类型前面

package main

import "fmt"

func add(x int, y int) int {
    return x + y
}

func main() {
    fmt.Println(add(42, 13))
}
// 55

对于多个参数有相同类型,只需在最后声明一次参数类型

package main

import "fmt"

func add(x, y int) int {
    return x + y
}

func main() {
    fmt.Println(add(42, 13))
}
// 55

多个返回值

package main

import "fmt"

func swap(x, y string) (string, string) {
    return y, x
}

func main() {
    a, b := swap("hello", "world")
    fmt.Println(a, b)
}
// world hello

函数返回值命名

返回值和类型在函数头声明

package main

import "fmt"

//返回值在函数头声明
func split(sum int) (x, y int) {
    x = sum * 4 / 9
    y = sum - x
    return
}

func main() {
    fmt.Println(split(17))
}
// 7 10

流程控制

for

for init; condition; post statement ,其中init和post statement是可选的

package main

import "fmt"

func main() {
    sum := 0
    for i := 0; i 

for是go中的while

go没有while语句,但可以用for实现while的功能

package main

import "fmt"

func main() {
    sum := 1
    for sum 

forever

for 省略循环条件将出现死循环

package main

func main() {
    for {
    }
}

if

if语句的条件不用()包裹

package main

import (
    "fmt"
    "math"
)

func sqrt(x float64) string {
    if x 

if可以像for一样有初始化语句,初始化语句中的变量只能在if-else if-else语句块中使用:初始化; 条件 {}

package main

import (
    "fmt"
    "math"
)

func pow(x, n, lim float64) float64 {
        // 初始化; 条件 {}
    if v := math.Pow(x, n); v = %gn", v, lim)
    }
    // can't use v here, though
    return lim
}

func main() {
    fmt.Println(
        pow(3, 2, 10),
        pow(3, 3, 20),
    )
}
// 27 >= 20
// 9 20

switch

go语言中的switch语句无需break,go执行完满足条件的语句自动跳出,cases不仅可以是整数,还可以是字符串类型。switch语句也可以赋初值

package main

import (
    "fmt"
    "runtime"
)

func main() {
    fmt.Print("Go runs on ")
    switch os := runtime.GOOS; os {
    case "darwin":
        fmt.Println("OS X.")
    case "linux":
        fmt.Println("Linux.")
    default:
        // freebsd, openbsd,
        // plan9, windows...
        fmt.Printf("%s.n", os)
    }
}
// Go runs on nacl.

switch语句按顺序匹配条件满足一个不再继续匹配

package main

import (
    "fmt"
    "time"
)

func main() {
    fmt.Println("When's Saturday?")
    today := time.Now().Weekday()
    fmt.Println(time.Saturday)
    // Saturday
    switch time.Saturday {
    case today + 0:
        fmt.Println("Today.")
    case today + 1:
        fmt.Println("Tomorrow.")
    case today + 2:
        fmt.Println("In two days.")
    default:
        fmt.Println("Too far away.")
    }
}
// When's Saturday?
// Saturday
// Too far away.

没有condition的switch语句相当于if-then-if

package main

import (
    "fmt"
    "time"
)

func main() {
    t := time.Now()
    switch {
    case t.Hour() 

defer

推迟到函数返回时执行

package main

import "fmt"

func main() {
    defer fmt.Println("world")

    fmt.Println("hello")
}
// hello
// world

defer后面的函数也在最后执行

import "fmt"

func main() {
    defer hello()

    fmt.Println("hello")
}
func hello() {
    fmt.Println("world")
}
// hello
// world

defer的函数调用被压入栈中,按照后进先出原则在函数返回前依次调用

package main

import "fmt"

func main() {
    fmt.Println("counting")

    for i := 0; i 

更多数据类型

指针(Pointers)

指针存放值的地址,*T表示T类型指针,例如:var p *int&取地址,如p=&i*取地址下的值,如fmt.Println(*p)。空指针的值为nil。go不同c的地方在于go没有指针算法,go没有了引用传参

package main

import "fmt"

func main() {
    i, j := 42, 2701

    p := &i         // point to i
    fmt.Println(*p) // read i through the pointer
    *p = 21         // set i through the pointer
    fmt.Println(i)  // see the new value of i

    p = &j         // point to j
    *p = *p / 37   // divide j through the pointer
    fmt.Println(j) // see the new value of j
}
// 42
// 21
// 73

结构体(Structs)

结构体是一些成员的集合,声明结构体:type 结构体名 struct{}

package main

import "fmt"

type Vertex struct {
    X int
    Y int
}

func main() {
    fmt.Println(Vertex{1, 2})
}
// {1 2}

通过.访问引用类型中的成员

package main

import "fmt"

type Vertex struct {
    X int
    Y int
}

func main() {
    v := Vertex{1, 2}
    v.X = 4
    fmt.Println(v.X)
}
// 4

指向结构体的指针有些特殊,可以通过p.X访问成员,这是(*p).X的简写形式

package main

import "fmt"

type Vertex struct {
    X int
    Y int
}

func main() {
    v := Vertex{1, 2}
    p := &v
    p.X = 1e9
    fmt.Println(v)
}
// {1000000000 2}
结构体字面量

通过列出所有或部分成员的值来构造结构体,从前往后依次赋值,没有赋值的成员有默认值,可用Name:Value给某些成员赋值

package main

import "fmt"

type Vertex struct {
    X, Y int
}

var (
    v1 = Vertex{1, 2}  // has type Vertex
    v2 = Vertex{X: 1}  // Y:0 is implicit
    v3 = Vertex{}      // X:0 and Y:0
    p  = &Vertex{1, 2} // has type *Vertex
)

func main() {
    fmt.Println(v1, p, v2, v3)
}

数组(Arrays)

var [n]T声明n个值得T数组,数组大小一旦声明不允许改变

package main

import "fmt"

func main() {
    var a [2]string
    a[0] = "Hello"
    a[1] = "World"
    fmt.Println(a[0], a[1])
    fmt.Println(a)

    primes := [6]int{2, 3, 5, 7, 11, 13}
    fmt.Println(primes)
}
// Hello World
// [Hello World]
// [2 3 5 7 11 13]

切片(Slices)

切片是动态数组,它无需指定大小。切片通过指定上下界来构造:a[low : high]

package main

import "fmt"

func main() {
    primes := [6]int{2, 3, 5, 7, 11, 13}

    var s []int = primes[1:4]
    fmt.Println(s)
}
// [3 5 7]

切片是原数组的一部分,改变原数组会改变切片,改变切片也会改变原数组

package main

import "fmt"

func main() {
    names := [4]string{
        "John",
        "Paul",
        "George",
        "Ringo",
    }
    fmt.Println(names)

    a := names[0:2]
    b := names[1:3]
    fmt.Println(a, b)
        
        // 改变切片会改变原数组
    b[0] = "XXX"
    fmt.Println(a, b)
    fmt.Println(names)
}
// [John Paul George Ringo]
// [John Paul] [Paul George]
// [John XXX] [XXX George]
// [John XXX George Ringo]
字面量切片

字面量切片和字面量数组区别在于字面量切片无需指定长度

package main

import "fmt"

func main() {
    q := []int{2, 3, 5, 7, 11, 13}
    fmt.Println(q)

    r := []bool{true, false, true, true, false, true}
    fmt.Println(r)

    s := []struct {
        i int
        b bool
    }{
        {2, true},
        {3, false},
        {5, true},
        {7, true},
        {11, false},
        {13, true},
    }
    fmt.Println(s)
}
// [2 3 5 7 11 13]
// [true false true true false true]
// [{2 true} {3 false} {5 true} {7 true} {11 false} {13 true}]

省略切片的上界或下界,默认是数组的上界或下界,如:a[0:10]
a[:10]
a[0:]
a[:]

package main

import "fmt"

func main() {
    s := []int{2, 3, 5, 7, 11, 13}

    s = s[1:4]
    fmt.Println(s)

    s = s[:2]
    fmt.Println(s)

    s = s[1:]
    fmt.Println(s)
}
// [3 5 7]
// [3 5]
// [5]
切片长度和容量

切片长度是切片中元素个数,可以通过len(s)获得,切片容量是数组大小,可以通过cap(s)获得

package main

import "fmt"

func main() {
    s := []int{2, 3, 5, 7, 11, 13}
    printSlice(s)

    // Slice the slice to give it zero length.
    s = s[:0]
    printSlice(s)

    // Extend its length.
    s = s[:4]
    printSlice(s)

    // Drop its first two values.
    s = s[2:]
    printSlice(s)
}

func printSlice(s []int) {
    fmt.Printf("len=%d cap=%d %vn", len(s), cap(s), s)
}
// len=6 cap=6 [2 3 5 7 11 13]
// len=0 cap=6 []
// len=4 cap=6 [2 3 5 7]
// len=2 cap=4 [5 7]
空切片(Nil slices)

没有长度、容量以及基础数组,等于nil

package main

import "fmt"

func main() {
    var s []int
    fmt.Println(s, len(s), cap(s))
    if s == nil {
        fmt.Println("nil!")
    }
}
// [] 0 0
// nil!
make

make函数构造基础数组以及切片。**a := make([]int, 5) **声明一个长度为5的全0数组,并返回它的切片。还可以传递第三个参数指定切片容量:
b := make([]int, 0, 5) // len(b)=0,
cap(b)=5
b = b[:cap(b)] // len(b)=5, cap(b)=5
b = b[1:] // len(b)=4, cap(b)=4

package main

import "fmt"

func main() {
    a := make([]int, 5)
    printSlice("a", a)

    b := make([]int, 0, 5)
    printSlice("b", b)

    c := b[:2]
    printSlice("c", c)

    d := c[2:5]
    printSlice("d", d)
}

func printSlice(s string, x []int) {
    fmt.Printf("%s len=%d cap=%d %vn",
        s, len(x), cap(x), x)
}
// a len=5 cap=5 [0 0 0 0 0]
// b len=0 cap=5 []
// c len=2 cap=5 [0 0]
// d len=3 cap=3 [0 0 0]
切片的切片

切片中可以是任何类型,包括切片

package main

import (
    "fmt"
    "strings"
)

func main() {
    // Create a tic-tac-toe board.
    board := [][]string{
        []string{"_", "_", "_"},
        []string{"_", "_", "_"},
        []string{"_", "_", "_"},
    }

    // The players take turns.
    board[0][0] = "X"
    board[2][2] = "O"
    board[1][2] = "X"
    board[1][0] = "O"
    board[0][2] = "X"

    for i := 0; i 
apend

func append(s []T, vs …T) []T用于向切片新增元素,返回的切片包含原切片和新增元素。如果超过切片最大容量,将产生一个新的基础数组,返回的切片指向新数组。切片容量变化和长度变化不是同步的,即有可能长度加1,而容量加2。阅读 Slices: usage and internals

package main

import "fmt"

func main() {
    var s []int
    printSlice(s)

    // append works on nil slices.
    s = append(s, 0)
    printSlice(s)

    // The slice grows as needed.
    s = append(s, 1)
    printSlice(s)

    // We can add more than one element at a time.
    s = append(s, 2, 3, 4)
    printSlice(s)
}

func printSlice(s []int) {
    fmt.Printf("len=%d cap=%d %vn", len(s), cap(s), s)
}
// len=0 cap=0 []
// len=1 cap=2 [0]
// len=2 cap=2 [0 1]
// len=5 cap=8 [0 1 2 3 4]

Range

range用于for循环遍历slicemap,每次迭代返回两个值,第一个是下标,第二个是值

package main

import "fmt"

var pow = []int{1, 2, 4, 8, 16, 32, 64, 128}

func main() {
    for i, v := range pow {
        fmt.Printf("2**%d = %dn", i, v)
    }
}
// 2**0 = 1
// 2**1 = 2
// 2**2 = 4
// 2**3 = 8
// 2**4 = 16
// 2**5 = 32
// 2**6 = 64
// 2**7 = 128

如果只需要index或者value,只需下面这样写:
for i, _ := range pow
for _, value := range pow
只要下标还可以这么写:
for i := range pow

package main

import "fmt"

func main() {
    pow := make([]int, 10)
    for i := range pow {
        pow[i] = 1 

Map

map是键值对,空mapnilmake函数可以产生一个指定类型的mapvar m map[string]int声明一个名为mmap,键的类型是string,值的类型为int

package main

import "fmt"

type Vertex struct {
    Lat, Long float64
}

var m map[string]Vertex

func main() {
    m = make(map[string]Vertex)
    m["Bell Labs"] = Vertex{
        40.68433, -74.39967,
    }
    fmt.Println(m["Bell Labs"])
}
// {40.68433 -74.39967}
字面量map

字面量map类似字面量struct,不同在于map需要制定键

package main

import "fmt"

type Vertex struct {
    Lat, Long float64
}

var m = map[string]Vertex{
    "Bell Labs": Vertex{
        40.68433, -74.39967,
    },
    "Google": Vertex{
        37.42202, -122.08408,
    },
}

func main() {
    fmt.Println(m)
}
// map[Bell Labs:{40.68433 -74.39967} Google:{37.42202 -122.08408}]

字面量中的类型可以省略

package main

import "fmt"

type Vertex struct {
    Lat, Long float64
}

var m = map[string]Vertex{
        // 省略Vertex
    "Bell Labs": {40.68433, -74.39967},
    "Google":    {37.42202, -122.08408},
}

func main() {
    fmt.Println(m)
}
// map[Bell Labs:{40.68433 -74.39967} Google:{37.42202 -122.08408}]
改变map

插入或更新:
m[key] = elem
获取元素:
elem = m[key]
删除元素:
delete(m, key)
测试键是否存在:
elem, ok = m[key]
如果键存在,oktrue,否则为false
如果键不存在,elem为对应类型的zero
注意: 如果elem和ok没有声明,可以用下面形式:
elem, ok := m[key]

package main

import "fmt"

func main() {
    m := make(map[string]int)

    m["Answer"] = 42
    fmt.Println("The value:", m["Answer"])

    m["Answer"] = 48
    fmt.Println("The value:", m["Answer"])

    delete(m, "Answer")
    fmt.Println("The value:", m["Answer"])

    v, ok := m["Answer"]
    fmt.Println("The value:", v, "Present?", ok)
}
// The value: 42
// The value: 48
// The value: 0
// The value: 0 Present? false

函数类型Function values

函数也是一种类型,可以当做参数传递,也可以作为返回值

package main

import (
    "fmt"
    "math"
)

func compute(fn func(float64, float64) float64) float64 {
    return fn(3, 4)
}

func main() {
    hypot := func(x, y float64) float64 {
        return math.Sqrt(x*x + y*y)
    }
    fmt.Println(hypot(5, 12))

    fmt.Println(compute(hypot))
    fmt.Println(compute(math.Pow))
}
// 13
// 5
// 81

函数闭包

函数闭包指的是函数可以使用函数体之外的变量

package main

import "fmt"

func adder() func(int) int {
    sum := 0
    return func(x int) int {
        sum += x
        return sum
    }
}

func main() {
    pos, neg := adder(), adder()
    for i := 0; i 

文章来源于互联网,如有雷同请联系站长删除:Go基础

发表评论