[Go]初学Go语言(一)

本文介绍了Go语言如何通过协程实现并行处理,提升系统性能,并概述了Go语言的简洁语法,包括字符串连接、格式化输出、变量和常量声明。文中还特别提到空白标识符、fmt.Println的使用以及iota在常量枚举中的作用。
摘要由CSDN通过智能技术生成

Go语言通过协程可以方便的实现并行处理,达到处理效率的最大化 ,提升系统的吞吐能力。

GO语言使用起来简单、代码描述效率高、编码规范统一、上手快。 通过少量的代码,即可实现框架的标准化,能快速的构建各种通用组件和公共类库,进一步提升开发效率,实现特定场景下的功能量产。

上面是Go语言的一些优点,简单的摘抄了点。下面是偏笔记的内容,多数笔记来自菜鸟教程,一些比较通用的方法比如说用等我就没有记录,记录的都是一些个人认为比较特殊的点。因为第一次尝试写这种入门的文章,文笔会很差,大家体谅一下,拜托!!!如果有错误或可以优化的地方,希望大家积极提出我会改正!!!

继续开个小坑,到时候开个目录,慢慢更新吧(


目录

1.下载安装

2.基础格式部分

3.数字类型

4.基础语法

①.Go语言的字符串连接可以通过+实现

②.格式化字符串

③.空白标识符在函数返回值时的使用

④.可以通过不导包完成打印的操作

5.申明变量

①.用var来申明

②.使用 := 赋值操作符

③.值类型和引用类型

6.申明常量

①.常量的申明

②.常量组的特性

③.特殊的常量 iota


1.下载安装

下载地址:All releases - The Go Programming Language

 

Windows 下可以使用 .msi 后缀(在下载列表中可以找到该文件,如go1.4.2.windows-amd64.msi)的安装包来安装。

默认情况下 .msi 文件会安装在 c:\Go 目录下。可以将 c:\Go\bin 目录添加到 Path 环境变量中。添加后你需要重启命令窗口才能生效。我们可以验证一下是否安装成功。

package main

import "fmt" 

func main(){
    fmt.println("Hello World!")
}

以下图的路径来进行测试。

如图则成功啦!


2.基础格式部分

我们来看一下Go语言的格式部分

  1. 第一行代码 package main 定义了包名。你必须在源文件中非注释的第一行指明这个文件属于哪个包,如:package main。package main表示一个可独立执行的程序,每个 Go 应用程序都包含一个名为 main 的包。
  2. 下一行 import "fmt" 告诉 Go 编译器这个程序需要使用 fmt 包(的函数,或其他元素),fmt 包实现了格式化 IO(输入/输出)的函数。
  3. 下一行 func main() 是程序开始执行的函数。main 函数是每一个可执行程序所必须包含的,一般来说都是在启动后第一个执行的函数(如果有 init() 函数则会先执行该函数)。
  4. 下一行 /*...*/ 是注释,在程序执行时将被忽略。单行注释是最常见的注释形式,你可以在任何地方使用以 // 开头的单行注释。多行注释也叫块注释,均已以 /* 开头,并以 */ 结尾,且不可以嵌套使用,多行注释一般用于包的文档描述或注释成块的代码片段。
  5. 下一行 fmt.Println(...) 可以将字符串输出到控制台,并在最后自动增加换行字符 \n。
    使用 fmt.Print("hello, world\n") 可以得到相同的结果。
    Print 和 Println 这两个函数也支持使用变量,如:fmt.Println(arr)。如果没有特别指定,它们会以默认的打印格式将变量 arr 输出到控制台。
  6. 当标识符(包括常量、变量、类型、函数名、结构字段等等)以一个大写字母开头,如:Group1,那么使用这种形式的标识符的对象就可以被外部包的代码所使用(客户端程序需要先导入这个包),这被称为导出(像面向对象语言中的 public);标识符如果以小写字母开头,则对包外是不可见的,但是他们在整个包的内部是可见并且可用的(像面向对象语言中的 protected )。

行分隔符

在 Go 程序中,一行代表一个语句结束。每个语句不需要像 C 家族中的其它语言一样以分号 ; 结尾,因为这些工作都将由 Go 编译器自动完成。

如果打算将多个语句写在同一行,它们则必须使用 ; 人为区分,但在实际开发中并不鼓励这种做法。

附上一个笔记:

关于包,根据测试得出以下几点:

  •  文件名与包名没有直接关系,不一定要将文件名与包名定成同一个。
  •  文件夹名与包名没有直接关系,并非需要一致。
  •  同一个文件夹下的文件只能有一个包名,否则编译报错。

3.数字类型

①.数字类型

Go 也有基于架构的类型,例如:int、uint 和 uintptr。

序号

类型和描述

1

uint8

无符号 8 位整型 (0 到 255)

2

uint16

无符号 16 位整型 (0 到 65535)

3

uint32

无符号 32 位整型 (0 到 4294967295)

4

uint64

无符号 64 位整型 (0 到 18446744073709551615)

5

int8

有符号 8 位整型 (-128 到 127)

6

int16

有符号 16 位整型 (-32768 到 32767)

7

int32

有符号 32 位整型 (-2147483648 到 2147483647)

8

int64

有符号 64 位整型 (-9223372036854775808 到 9223372036854775807)

②.浮点型

序号

类型和描述

1

float32

IEEE-754 32位浮点型数

2

float64

IEEE-754 64位浮点型数

3

complex64

32 位实数和虚数

4

complex128

64 位实数和虚数

③.其他数字类型

以下列出了其他更多的数字类型:

序号

类型和描述

1

byte

类似 uint8

2

rune

类似 int32

3

uint

32 或 64 位

4

int

与 uint 一样大小

5

uintptr

无符号整型,用于存放一个指针


4.基础语法

①.Go语言的字符串连接可以通过+实现
package main

import "fmt"

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

但是Go语言中不能让不同类型的字节进行相加,包括打印的时候。

 

②.格式化字符串

Go 语言中使用 fmt.Sprintf 或 fmt.Printf 格式化字符串并赋值给新串:

  • Sprintf 根据格式化参数生成格式化的字符串并返回该字符串。
  • Printf 根据格式化参数生成格式化的字符串并写入标准输出。
func main(){
    var a = 123
    var b = "abc"
    var c = "a : %d,b : %s"
    fmt.Printf(c,a,b)
}

这一段效果等同于下面一段

func main(){
    var a = 123
    var b = "abc"
    var c = "a : %d,b : %s"
    var d = fmt.Sprintf(c,a,b)
    fmt.Print(d)
}

.空白标识符在函数返回值时的使用
package main

import "fmt"

func main() {
  _,numb,strs := numbers() //只获取函数返回值的后两个
  fmt.Println(numb,strs)
}

//一个可以返回多个值的函数
func numbers()(int,int,string){
  a , b , c := 1 , 2 , "str"
  return a,b,c
}

输出结果:

2 str

如果是fmt.Println(_,numb,strs)会出现报错

④.可以通过不导包完成打印的操作
package main

func main () {
    println(1)
}

由此我们可以知道,在包.方法的情况下,方法的首字母要大写,而直接使用方法的时候则需要小写。


5.申明变量

Go里面的申明变量有以下几种方式:

①.用var来申明

一般来说申明变量都是用var关键字。

eg: var identifier type

也可以同时申明多个变量,

eg: var identifier1,identifier2 type

如果我们不申明初始值的话,变量则会默认为零值 

 

由此我们可见,String类型的零值为"" ,int类型的零值为0,而布尔值的零值为false。

同样的,Go语言中也存在全局变量。全局变量是可以被申明后不去使用的。

在Go语言中,存在一个特性就是没有用到的局部变量不能申明

看下面这个例子:

不过一般申请全局变量都用以下这种形式:

package main

import "fmt"

// 这种因式分解关键字的写法一般用于声明全局变量
var (
    vname1 v_type1
    vname2 v_type2
)

func main() {

}

 同样的,Go有自动判断变量类型的功能,所以我们在申请变量的时候可以不用加变量类型的哦。

package main

import "fmt"

func main() {
    var a = "str"
    var b = 5
    var c = true

    fmt.Println(a)
    if c {
        fmt.Println(b)
    }
}

②.使用 := 赋值操作符

我们知道可以在变量的初始化时省略变量的类型而由系统自动推断,声明语句写上 var 关键字其实是显得有些多余了,因此我们可以将它们简写为 a := 50 或 b := false。

a 和 b 的类型(int 和 bool)将由编译器自动推断。

这是使用变量的首选形式,但是它只能被用在函数体内,而不可以用于全局变量的声明与赋值。使用操作符 := 可以高效地创建一个新的变量,称之为初始化声明。

如果在相同的代码块中,我们不可以再次对于相同名称的变量使用初始化声明,例如:a := 20 就是不被允许的,编译器会提示错误 no new variables on left side of :=,但是 a = 20 是可以的,因为这是给相同的变量赋予一个新的值。

同样的,因为不是全局变量,如果不去使用申明的变量我们依然会得到报错。

package main

import "fmt"

func main() {
    a := "str"
    b := 5
    c := true

    fmt.Println(a)
    if c {
        fmt.Println(b)
    }
}

结果如下:

Go语言中全局变量和局部变量名称可以相同,但是局部变量会被优先考虑。

③.值类型和引用类型

所有像 int、float、bool 和 string 这些基本类型都属于值类型,使用这些类型的变量直接指向存在内存中的值,当使用等号 = 将一个变量的值赋值给另一个变量时,如:j = i,实际上是在内存中将 i 的值进行了拷贝。我们用&i的方式可以打印出地址来观察

package main

import "fmt"

func main() {
    a := "str1"
    b := a

    fmt.Println("a:" + a)
    fmt.Println("b:" + b)

    fmt.Println(&a)
    fmt.Println(&b)

    a = "str2"
    fmt.Println("a:" + a)
    fmt.Println("b:" + b)

    fmt.Println(&a)
    fmt.Println(&b)
}

结果如下:

可以发现a,b的地址是不同的,所以当a改变的同时b是不会发生改变的。

这里就涉及到深拷贝和浅拷贝的概念,大家可以去看一下。这里截取部分概念。

Go语言讲解深拷贝与浅拷贝 - 简书 (jianshu.com)

深拷贝(Deep Copy):

拷贝的是数据本身,创造一个样的新对象,新创建的对象与原对象不共享内存,新创建的对象在内存中开辟一个新的内存地址,新对象值修改时不会影响原对象值。既然内存地址不同,释放内存地址时,可分别释放。

值类型的数据,默认全部都是深复制,Array、Int、String、Struct、Float,Bool。

浅拷贝(Shallow Copy):

拷贝的是数据地址,只复制指向的对象的指针,此时新对象和老对象指向的内存地址是一样的,新对象值修改时老对象也会变化。释放内存地址时,同时释放内存地址。引用类型的数据,默认全部都是浅复制,Slice,Map。


6.申明常量

①.常量的申明

常量是一个简单值的标识符,在程序运行时,不会被修改的量。

常量中的数据类型只可以是布尔型、数字型(整数型、浮点型和复数)和字符串型。

常量的定义格式有如下几种:

const identifier [type] = value

const c_name1, c_name2 = value1, value2

const (
    Unknown = 0
    Female = 1
    Male = 2
)

同样的,我们可以省略常量的类型,Go语言会自己判断出来的。

常量可以用len(), cap(), unsafe.Sizeof()函数计算表达式的值。常量表达式中,函数必须是内置函数,否则编译不过。

package main

import "unsafe"
const (
    a = "abc"
    b = len(a)
    c = unsafe.Sizeof(a)
)

func main(){
    println(a, b, c)
}

以上实例运行结果为:

abc 3 16

这里对unsafe.Sizeof()进行一点补充:

a = "hello"
unsafe.Sizeof(a)

输出结果为:16

字符串类型在 go 里是个结构, 包含指向底层数组的指针和长度,这两部分每部分都是 8 个字节,所以字符串类型大小为 16 个字节。

在Go语言中,字符串类型是一个结构体,包含一个指向底层数据的指针和一个表示字符串长度的整数。在64位系统上,每个指针占用8字节,整数占用8字节。因此,一个字符串类型在64位系统上总共占用16字节的空间。

对于给定的代码a = "hello",虽然a是一个字符串类型的变量,但在赋值时,实际上是将一个指向字符串"hello"底层数据的指针赋值给了a。因此,unsafe.Sizeof(a)返回的是一个指针的大小,即8字节。

因此,代码a = "hello"; unsafe.Sizeof(a)的运行结果是8。

②.常量组的特性

在定义常量组时,如果不提供初始值,则表示将使用上行的表达式。

package main
import "fmt"
const (
    a = 1
    b
    c
    d
)
func main() {
    fmt.Println(a)
    // b、c、d没有初始化,使用上一行(即a)的值
    fmt.Println(b)   // 输出1
    fmt.Println(c)   // 输出1
    fmt.Println(d)   // 输出1
}
③.特殊的常量 iota

iota,特殊常量,可以认为是一个可以被编译器修改的常量。

iota 在 const关键字出现时将被重置为 0(const 内部的第一行之前),const 中每新增一行常量声明将使 iota 计数一次(iota 可理解为 const 语句块中的行索引)。

iota 可以被用作枚举值

const (
    a = iota
    b = iota
    c = iota
)

第一个 iota 等于 0,每当 iota 在新的一行被使用时,它的值都会自动加 1;所以 a=0, b=1, c=2 可以简写为如下形式:

const (
    a = iota
    b
    c
)

可以看一下示例:

package main

import "fmt"

func main() {
    const (
            a = iota   //0
            b          //1
            c          //2
            d = "ha"   //独立值,iota += 1
            e          //"ha"   iota += 1
            f = 100    //iota +=1
            g          //100  iota +=1
            h = iota   //7,恢复计数
            i          //8
    )
    fmt.Println(a,b,c,d,e,f,g,h,i)
}

以上实例运行结果为:

0 1 2 ha ha 100 100 7 8

还有一个实例:

package main

import "fmt"
const (
    i=1<<iota
    j=3<<iota
    k
    l
)

func main() {
    fmt.Println("i=",i)
    fmt.Println("j=",j)
    fmt.Println("k=",k)
    fmt.Println("l=",l)
}

 

以上实例运行结果为:

i= 1
j= 6
k= 12
l= 24

iota 表示从 0 开始自动加 1,所以 i=1<<0j=3<<1<< 表示左移的意思),即:i=1, j=6,这没问题,关键在 k 和 l,从输出结果看 k=3<<2l=3<<3

简单表述:

  • i=1:左移 0 位,不变仍为 1。
  • j=3:左移 1 位,变为二进制 110,即 6。
  • k=3:左移 2 位,变为二进制 1100,即 12。
  • l=3:左移 3 位,变为二进制 11000,即 24。

iota 只是在同一个 const 常量组内递增,每当有新的 const 关键字时,iota 计数会重新开始。

package main
const (
    i = iota
    j = iota
    x = iota
)
const xx = iota
const yy = iota
func main(){
    println(i, j, x, xx, yy)
}

输出结果是 0 1 2 0 0

  • 9
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值