我的第一个go app

奔跑的小蚂蚁 · · 1875 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

一、安装

1.下载和解压缩


# wget https://storage.googleapis.com/golang/go1.7.1.linux-amd64.tar.gz
# tar -C /usr/local -xzf go1.7.1.linux-amd64.tar.gz

2、添加环境变量

2.1 Add /usr/local/go/bin to the PATH environment variable

在控制台临时设置变量

# export GOROOT=/usr/local/go
# export PATH=$PATH:$GOROOT/bin

在配置文件中 vim /etc/profile 永久设置变量,具体方法问百度。

3、测试环境

# mkdir -p $HOME/go/workspace
# export GOPATH=$HOME/go/workspace
# mkdir $GOPATH/src/hello
# echo "" > $GOPATH/src/hello/hello.go  #新增go文件

在hello.go里面的内容

package main

import "fmt"

func main() {
    fmt.Printf("hello, world\n")
}

使用go tool 编译该项目

# go install hello
# $GOPATH/bin/hello
hello, world

二、go 语法学习

基本类型

bool

string

int  int8  int16  int32  int64
uint uint8 uint16 uint32 uint64 uintptr

byte // uint8 的别名

rune // int32 的别名
     // 代表一个Unicode码

float32 float64

complex64 complex128

这个例子演示了具有不同类型的变量。 同时与导入语句一样,变量的定义“打包”在一个语法块中。

intuintuintptr 类型在32位的系统上一般是32位,而在64位系统上是64位。当你需要使用一个整数类型时,你应该首选 int,仅当有特别的理由才使用定长整数类型或者无符号整数类型。

1、导入包:

1)包使用“”标示  2)包路径/

单独导入

​import "fmt"
import "math/rand"

组合导入 1、使用括号组织包 2、,3、包之间换行 4、

import (
	"fmt"
	"math/rand"
)

2、导出名

只有首字母大写可以被导出

Func Foo()
{
}
Func FOO()
{
}
Func foo()
{
}

Foo 和FOO可以被导出,foo 首字母小写无法导出。

3、函数

3.1 注意类型在变量名 之后 。

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

3.2 当两个或多个连续的函数命名参数是同一类型,则除了最后一个类型之外,其他都可以省略

func(x, y, z int ) int {
    return (x + y + z);
}

3.3 可以返回任何数量的返回值

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)
}

3.4 命名返回值 下面代码命名了 x,y int

func split(sum int)(x, y int) {
    x = sum * 4 /9
    y = sum - x
    return
}

4 var 定义变量列表

var 语句定义了一个变量的列表;跟函数的参数列表一样,类型在后面。

var c, python, java bool
var (
	ToBe   bool       = false
	MaxInt uint64     = 1<<64 - 1
	z      complex128 = cmplx.Sqrt(-5 + 12i)
)

5、初始化变量

定义变量可以包含初始化值,每个变量对应一个值

var a , b , c string = "hello1","hello2","hello3"

如果初始化变量值是表达式,可以忽略变量类型;变量类型从表达式结果中获得

var a , b , c  = "hello1","hello2","hello3"

6、短声明变量 :=

该用法不可以使用在函数外面。在函数中,简洁赋值语句在类型明确的地方,可以用于替换 var

a , b , c := "hello11","hello22","hello33"

7、变量在定义时没有明确初始化,会默认为零值

数值为0,bool 为 false,string 为 ""(空字符串)

8、类型转换

表达式 T(v),将值 v 转换为类型T ,不通类型转换必须显式转换。

9、常量

const Pi = 3.14

10、for 循环

10.1for 循环并不需要使用括号括起来:初始化语句;循环条件表达式;后置语句;但是循环体必须使用{}括起来。

    sum := 0;
    for i := 0; i < 10; i++  {
        sum += i
    }
    fmt.Println(sum)

10.2 for初始化语句和后置语句是可选的

sum := 1
for ; sum < 1000; {
    sum += sum
}

11 for 是go 的while

sum := 1
for sum < 1000 {
    sum += sum
}

12 死循环

忽略了循环条件,循环就不会结束,因此可以用更简洁的语句表达死循环

for {}

13 if 的便捷表达式

跟 for 一样, if 语句可以在条件之前执行一个简单语句。该语句定义的变量作用域仅在if /else 范围内

if v := math.Pow(3,3); v < 20 {
    fmt.Println(v)
} else {
    fmt.Println(v)
}

14 switch 的便捷表达式

跟 for 一样, switch 语句可以在条件之前执行一个简单语句。该语句定义的变量作用域仅在switch 范围内

switch os := runtime.GOOS; os {
	case "darwin":
		fmt.Println("OS X.")
	case "linux":
		fmt.Println("Linux.")
	default:
		// freebsd, openbsd,
		// plan9, windows...
		fmt.Printf("%s.", os)
}

switch 分支不需要break,除非以 fallthrough 语句结束,否则分支会自动终止

15 defer

defer 语句会延迟函数的执行直到上层函数返回。

1) 延迟调用的参数会立刻生成,但是在上层函数返回前函数都不会被调用

2)延迟的函数调用被压入一个栈中。当函数返回时, 会按照后进先出的顺序调用被延迟的函数调用。

func main() {
        fmt.Println("start")
        for i := 0 ; i < 10; i++ {
           fmt.Println(i)
        }
        fmt.Println("done")
}
#./test
start
done
9
8
7
6
5
4
3
2
1
0

16、指针

go没有指针运行符

x, y := 12,13
p := &x
fmt.Println(*p)  #即将打印12
p = &y
*p = 21
fmt.Println(y)  #即将打印21

 

17、结构struct
1)声明:

type struName struct{
     var1 T1
     var2 T2
}

2)调用构造函数 struName{var1,var2....}

3)访问方式 .成员变量

type Vertex struct {
    x int
    y int
}
func main() {
    stru := Vertex{1 ,2}
    fm.Println(stru)            #输出:{1,2}
    fmt.Println(stru.x, stru.y) #输出:1 2
    p := &stru 
    fm.Println(*p)              #输出:{1,2}
    fmt.Println(p.x, p.y)       #输出:1 2
}

18、数组

var a [2]string
a[0] = "hello"
a[1] = "world"

19、slice

19.1 一个slice 会指向一个有序列的值,并且包含长度信息。形如: []T

ss := [][]string{
        []string{"hello0","world0"},
        []string{"hello1","world1"},
        []string{"hello2","world2"},
    }
    for i := 0; i< len(ss); i++ {
         fmt.Println(ss[i][0],ss[i][1])
    }

结果

#./test
hello0 world0
hello1 world1
hello2 world2

19.2 对slice切片

slice可以重新切片,创建一个新的slice值指向相同的数组。形如:s[lo:hi],表示从lo到hi-1的slice元素,含前端,不包含后端。s[lo, lo] 是空值,s[lo,lo+1]有1个元素

19.3 make 函数

make:分配一个全是零值的数组并且返回一个slice指向这个数组。形如:s := make([]string , 3)

注意slice有长度和容量 ,长度:len(s),容量:cap(s)

s := make([]string, 0 , 5)

len(s) :返回0

cap(s) ::返回5

19.4 slice的零值为nil

20 range

for 循环的range 格式可以对slice 或者map 进行迭代,当使用for循环遍历一个slice时,每次迭代range 将返回两个值:下标和值

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

func main() {
	for i, v := range pow {
		fmt.Printf("2**%d = %d\n", i, v)
	}
}

输出

# ./test
2**0 = 1
2**1 = 2
2**2 = 4
2**3 = 8
2**4 = 16
2**5 = 32
2**6 = 64
2**7 = 128

for range 的简略写法

func main() {
	pow := make([]int, 10)
        //只需要索引,去掉", value"
	for i := range pow {
		pow[i] = 1 << uint(i)
	}
        //只需要治,赋值给_忽略序号
	for _, value := range pow {
		fmt.Printf("%d\n", value)
	}
}

21 map--映射值到键

map在使用之前必须使用make来创建,否则为空map,值为nil,不能对其赋值

var m map[string]int
func main() {
    m = make(map[string]int)
    m["Bell"] = 12   //插入一个元素
    fmt.Println("Bell' age is %d", m["Bell"])  //获取一个元素
    m["Bell"] = 15   //修改一个元素
    m2 := map[string]int {
        "Alice":13,
    }
    elem , ok  := m2["Alice"]   //使用双赋值检测某个键存在,存在 ok为true,否则为false,并且elem是map元素类型的零值
    if ok {
      fmt.Println("Alice' age is %d", elem)
    }
    
    delete(m2, "Alice")  //删除一个元素
    elem, ok = m2["Alice"]
    if ok {
      fmt.Println("Alice' age is %d", elem)
    }
    

22 函数值--函数作为函数参数传递或者作为返回值

func compute(fn func(float64, float64) float64) float64 {
        return fn(float64(3), float64(4))  //调用参数 -fn
}
func add(x ,y float64) float64 {
    return x + y
}

func getfunc() func(float64, float64) float64 {

    hypot := func(x, y float64) float64 {
                return math.Sqrt(x*x + y*y)
    }
    return hypot  //返回函数
}

func main() {

        hypot := getfunc()
        fmt.Println(compute(hypot))     //hypot是参数
        fmt.Println(compute(math.Pow)) //math.Pow是参数
        fmt.Println(compute(add)) // add 是参数

}

23 函数闭包

Go函数可以是一个闭包。

func adder() func(int) int {
	sum := 0  
        //fun 是一个闭包,它引用了函数体之外(本身fn之外)的变量
        fn := func(x int) int {
		sum += x
		return sum
	}
	return fn 
}

func main() {
	pos, neg := adder(), adder() //pos.neg是一个闭包,有各自的绑定的sum变量
	for i := 0; i < 10; i++ {
		fmt.Println(
			pos(i),
			neg(-2*i),
		)
	}
}

 

24 在结构类型上定义方法

type Vertex struct {
    X, Y float64
}
//方法 Sqrt被 v接收,v出现在 func 关键字和 方法Sqrt名 之间
func (v *Vertex) Sqrt() float64 {
    return math.Sqrt(v.X * v.X + v.Y*v.Y)

}

func main() {
   p := &Vertex{3, 4}
   fmt.Println(p.Sqrt())
}

其实,可以在保内的任何类型定义任意方法,基础类型和其他包的类型除外。

type myfloat float64
//如果只读,使用值作为接收者,函数内部是调用者的副本
func (f myfloat) Abs() float64 {
    if f < 0 {
        return float64(-f)
    }
    return float64(f)
}
//如果是可写,使用指针作为接收者
func (f *myfloat) Abs2() float64 {
    if *f < 0 {
        *f = -*f
        return float64(-*f)
    }
    return float64(*f)
}

func main() {
   fmt.Println((myfloat(-5.5)).Abs() )
   f := myfloat(-5.5)
   (&f).Abs2()
}

25 接口

type myfloat float64
type Iface interface {
    Abs() float64
}

func (f myfloat) Abs() float64 {
    if f < 0 {
        return -float64(f)
    }
    return float64(f)
}
func main() {
   var a Iface
   f := myfloat(-5.5)
   a = f;
   fmt.Println(a.Abs())
}

26 Web服务器 包http 通过实现了http.Handler的接口来响应HTTP请求

type Hello struct{}

func (h Hello) ServeHTTP(
	w http.ResponseWriter,
	r *http.Request) {
	fmt.Fprint(w, "Hello!")
}

func main() {
	var h Hello
	err := http.ListenAndServe("localhost:4000", h)
	if err != nil {
		log.Fatal(err)
	}
}

27 goroutine

goroute 是由go 运行时环境管理的轻量级线程 。语法:go f(x, y, x)


有疑问加站长微信联系(非本文作者)

本文来自:开源中国博客

感谢作者:奔跑的小蚂蚁

查看原文:我的第一个go app

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

1875 次点击  
加入收藏 微博
1 回复  |  直到 1999-12-31 16:00:00
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传