8bfd8a0528c0172912adb9ad002d2bbb6902bda5.jpg

变量的定义和赋值

Go 是静态编译型语言,所有变量在定义时都必须明确其类型,定义格式和示例如下:

var identifier [type] = value
   var xjj string
   var xjj2 string = "hello xjj"

Go 语言支持类型推断,可以使用 := 赋值操作符对一个变量定义并赋值。

a := "xjj"
   b := false

a和b的类型编译器会自行推断,a则会默认为string类型,b为bool

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

常量

常量使用关键字 const 定义,用于存储不会改变的数据。存储在常量中的数据类型只可以是布尔型、数字型(整数型、浮点型和复数)和字符串型。

const Pi = 3.14159

空白标识符

在 Go 语言中,_ 被称作空白标识符,用于抛弃值,例如:

_, b := 5, 7

5 这个值将会被抛弃。

_ 实际上是一个只写变量,你不能得到它的值。这样做是因为 Go 语言中你必须使用所有被声明的变量,但有时你并不需要使用从一个函数得到的所有返回值。

包和 import

一个文件夹下只能有一个包。

import 是以包为单位的,导入名称是包的路径,导入后使用是用包名,并非路径的最后一级字符。

import _ "..."

表示只调用包的 init 函数,并没有把整个包都导入进来

可见性

Go 语言中没有像其它语言中的 public、protected、private 等访问控制修饰符,它是通过字母大小写来控制可见性的,如果定义的变量、常量、类型、函数等的名称是大写字母开头就表示能被其它包访问或调用(相当于 public),非大写开头就只能在包内使用(相当于 private,变量或常量也可以以下划线开头)。

换行规则(坑爹)

左大括号 { 必须与方法的声明放在同一行,这是编译器的强制规定,Go 语言虽然看起来不使用分号作为语句的结束,但实际上这一过程是由编译器自动完成,所以下面这种定义将会报错:

func functionName(parameter_list) (return_value_list)
{
   …
}
syntax error: unexpected semicolon or newline before {

而右大括号 } 需要被放在紧接着函数体的下一行。如果你的函数非常简短,你也可以将它们放在同一行。

如果我们的函数参数太多,想换行来写,这时候也要注意,最后一个字符必须是逗号。

只要牢记 Go 语言使用分号作为语句的结束这一过程是由编译器自动完成的,为什么会报错也不难理解。

a := []string{"a", "b", "c"}

// Good
a := []string{
    "a",
    "b",
    "c",
}

// Bad
a := []string{
    "a",
    "b",
    "c"
}
// syntax error: unexpected newline, expecting comma or }

指针

不像 Java 和 PHP,Go 语言中有指针;但是,你不能进行指针运算。通过给予程序员基本内存布局,Go 语言允许你控制特定集合的数据结构、分配的数量以及内存访问模式。类似于引用

声明格式如下:

var intP *int

Go 语言的取地址符是 &,放到一个变量前使用就会返回相应变量的内存地址。

var i = 5
var intP *int

intP = &i

intP 存储了 i 的内存地址;它指向了 i 的位置,它引用了变量 i。

try catch?

Go 语言追求简洁优雅,所以,Go 语言不支持传统的 try…catch…finally 这种异常,因为 Go 语言的设计者们认为,将异常与控制结构混在一起会很容易使得代码变得混乱。因为开发者很容易滥用异常,甚至一个小小的错误都抛出一个异常。在 Go 语言中,使用多值返回来返回错误。不要用异常代替错误,更不要用来控制流程。

错误处理基本靠 if err != nil

class?

Go 语言中没有类的概念,但不代表它没有面向对象这个概念。Go 语言中可以通过一种特殊的函数定义语法来为变量定义方法。

方法是作用在接收者(receiver)上的一个函数,接收者是某种类型的变量。因此方法是一种特殊类型的函数。

接收者类型可以是(几乎)任何类型,不仅仅是结构体类型:任何类型都可以有方法,甚至可以是函数类型,可以是 int、bool、string 或数组的别名类型。但是接收者不能是一个接口类型,因为接口是一个抽象定义,但是方法却是具体实现;如果这样做会引发一个编译错误:invalid receiver type。

定义方法的一般格式如下:

func (recv receiver_type) methodName(parameter_list) (return_value_list) { ... }

因为方法是函数,所以同样的,不允许方法重载,即对于一个类型只能有一个给定名称的方法。但是如果基于接收者类型,是有重载的:具有同样名字的方法可以在 2 个或多个不同的接收者类型上存在(就相当于不同的类中有一样的名称的方法),比如在同一个包里这么做是允许的:

func (a *denseMatrix) Add(b Matrix) Matrix
func (a *sparseMatrix) Add(b Matrix) Matrix

接口

但是 Go 语言里有非常灵活的接口概念,通过它可以实现很多面向对象的特性。接口提供了一种方式来说明对象的行为:如果谁能搞定这件事,它就可以用在这儿。

接口定义了一组方法(方法集),但是这些方法不包含(实现)代码:它们没有被实现(它们是抽象的)。接口里也不能包含变量。

通过如下格式定义接口:

type Namer interface {
    Method1(param_list) return_type
    Method2(param_list) return_type
     ...
}

上面的 Namer 是一个接口类型。

(按照约定,只包含一个方法的)接口的名字由方法名加 [e]r 后缀组成,例如 Printer、Reader、Writer、Logger、Converter 等等。还有一些不常用的方式(当后缀 er 不合适时),比如 Recoverable,此时接口名以 able 结尾,或者以 I 开头(像 PHP 或 Java 中那样)

go fmt

Go 开发团队不想要 Go 语言像许多其它语言那样总是在为代码风格而引发无休止的争论,浪费大量宝贵的开发时间,因此他们制作了一个工具:go fmt(gofmt)。这个工具可以将你的源代码格式化成符合官方统一标准的风格,属于语法风格层面上的小型重构。遵循统一的代码风格是 Go 开发中无可撼动的铁律,因此你必须在编译或提交版本管理系统之前使用 gofmt 来格式化你的代码。不得不说,这个理念是真的不错。

初学Go语言,还有很多理解不到的地方,欢迎各位大佬指教