分享
  1. 首页
  2. 文章

我的第一个go app

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

一、安装

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

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

int,uintuintptr 类型在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

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

用户登录

没有账号?注册
(追記) (追記ここまで)

今日阅读排行

    加载中
(追記) (追記ここまで)

一周阅读排行

    加载中

关注我

  • 扫码关注领全套学习资料 关注微信公众号
  • 加入 QQ 群:
    • 192706294(已满)
    • 731990104(已满)
    • 798786647(已满)
    • 729884609(已满)
    • 977810755(已满)
    • 815126783(已满)
    • 812540095(已满)
    • 1006366459(已满)
    • 692541889

  • 关注微信公众号
  • 加入微信群:liuxiaoyan-s,备注入群
  • 也欢迎加入知识星球 Go粉丝们(免费)

给该专栏投稿 写篇新文章

每篇文章有总共有 5 次投稿机会

收入到我管理的专栏 新建专栏