Go语言探险思考笔记(1)

最近接触对象存储,国际上鼎鼎有名的Amazon S3还有Google Cloud Service在国内由于防火墙还有机房过远的问题,并不能投入生产使用。国内有名的对象存储,大家众所周知的七牛云,后台就是Go语言实现的。对于第一个敢吃螃蟹的人,我一直很佩服。于是抱着憧憬的心态走进Go语言的大门。

首先,接触一门语言,就从最啰嗦但是最不能缺少的基础语法和顺序变成开始。对于接触这些,我一般是从搭建好自己的编译构建环境开始,首先下载Go语言SDK,国内下载地址:http://golangtc.com/download

我这里用的是最新的1.7.2,如果你要用IDEA 的go plugin进行编程,则需要用1.4.2,不能用高版本的。之后,下载LiteIDE,进行编码:http://www.golangtc.com/download/liteide

我们打开LiteIDE,新建一个非GOPATH目录下的示例项目(我们这里吐槽下LiteIDE,他并不是一个很严谨,很好用,很完整的IDE,对于习惯了IDEA的懒人程序员,可能不太习惯。但是,回归原始也是很有好处的),命名为Gotest。

项目会自动生成目录和代码。我们只保留main.go就可以。Go语言有他智能的一面,首先摆上两个原则:

  1. 对于每个项目,都需要配置GOPATH。为了能构建这个项目,需要把项目根目录加入到GOPATH,否则找不到这个项目内部的package。
  2. Go根据项目目录结构自动构建,这里基本原则就是:需要一个main入口,自己新建应用或者一个代码包都是在src目录下新建一个文件夹,文件夹名称一般是代码包名称,当然也允许多级目录,例如在src下面新建了目录$GOPATH/src/github.com/hashZhang/test那么这个包路径就是“github.com/hashZhang/test”,包名称是最后一个目录test

变量定义

Go语言兼顾了自由性和严谨性:首先,对于变量的定义,我们有三种方式,很自由。接着,没用的元素在编译时就不会通过。例如:没用的包引入,没用的变量定义,这些在编译时就会报错。

下面我们写一个小程序:

我们在项目根目录新建pkg和src两个文件夹,src目录存放我们的源代码,pkg是给go编译器用的,会生成编译好的文件,其实就是编译好的库文件。根目录保留main.go

在src目录下新建fundamental文件夹,在fundamental文件夹新建variables.go。

编写源码(这里先提出一点Go语言不用分号分割,回车就可以):

package fundamental

import "fmt" //包如果没用,则会在编译时报错,这里用了标准输出函数

func Initialization() { //go,模块中要导出的函数,必须首字母大写。
    var var1 int //变量如果没有用过,也会在编译时报错,初始化为默认值0
    fmt.Println("var1:", var1)
    var var2 string //注意小写s,初始化为默认值""
    fmt.Println("var2:", var2)
    var var3 [10]int //数组,初始化为默认值[0 0 0 0 0 0 0 0 0 0]
    fmt.Println("var3:", var3)
    var var4 []int //动态数组,数组切片,初始化为默认值[]
    fmt.Println("var4:", var4)
    var var5 struct { //相当于C语言中的结构体,,初始化为默认值{0 ""}
        f int
        j string
    }
    fmt.Println("var5:", var5)
    var var6 *int //指针,初始化为默认值<nil>
    fmt.Println("var6:", var6)
    var var7 map[string]int //Key为string,value为int,初始化为默认值map[]
    fmt.Println("var7:", var7)
    var var8 func(a int) int //定义为一个function,规定输入输出,初始化为默认值<nil>
    fmt.Println("var8:", var8)
    var var9 = 10 //根据初始值自动判断类型
    fmt.Println("var9:", var9)
    var10 := 11 //第三种初始化
    fmt.Println("var10:", var10)
}

func SwapDisplay1() { //常规思路的交换,利用a+b-a和a+b-b来达到交换的目的
    var (
        a = 19
        b = -7
    )
    fmt.Println("Before swap:\n", "a:", a, ",b:", b)
    a = a + b
    b = a - b
    a = a - b
    fmt.Println("After swap:\n", "a:", a, ",b:", b)
}

func SwapDisplay2() { //Go语言交换,因为函数可以返回多个值,而且支持类似于a,b=b,a的多重赋值语法
    var (
        a = 19
        b = -7
    )
    fmt.Println("Before swap:\n", "a:", a, ",b:", b)
    a, b = swap(a, b)
    fmt.Println("After swap:\n", "a:", a, ",b:", b)
}

func swap(a int, b int) (int, int) { //go,对于模块中不需要导出的函数,首字母不要大写。
    return b, a
}

我们总结下:

1 变量有3种定义或初始化方式:

    var var1 int
    var var9 = 10
    var10 := 11 

2.变量类型非常自由,有C语言的结构体,也有像Javascript那样的函数类型变量。

3.变量赋值很自由,对于其他语言,变量交换有两种方式:一种是中间变量,另一种是利用a+b-a和a+b-b来达到交换的目的。Go语言支持多重赋值,i,j=j,i

func SwapDisplay1() { //常规思路的交换,利用a+b-a和a+b-b来达到交换的目的
    var (
        a = 19
        b = -7
    )
    fmt.Println("Before swap:\n", "a:", a, ",b:", b)
    a = a + b
    b = a - b
    a = a - b
    fmt.Println("After swap:\n", "a:", a, ",b:", b)
}

func SwapDisplay2() { //Go语言交换,因为函数可以返回多个值,而且支持类似于a,b=b,a的多重赋值语法
    var (
        a = 19
        b = -7
    )
    fmt.Println("Before swap:\n", "a:", a, ",b:", b)
    a, b = swap(a, b)
    fmt.Println("After swap:\n", "a:", a, ",b:", b)
}

4.以上的多重赋值,也来源于Go语言的函数可以返回多个值。

func swap(a int, b int) (int, int) { //go,对于模块中不需要导出的函数,首字母不要大写。
    return b, a
}

5.Go语言的var关键字和import关键字都支持括号内多个定义,例如:

    var(
        v1 int
        v2 string
    )

6.对于包外部可见的function,function名称开头必须大写(就是说,利用开头字母大写的方法定义包外部可见可以调用的function)

这里我们可以调用的是Initialization(),SwapDisplay1(),SwapDisplay2()方法,而swap方法不可以。

在main.go中编写:

// Gotest project main.go
package main

import (
    "fmt"
    "fundamental"
)

func main() {
    fundamental.Initialization() //go,模块中要导出的函数,必须首字母大写。
    fmt.Println("Hello World!")
    fundamental.SwapDisplay1() //go,模块中要导出的函数,必须首字母大写
    fundamental.SwapDisplay2() //go,模块中要导出的函数,必须首字母大写
}

编译运行:

var1: 0
var2:
var3: [0 0 0 0 0 0 0 0 0 0]
var4: []
var5: {0 }
var6: <nil>
var7: map[]
var8: <nil>
var9: 10
var10: 11
Hello World!
Before swap:
 a: 19 ,b: -7
After swap:
 a: -7 ,b: 19
Before swap:
 a: 19 ,b: -7
After swap:
 a: -7 ,b: 19

生成的文件:

如我们之前所说,在pkg目录下自动生成了.a库文件。在根目录下还生成了和项目名称一样的exe可执行文件。

常量定义

Go语言的字面量是无类型的

在fundamental文件夹下新建constants.go:

package fundamental

import "fmt" //包如果没用,则会在编译时报错,这里用了标准输出函数

func ConstDefinition() {
    const PI_f32 float32 = 3.141592654 //不用像其他语言那样指定是float还是double,末尾加上f,字面量常量都是无类型的,这里实际上是3.1415927
    const PI_f64 float64 = 3.141592654 //不用像其他语言那样指定是float还是double,末尾加上f,字面量常量都是无类型的,这里实际上是3.141592654
    fmt.Println("PI_f32:", PI_f32)
    fmt.Println("PI_f64:", PI_f64)
    const PI = 3.141592654 //不指定类型也可以,会自动匹配成能容纳这个变量的浮点类型常量
    fmt.Println("PI:", PI)
    const (
        a, b, c = "a", 1, 3.0
        d       = "asd"
    )
    fmt.Println("a:", a, ",b:", b, ",c:", c, ",d:", d)

    const ( //三种预定义常量,iota会在下一个const之前递增,但是,必须在不同赋值语句才能递增。
        e1, e2 = true, false
        e3     = iota //0
        e4     = iota //1
    )
    fmt.Println("e1:", e1, ",e2:", e2, ",e3:", e3, ",e4:", e4)

    const ( //iota必须在不同赋值语句才能递增。
        f1, f2 = iota, iota //0,0
        f3, f4 = iota, iota //1,1
    )
    fmt.Println("f1:", f1, ",f2:", f2, ",f3:", f3, ",f4:", f4)
}

总结如下几点:

1.Go语言的字面量是无类型的,对于浮点型,不用像其他语言那样指定是float还是double,末尾加上f,字面量常量都是无类型的

const PI_f32 float32 = 3.141592654 //不用像其他语言那样指定是float还是double,末尾加上f,字面量常量都是无类型的,这里实际上是3.1415927
const PI_f64 float64 = 3.141592654 //不用像其他语言那样指定是float还是double,末尾加上f,字面量常量都是无类型的,这里实际上是3.141592654

2.在定义常量时,不指定类型也可以,会自动匹配成能容纳这个变量的浮点类型常量

3.三种预定义常量(true,false,iota),iota会在下一个const之前递增,但是,必须在不同赋值语句才能递增。

    const ( //三种预定义常量,iota会在下一个const之前递增,但是,必须在不同赋值语句才能递增。
        e1, e2 = true, false
        e3     = iota //0
        e4     = iota //1
    )
    const ( //iota必须在不同赋值语句才能递增。
        f1, f2 = iota, iota //0,0
        f3, f4 = iota, iota //1,1
    )

类型

布尔类型

func TestBool() {
    var v1 bool //初始化为bool类型,默认为false
    fmt.Println("v1:", v1)
    v1 = true
    fmt.Println("v1:", v1)
    v2 := (1 >= 0 && 2 <= 3) //也可以表达式赋值,需要加上括号
    fmt.Println("v2:", v2)
}

总结:

1. 布尔类型初始化,默认为false

2. 布尔类型不支持其它赋值或者强制转换,例如赋值为1

整型

func TestInt() {
    var a int8
    a = 6 //int类型可以指定长度
    fmt.Println("a:", a)
    var b int32
    b = 7.0000   //这个本来小数点全为0的也可以赋值给int类型,但是7.0001就不行了
    b = int32(a) //同时,也不能将a赋值给b,因为不同类型,同时也不能互相比较
    fmt.Println("b:", b)
    fmt.Println("b > 0.00:", b > 0.00) //不同类型也不能互相比较
    fmt.Println("^b:", ^b)             //其他运算符都和其他语言一样,除了非运算,非运算符为^
}

总结:

1. 不同类型的整型不可以互相赋值,或者互相比较

2. 字面量无类型,可以复制,可以比较,但是必须为整型

b = 7.0000                         //这个本来小数点全为0的也可以赋值给int类型,但是7.0001就不行了

3. 其他运算符都和其他语言一样,除了非运算,非运算符为^

4. 一般都用int,uint来编程

浮点型

func TestFloat() {
    var f1 float32
    fmt.Println("f1:", f1)
    f2 := 12.0 //不能f2 = f1 ,f2为float64
    f3 := 11.9091
    fmt.Println("isEqual(f2, f3, 1)", isEqual(f2, f3, 1))
}
func isEqual(f1, f2, p float64) bool {//浮点数不能直接用==判断相等,只能用精度比较
    return math.Abs(f1-f2) < p
}

总结:

1.不同类型的浮点型不可以互相赋值,或者互相比较

2.浮点数不能直接用==判断相等,只能用精度比较

字符串

func TestString() {
    str := "Hello World! by 张哈希"
    fmt.Println("str:", str)
    fmt.Println("len(str):", str)//利用内置函数len获取长度
    for i := 0; i < len(str); i++ {//遍历
        fmt.Println(i, str[i])
    }
    for i, ch := range str {//以Unicode方式遍历
        fmt.Println(i, ch)
    }
}

输出:

str: Hello World! by 张哈希
len(str): Hello World! by 张哈希
0 72
1 101
2 108
3 108
4 111
5 32
6 87
7 111
8 114
9 108
10 100
11 33
12 32
13 98
14 121
15 32
16 229
17 188
18 160
19 229
20 147
21 136
22 229
23 184
24 140

0 72
1 101
2 108
3 108
4 111
5 32
6 87
7 111
8 114
9 108
10 100
11 33
12 32
13 98
14 121
15 32
16 24352
19 21704
22 24076
时间: 2024-10-24 00:52:26

Go语言探险思考笔记(1)的相关文章

Go语言探险思考笔记

最近接触对象存储,国际上鼎鼎有名的Amazon S3还有Google Cloud Service在国内由于防火墙还有机房过远的问题,并不能投入生产使用.国内有名的对象存储,大家众所周知的七牛云,后台就是Go语言实现的.对于第一个敢吃螃蟹的人,我一直很佩服.于是抱着憧憬的心态走进Go语言的大门. 首先,接触一门语言,就从最啰嗦但是最不能缺少的基础语法和顺序变成开始.对于接触这些,我一般是从搭建好自己的编译构建环境开始,首先下载Go语言SDK,国内下载地址:我这里用的是最新的1.7.2,如果你要用I

[BetterExplained]书写是为了更好的思考笔记

书写的好处有以下几点: 书写是对思维的备忘: 书写是对思维的缓存: 书写是与自己的对话: 书写时与别人的交流: 有时候,语言自己也会思考. 在开始书写你的想法之前,我知道很多人不书写的原因是因为觉得没有什么可写的,其实这是一个怪圈,你越是不开始书写,总是拿有限的思维缓存去默想一个问题,就越是没有内容可以写,如果你逼着自己将一些不成熟的想法写下来,看着自己写的内容,试着进一步拓展它们,就有可能在理性的道路上走得很远,很远. 原文链接:[BetterExplained]书写是为了更好的思考笔记

初探swift语言的学习笔记十一(performSelector)

作者:fengsh998 原文地址:http://blog.csdn.net/fengsh998/article/details/35842441 转载请注明出处 如果觉得文章对你有所帮助,请通过留言或关注微信公众帐号fengsh998来支持我,谢谢! 在OC中使用好好的performSelector,但不知为什么在swift有意的被拿掉了.更有甚者连IMP, objc_msgSend也不能用了.虽然想不通为什么,但应该有他的道理.就不纠结了. 大家可能在OC中使用得更多的就是延时处理,及后台处

初探swift语言的学习笔记十(block)

作者:fengsh998 原文地址:http://blog.csdn.net/fengsh998/article/details/35783341 转载请注明出处 如果觉得文章对你有所帮助,请通过留言或关注微信公众帐号fengsh998来支持我,谢谢! 在前面一些学习中,原本把闭包给理解成了block尽管有很多相似之处,但block还是有他自己的独特之外.近日,在写oc/swift混合编码时,有时候需要swift回调oc,oc回调swift . 因此我把swift中的 block 常见的声明和写

C语言、数据结构笔记集合

链表中的“p->next” p->next到底是指p的下一个节点还是p的指针域呢?p是一个指针,那么p->next也应该是一个指针,即p->next应该是一个地址,因此p->next其实是p指向的节点的指针域(next域),所以p->next还是属于当前节点的,只不过它是下一个节点的地址罢了.所以如果函数返回“p->next”,那么函数的类型应为指针函数. 如何让VS2013进行C编程的时候使用基本库函数不会得到警告 把VS项目创建中的安全周期检查关闭就可以任意使

《你必须知道的495个C语言问题》笔记--库函数

怎样把数字转为字符串(与atoi相反)?有itoa函数吗? 用sprintf就可以了: sprintf(string, "%d", number); 同理,也可以同sprintf把long型或浮点型转换成字符串(使用%ld或%f),也就是说,可以把sprintf看成是atol或者atof的 反函数. 怎样在日期上加n天?怎样取得两个日期的时间间隔? 第一个问题,mktime接受没有规范话的日期,所以可以用一个日期的struct tm结构,直接在tm_mday域上进行加减,然后 调用mk

《你必须知道的495个C语言问题》笔记--杂项

如何进行移位操作? 因为左移操作(<<)不会导致符号位出现缺位,不考虑符号位,低位补0即可.所以对于无符号和有符号数来说,均为逻辑左移. 右移操作(>>)会涉及到符号位出现缺位的问题,所以在有符号数的右移操作时要考虑符号位怎么补的问题.对于无符号数来说, 最左侧补0,即逻辑右移:对于有符号来说,最左侧补符号位,即符号右移. 实践: #include <stdio.h> int main(void) { unsigned rui; int ri; unsigned int

《你必须知道的495个C语言问题》笔记--标准输入输出

getchar的返回值 这样的代码有什么问题: char c; while((c = getchar()) != EOF).... getchar返回值变量必须是int型.因为EOF通常定义为-1,二十进制为255的字符会被符号扩展,和EOF比较时会相等,从而 过早第结束输入. feof函数的使用 为什么这些代码最后一行复制了两遍? #include <stdio.h> #include <unistd.h> #include <fcntl.h> #define MAX

《你必须知道的495个C语言问题》笔记--数组和指针

一.如何动态分配多维数组? 1.分配一个指针数组,然后把每个指针初始化为动态分配的行 代码如下: int **array = (int **)malloc(ROW * sizeof(int*)); int i = 0; for(i=0; i<ROW; i++){ array[i] = (int *)malloc(COL * sizeof(int)); } 2.让数组的内容连续,但在后来重新分配行. 代码如下: int **array = (int**)malloc(ROW * sizeof(in