初学者GO 之旅 (1) 包、变量、函数

本篇文章为go的启蒙文章,非常适合新手阅读,本文文笔生动形象,配图有趣可爱,实为下饭上厕所无聊打发时间的良心文字,欢迎大家阅读+评论。本文大部分文档来源于go官网教程:https://tour.golang.org/list 。也有一些第三方资料。

 Packages (包)

  所有的go程序都是由包组成的,意思就是说你不能像拍簧片(php) 一样, 这里拉一坨,那里拉一坨,你必须像java一样,所有的代码都对应着一个包,在包里面编写代码。懂了吗? 还不懂?给我爬。。。。。。

  但是呢,就像你出生在普通家庭,隔壁王二蛋却是个富二代一样。虽然大家都是包,但是有个包就比较特殊,那就 main 包(正好我认识一个昵称叫main的人)。所有的程序入口都是由main包开始的,就像你写c程序一样,必须要 void main() 。

import

  go程序都是由 import 关键字来导入包。import 一般在程序中都是导入的意思,类似的还有其他语言里面的 include(包含)require (依赖)等。每个语言都有自己的关键字。这里我们只说go。

一般来说 按照约定,程序包名称与导入路径的最后一个元素相同。例如,“ math/rand” 就有rand这个包的文件。当然,go也很贴心的为你准备了两种import写法。

第一种 写个() 把所有的代码包起来 (go官方推荐)

import (
	"fmt"
	"math/rand"
)

第二种 用双引号,一行一行的写

import "fmt"
import "math/rand"

  

好了 下面看一段比较完整代码:

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

下面我们分析下这段代码:
  第一行,声明是main包

  第二行,使用import关键字。引入了2个包。fmt是输出包,类似php里面的 echo
  第六行,我们定义了一个main 方法 mian包里只能有一个唯一的main方法,
  第七行,我们用fmt包里面的 Println 输出你最喜欢的数字。
  来看看,这个rand.Intn方法,哦 我的上帝,这是个伪随机数方法,所以我们这么写只会返回一个固定的值。
这真是个糟糕的决定,它看起来就像保罗叔叔的臭靴子一样恶心!
所以,应该怎么正确输出随机数呢。不对!这个问题我们不应该放在这里讲,后面我们会讲到,我发誓!

被导出的变量
在go里面,如果一个包里面的某个变量是大写字母开头,那么它就是public权限的,就是可以被导出。当你使用 import 一个包的时候,
默认你就拥有了这个包所有大写字母开头的变量和方法的权限。当然了 小写字母开头的变量和方法是无法使用的。来看看代码:
package main
import (
	"fmt"
	"math"
)
func main() {
	fmt.Println(math.Pi)  //这个是可以的
	fmt.Println(math.pi) //这个就报错了
}

Variables (变量)
go的变量声明和其他语言不太一样,go是类型在后面的声明,下面看代码:
var a int
var c,d,e bool

     变量定义既可以在包里,也可以在函数里,这两种变量的上下文会有所不同。变量也可以在定义的时候初始化:

var gwyy int = 3

  在函数内部,可以使用短语句来定义变量,不需要写完整的变量类型,这种定义还是比较方便的,大部分函数内我们都喜欢这么用。不过要注意哦,在函数外部是不可以的。

func gwyy() {
    a := 3
    b := true
    c := "fff"
}

  

 基本类型

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

  基本类型大概有这么几个。int,uint和uintptr类型在32位系统上通常为32位宽,在64位系统上为64位宽。当您需要整数值时,应该使用int,除非有特殊原因要使用大小或无符号整数类型。

      go有个体贴的地方,如果你声明变量没有赋值的话,go会默认给你初始化0值。

      数字类型 默认 0

      布尔类型默认  false

     字符串类型 默认 “”

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

  

类型转换

      表达式T(v)将值v转换为类型T。看个例子:

 

func main() {
	//一些数字转换
	var i int = 42
	var f float64 = float64(i)
	var u uint = uint(f)
	//或者更简单的
	i := 42
	f := float64(i)
	u := uint(f)
}

  

类型推断

    在声明变量而不指定显式类型时(通过使用:=语法或var =表达式语法),将从右侧的值推断出变量的类型。  

func main() {
	var i int
	j := i // 自动推断是 int
	//下面这些,右侧包含无类型的数字常量时,新变量可以是int,float64或complex128,具体取决于常量的精度:
	i := 42           // int
	f := 3.142        // float64
	g := 0.867 + 0.5i // complex128
}

  

常量

常量像变量一样声明,但是带有const关键字。常量可以是字符,字符串,布尔值或数字值。不能使用:=语法声明常量。

 

const Pi = 3.14

 

  



Functions

    go里面也是有函数的,一个函数可以接受0个或者多个参数。看下面的例子,add函数就接受了2个参数。这里有个小注意点,参数类型是放在变量名后面的。

package main
import "fmt"
func add(x int, y int) int {
	return x + y
}
func main() {
	fmt.Println(add(42, 13))
}

  这里有个语法糖,当函数多个参数类型一样的时候,可以只写一次类型像下面这样:

package main
import "fmt"
func add(x,y int) int {
	return x + y
}
func main() {
	fmt.Println(add(3,4))
}

  下面我们再看下函数的多返回值,这个特性是我几乎在别的语言里面没看到过,go的一个函数可以允许你定义多个返回值,这个东西得好好唠唠,这个东西比想象中要复杂。先看个例子:

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

  这个方法返回了2个返回值 ,其实就是一个简单的交换方法,如果java来做,可能就只能返回个map, 我们可以看到,在返回值的位置,我们是写了2个返回值类型,代表要返回几个返回值,类型是什么。

 

命名返回值

     看下面的例子,你又发现了什么呢:

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

  是不是很神奇,定义了2个返回值,但是return啥也没返回,就写了个空return。这个叫什么呢,这个叫命名返回值,就是你在函数声明的时候,就先把返回值给定义好,这个时候,最骚的操作来了,你根本不需要return任何狗屁东西直接就写个 return 就好了。是不是很神奇,大家可以再多看看。而且你再这个函数内 x y的变量也不用定义,因为在 “命名返回值” 里你自己已经定义好了。这种不带参数的return语句返回命名的返回值就是所谓的“裸”回报。

    其实这里go会把这2个变量当做你再函数顶部定义过了。但是!,这里有个大坑大家得注意下。看下代码:

 

func gwyy() (item []string) {
	item[0] = "aaa"
	return
}

 

  看起来是不是好像没问题,但是会直接panic:runtime error: index out of range [0] with length 0 。这是为什么呢。其实换个写法大家应该就能看懂了。

func gwyy()  {
	var item []string
	item[0] = "aaa"
	return
}

  其实刚才的命名返回值,我们拆开了就是这样的,可以看到 item变量只是声明了,根本没初始化。所以会直接报错。需要再代码最顶端加个初始化就好了

 

func gwyy()  {
	var item []string
	item = make([]string,3,3)
	item[0] = "aaa"
	return
}

  所以说这里要特别注意下,如果使用了命名返回值,基本类型不需要初始化了,go会默认给你初始化成0值或者“”,引用类型,像是 map,slices,channels,struct 等需要初始化的。当然啦 最后记得不要忘记写下 return。这里也有个建议。如果裸返回值不要再很长的函数内使用。否则会降低函数的可读性。

 

posted @ 2020-06-09 13:58  梁天  阅读(335)  评论(0编辑  收藏  举报