Golang极简入门教程(一):基本概念

 更新时间:2014年10月27日 09:37:06   投稿:junjie  
这篇文章主要介绍了Golang极简入门教程(一):基本概念,本文讲解了Golang的基本知识、基础语法、相关术语等,需要的朋友可以参考下

安装 Golang

http://golang.org/dl/ 可以下载到 Golang。安装文档:http://golang.org/doc/install

Hello Go

我们先创建一个文件 hello.go:

复制代码 代码如下:

package main
 
import "fmt"
 
func main() {
    fmt.Printf("hello Golang\n");
}

执行此程序:

复制代码 代码如下:

go run hello.go

Golang 程序由包(packages)组成,程序从 main 包开始运行:

复制代码 代码如下:

package main

此语句表示此文件属于 main 包(多个源文件可以属于同一个包)。import 语句后接上包所在的路径(被叫做包路径或导入路径),一个目录中放置一个包,通常的做法是,目录名和包名相同:

复制代码 代码如下:

import (
    "fmt"
    "math/rand"
)

这里的 “fmt” 和 “math/rand” 为包路径(导入路径)。上面的 import 语句也可以这样写:

复制代码 代码如下:

import "fmt"
import "math/rand"

我们导入了包之后,就可以通过 “包名.name” 来引用导出的 name 了,例如:

复制代码 代码如下:

import "fmt"
 
// fmt 包导出了 Printf
fmt.Printf("hello Golang\n");

在 Golang 中,一个名字如果首字母大写则表示此名字被导出。

函数

复制代码 代码如下:

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

需要注意的就是,变量名在类型之前,这和很多语言都不一样。另外 x int, y int 也可以写为 x, y int:
复制代码 代码如下:

func add(x, y int) int {
    return x + y
}

函数可以返回多个值:

复制代码 代码如下:

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)
}

返回值可以被指定变量名,并且像变量一样使用:

复制代码 代码如下:

package main
 
import "fmt"
 
func split(sum int) (x, y int) {
    x = sum * 4 / 9
    y = sum - x
    return
}
 
func main() {
    fmt.Println(split(17))
}

可以看到 split 函数直接使用 return 语句而不用带参数。

变量

变量的声明使用 var 语句:

复制代码 代码如下:

var i int
var c, python, java bool

变量在声明时可以进行初始化:

复制代码 代码如下:

var x, y int = 1, 2
var i, j = true, "hello"

我们看到,初始化时可以指定也可以不指定变量类型。
按照 Golang 的语法,在函数外的任何结构(construct)都通过一个关键字开始,例如变量使用 var 关键字开始,函数使用 func 关键字开始。在函数内,变量赋值可以使用 := 操作符:

复制代码 代码如下:

package main
 
func main() {
    var x, y int = 1, 2
    i, j := true, "hello"
}

:= 操作符左边为变量,右边为值。

数据类型

基本数据类型:

1.bool
2.string
3.int int8 int16 int32 int64
4.uint uint8 uint16 uint32 uint64
5.uintptr
6.byte(等价于 uint8)
7.rune(等价于 int32,用于表示一个 unicode code point)
8.float32 float64
9.complex64 complex128

类型转换使用表达式 T(v),含义为将 v 转换为类型 T:

复制代码 代码如下:

var i int = 42
var f float64 = float64(i)
 
i := 42
f := float64(i)

类型转换总需要显式的进行。

使用 const 来声明常量:

复制代码 代码如下:

const Pi = 3.14
 
const (
    Big = 1 << 100
    Small = Big >> 99
)

控制语句

for 语句

Golang 使用(且只使用)for 来进行循环(没有 while 语句):

复制代码 代码如下:

package main
 
func main() {
    sum := 0
   
    for i := 0; i < 10; i++ {
        sum += i
    }
   
    // 这种写法等价于 C/C++ 等语言中的 while 语句
    for sum < 1000 {
        sum += sum
    }
}

区别于 C/C++ 等语言,使用 for 语句时不需要 () 并且 {} 是必须的(后面谈到的 if、switch 在此语法处理上也是一样的)。如果需要无限循环,那么使用:

复制代码 代码如下:

for {
}

if 语句

if 语句可以在执行条件判断前带一个语句(这常被叫做 if 带上一个短语句),此语句中变量的生命周期在 if 语句结束后结束。例如:

复制代码 代码如下:

package main
 
import (
    "fmt"
    "math/rand"
)
 
func main() {
    if n := rand.Intn(6); n <= 2 {
        fmt.Println("[0, 2]", n)
    } else {
        fmt.Println("[3, 5]", n)
    }
 
    // 这里开始无法使用变量 n
}

switch

复制代码 代码如下:

package main
 
import (
    "fmt"
    "runtime"
)
 
func main() {
    fmt.Print("Go runs on ")
    // switch 类似 if 可以带上一个短语句
    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)
    }
}

不像 C/C++ 等语言,Golang 中无需使用 break 语句来跳出 switch。另外,switch 可以没有条件:

复制代码 代码如下:

package main
 
import (
    "fmt"
    "time"
)
 
func main() {
    t := time.Now()
    switch {
    case t.Hour() < 12:
        fmt.Println("Good morning!")
    case t.Hour() < 17:
        fmt.Println("Good afternoon.")
    default:
        fmt.Println("Good evening.")
    }
}

defer

一个 defer 语句能够将一个函数调用加入一个列表中(这个函数调用被叫做 deferred 函数调用),在当前函数调用结束时调用列表中的函数。范例:

复制代码 代码如下:

func CopyFile(dstName, srcName string) (written int64, err error) {
    src, err := os.Open(srcName)
    if err != nil {
        return
    }
    defer src.Close()
 
    dst, err := os.Create(dstName)
    if err != nil {
        return
    }
    defer dst.Close()
 
    return io.Copy(dst, src)
}

deferred 函数调用按先进后出的顺序执行:

复制代码 代码如下:

package main
 
import "fmt"
 
func main() {
    for i := 0; i < 5; i++ {
        // 输出 43210
        defer fmt.Print(i)
    }
}

结构(structs)

结构是一个域的集合:

复制代码 代码如下:

package main
 
import "fmt"
 
type Vertex struct {
    X int
    Y int
}
 
func main() {
    v := Vertex{1, 2}
    v.X = 4
    fmt.Println(v)
}

Golang 中是存在指针的,但是指针不支持算术运算:

复制代码 代码如下:

p := Vertex{1, 2} // {1, 2} 为 struct literal
q := &p // q 类型为 *Vertex
q.X = 2 // 直接访问域 X

就像上面看到的,struct 的 literal 由 {} 包裹,在 struct literal 中我们可以使用 Name: 这样的语法来为特定域设置值:

复制代码 代码如下:

type Vertex struct {
    X, Y int
}
 
r := Vertex{X: 3} // 这时候 Y 为 0

new 函数

我们可以通过表达式 new(T) 分配一个被初始化为 0 且类型为 T 的值,并且返回指向此值的指针,用法如下:

复制代码 代码如下:

var p *T = new(T)
p := new(T)

更详尽的例子:

复制代码 代码如下:

package main
 
import "fmt"
 
type Vertex struct {
    X, Y int
}
 
func main() {
    v := new(Vertex)
    fmt.Println(v)
    v.X, v.Y = 11, 9
    fmt.Println(v)
}

数组和 slice

[n]T 在 Golang 中是一个类型(就像 *T 一样),表示一个长度为 n 的数组其元素类型为 T。范例:

复制代码 代码如下:

package main
 
import "fmt"
 
func main() {
    var a [2]string
    a[0] = "Hello"
    a[1] = "World"
    fmt.Println(a[0], a[1])
    fmt.Println(a)
}

注意,数组长度无法被改变。

slice 是一个数据结构,其指向一个数组某个连续的部分。slice 用起来很像数组。[]T 为 slice 类型,其中元素类型为 T:

复制代码 代码如下:

package main
 
import "fmt"
 
func main() {
    // 构建一个 slice
    p := []int{2, 3, 5, 7, 11, 13}
    fmt.Println("p ==", p)
 
    for i := 0; i < len(p); i++ {
        fmt.Printf("p[%d] == %d\n", i, p[i])
    }
}

表达式 s[lo:hi] 用于创建一个 slice,新创建的 slice 的元素为 s 中 [lo, hi) 位置的元素。

创建 slice 使用 make 函数(而不是用 new 函数,因为需要设置额外的参数来控制 slice 的创建):

复制代码 代码如下:

// len(a) 为 5
a := make([]int, 5)

这里 make 函数会创建一个数组(其元素初始化为 0)并返回一个 slice 指向此数组。make 可以带第三个参数,用于指定容量:

复制代码 代码如下:

// len(b) 为 0
// cap(b) 为 5
b := make([]int, 0, 5)
 
b = b[:cap(b)] // len(b)=5, cap(b)=5
b = b[1:] // len(b)=4, cap(b)=4

一个没有值的 slice 是 nil,长度和容量都为 0。

复制代码 代码如下:

package main
 
import "fmt"
 
func main() {
    var z []int
    fmt.Println(z, len(z), cap(z))
    if z == nil {
        fmt.Println("nil!")
    }
}

range

range 被用在 for 中来迭代一个 slice 或者一个 map:

复制代码 代码如下:

package main
 
import "fmt"
 
var s = []int{1, 2, 3}
 
func main() {
    for i, v := range s {
        fmt.Println(i, v)
    }
 
    // 只需要值,使用 _ 忽略索引
    for _, v := range s {
        fmt.Println(v)
    }
 
    // 只需要索引
    for i := range s {
        fmt.Println(i)
    }
}

map

map 用于映射 key 到 value(值)。map 可以通过 make 来创建(而非 new):

复制代码 代码如下:

package main
 
import "fmt"
 
type Vertex struct {
    Lat, Long float64
}
 
var m map[string]Vertex
 
func main() {
    m = make(map[string]Vertex)
    m["Bell Labs"] = Vertex{
        40.68433, -74.39967,
    }
    fmt.Println(m["Bell Labs"])
}

map iteral 很像 struct literal:

复制代码 代码如下:

var m = map[string]Vertex{
    // 这里 Vertex 可以省略不写
    "Bell Labs": Vertex{
        40.68433, -74.39967,
    },
    "Google": Vertex{
        37.42202, -122.08408,
    },
}

使用 [] 来访问 map 中的值,使用 delete 来删除 map 中的值:

复制代码 代码如下:

m[key] = elem
elem = m[key]
delete(m, key)

如果需要检查 map 中某 key 是否存在使用:
复制代码 代码如下:

elem, ok = m[key]

elem 表示 key 的值(key 不存在时,elem 为 0),ok 表示 key 是否存在。

闭包

Golang 中函数也是一个值(就像 int 值一样),且函数可以是一个闭包。闭包是一个引用了外部变量的函数。看一个例子:

复制代码 代码如下:

package main
 
import "fmt"
 
func adder() func(int) int {
    sum := 0
    // 返回一个闭包,此闭包引用了外部变量 sum
    return func(x int) int {
        sum += x
        return sum
    }
}
 
func main() {
    a := adder()
    fmt.Println(a(9527))
}

相关文章

  • Go 并发实现协程同步的多种解决方法

    Go 并发实现协程同步的多种解决方法

    这篇文章主要介绍了Go 并发——实现协程同步的多种解决方法,非常不错,具有一定的参考借鉴价值,需要的朋友可以参考下
    2018-08-08
  • go语言读取json并下载高清妹子图片

    go语言读取json并下载高清妹子图片

    前面我们介绍了使用python下载高清妹子图,作为程序猿,我们当然不能只会一种语言,今天我们就来使用go语言来读取API来下载妹子图吧,有需要的宅男们可以参考下。
    2015-03-03
  • golang解析yaml文件操作

    golang解析yaml文件操作

    这篇文章主要介绍了golang解析yaml文件操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-12-12
  • Windows下使用go语言写程序安装配置实例

    Windows下使用go语言写程序安装配置实例

    这篇文章主要介绍了Windows下使用go语言写程序安装配置实例,本文讲解了安装go语言、写go代码、生成可执行文件、批量生成可执行文件等内容,需要的朋友可以参考下
    2015-03-03
  • 深入分析golang多值返回以及闭包的实现

    深入分析golang多值返回以及闭包的实现

    相对于C/C++,golang有很多新颖的特性,例如goroutine,channel等等,这些特性其实从golang源码是可以理解其实现的原理。今天这篇文章主要来分析下golang多值返回以及闭包的实现,因为这两个实现golang源码中并不存在,我们必须从汇编的角度来窥探二者的实现。
    2016-09-09
  • 基于Go和PHP语言实现爬楼梯算法的思路详解

    基于Go和PHP语言实现爬楼梯算法的思路详解

    这篇文章主要介绍了Go和PHP 实现爬楼梯算法,本文通过动态规划和斐波那契数列两种解决思路给大家讲解的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-05-05
  • 如何使用Goland IDE go mod 方式构建项目

    如何使用Goland IDE go mod 方式构建项目

    这篇文章主要介绍了如何使用Goland IDE go mod 方式构建项目,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-10-10
  • golang 结构体初始化时赋值格式介绍

    golang 结构体初始化时赋值格式介绍

    这篇文章主要介绍了golang 结构体初始化时赋值格式介绍,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-12-12
  • 浅谈goland导入自定义包时出错(一招解决问题)

    浅谈goland导入自定义包时出错(一招解决问题)

    这篇文章主要介绍了浅谈goland导入自定义包时出错(一招解决问题),具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-12-12
  • go语言中json数据的读取和写出操作

    go语言中json数据的读取和写出操作

    这篇文章主要介绍了go语言中json数据的读取和写出操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-04-04

最新评论