前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Golang简介

Golang简介

作者头像
老高的技术博客
发布2022-12-28 12:21:07
4060
发布2022-12-28 12:21:07
举报
文章被收录于专栏:老高的技术博客

Golang简介

Why Golang?

我发现我花了四年时间锤炼自己用 C 语言构建系统的能力,试图找到一个规范,可以更好的编写软件。结果发现只是对 Go 的模仿。缺乏语言层面的支持,只能是一个拙劣的模仿。 --- 吴云洋(云风的 BLOG)

特点

  • 并行
  • 快速
  • UTF-8
  • 跨平台

配置运行环境

下载安装

官网下载地址 https://golang.org/dl/

下载文件并执行安装,Linux系统只需要解压即可!

Docker--Golang

tips 命令行godoc -http=:8081 可以查看离线文档

配置

指定GOPATH为将要工作的目录,然后将bin添加到PATH中,输入命令go env查看

代码语言:javascript
复制
GOARCH="amd64"   ---架构
GOBIN=""         ---编译好的文件
GOEXE=""  
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GOOS="darwin"  --系统
GOPATH="/Users/gaozhimin/work"  --工作目录
GORACE=""
GOROOT="/usr/local/go"     --go的安装目录
GOTOOLDIR="/usr/local/go/pkg/tool/darwin_amd64"
CC="clang"
GOGCCFLAGS="-fPIC -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/qy/y1gwdk9x425f4nn60278ncp00000gn/T/go-build689949734=/tmp/go-build -gno-record-gcc-switches -fno-common"
CXX="clang++"
CGO_ENABLED="1"

编辑器

推荐使用

基本语法

HELLO_WORLD

代码语言:javascript
复制
// 一个文件夹内只能有一个包名
package main

import "fmt"

func main() {
    // P在⬇️此处大写,注意
    fmt.Println("Hello world!")
    // 普通字符使用双引号
}

Golang的双引号和反引号都可用于表示一个常量字符串,不同在于:

  • 双引号用来创建可解析的字符串字面量(支持转义,但不能用来引用多行)
  • 反引号用来创建原生的字符串字面量,这些字符串可能由多行组成(不支持任何转义序列),原生的字符串字面量多用于书写多行消息、HTML以及正则表达式

变量声明

类型在变量的后面

例子

代码语言:javascript
复制
var a int
var b bool
// := 等价于 var 后赋值
c := 5

var (
    e int
    f bool
)
g := `Linkin
    Park`

const x = 42

const (
    y = 1
    b = ""
)

基本类型

  • int,Runes(注:Rune 是int 的别名)
  • int8 ,int16 ,int32 ,int64
  • byte ,uint8 ,uint16 ,uint32 ,uint64 (注:byte是uint8 的别名)
  • float32 ,float64 (没有float 类型)
  • bool
  • string
  • complex128,complex64

保留关键字

break case chan const continue default func defer go else goto fallthrough if for import interface map package range return select struct switch type var

对比PHP

控制结构

代码语言:javascript
复制
// if
if err := Chmod(0664); err != nil {
    // 注意err的作用于
    fmt.Printf(err)
    return err
}

// for
sum := 0
for i := 0; i < 10; i++ {
    sum += i
}

//循环中的break和continue

for{
    // 如果不加break,就是一个完美的死循环
    break
}

for pos, char := range "abc" {
    fmt.Printf("character '%c' starts at byte position %d\n", char, pos)
}

// switch

var i int
switch i {
case 0:
case 1:
    f()
default:
    g() //当i不等于0或1时调用
}

复合类型

array、slices 和 map

array

代码语言:javascript
复制
// 定长
var arr [10]int
// 长度不同类型不同
var a [10]int
var b [11]int
a = b //报错

// 传值不传址

slice

代码语言:javascript
复制
// 长度可以改变
sl := make([]int, 10)
// 传地址
s1 := []int{1, 2, 3}
s2 := s1
fmt.Println(s2)
s1[0] = 0
fmt.Println(s2)
// [1 2 3]
// [0 2 3]
s3 := append(s3, 4)
fmt.Println(s3)

map

≈ python.map

代码语言:javascript
复制
newMap := map[int]string{
    0: "Sun", 1: "Mon",
    2: "Tue", 3: "Wed",
    4: "Thu", 5: "Fri",
    6: "Sat",
}
// 查找键值是否存在
if v, ok := newMap[7]; ok {
    fmt.Println(v)
} else {
    fmt.Println("Key Not Found")
}
// Key Not Found
delete(newMap, 5)
fmt.Println(newMap)

函数

作用域

代码语言:javascript
复制
package main

var a = 6

func main() {
    p()
    q()
    p()
}
func p() {
    println(a)
}
func q() {
    a := 5
    // a = 5
    println(a)
}

返回格式

代码语言:javascript
复制
// 函数参数 ip,类型为string
// 函数返回,conn和error
func connect(ip string) (conn *conn, err error){
    ...
    ...
    
    return
}

func connect(ip string) (*conn, error){
    conn := xxxx
    err := xxx
    
    return conn, err
}

// 接参数
con, err = connect("127.0.0.1")
if err != nil{
    panic("error")
}

// 忽略参数
_, err = connect("127.0.0.1")
if err != nil{
    panic("error")
}

Defer

代码语言:javascript
复制
func downloadFile(filepath string, url string) (err error) {

    // Create the file
    out, err := os.Create(filepath)
    if err != nil {
        return err
    }
    defer out.Close()

    // Get the data
    resp, err := http.Get(url)
    if err != nil {
        return err
    }
    defer resp.Body.Close()

    // Writer the body to file
    _, err = io.Copy(out, resp.Body)
    if err != nil {
        return err
    }

    return
}

匿名函数

代码语言:javascript
复制
func main() {
    a := func() {
        fmt.Println("你好")
    }
    a()
}

回调

代码语言:javascript
复制
func main() {
    callback("callback", print)
}
func print(s string) {
    fmt.Println(s)
}

func callback(s string, f func(string)) {
    f(s)
}

恐慌和恢复

代码语言:javascript
复制
func main() {
    if throwsPanic(p) {
        fmt.Println("Panic Happened")
    }
}

//可能出现恐慌
func p() {
    panic("failed")
}

func throwsPanic(f func()) (b bool) {
    // defer在发生恐慌后能够执行,使用recover能捕捉到panic
    defer func() {
        if x := recover(); x != nil {
            b = true
        }
    }()
    f()
    return
}

包是函数和数据的集合。用 package 关键字定义一个包。每个文件都必须以package开头!

包名

简洁明了,无下划线,无大小写混合,分隔符表示目录层级关系。

import的起点为

代码语言:javascript
复制
import (
    "io"
    "net/http"
    "os"
    
    "github.com/laogao/tools/lib"
)

net/http net/http 实现了 HTTP 请求、响应和 URL 的解析,并且提供了可扩展的 HTTP 服 务和基本的 HTTP 客户端。

flag flag 包实现了命令行解析。

os os 包提供了与平台无关的操作系统功能接口。其设计是 Unix 形式的。

io 这个包提供了原始的 I/O 操作界面。它主要的任务是对 os 包这样的原始的 I/O 进 行封装,增加一些其他相关,使其具有抽象功能用在公共的接口上。

fmt 包 fmt 实现了格式化的 I/O 函数,这与 C 的 printf 和 scanf 类似。格式化短语 派生于 C 。

首字母大小写

名称以大写字母起始的是可导出(exported)的。

代码语言:javascript
复制
func Add(a, b int) int {
    return a + b
}

func hide(){
    xxxx
}

工程目录

代码语言:javascript
复制
goWorkSpace     // goWorkSpace为GOPATH目录
  -- bin
     -- myApp1  // 编译生成
     -- myApp2  // 编译生成
     -- myApp3  // 编译生成
  -- pkg
  -- src
     -- common 1
     -- common 2
     -- common utils ...
     -- myApp1     // project1
        -- models
        -- controllers
        -- others
        -- main.go 
     -- myApp2     // project2
        -- models
        -- controllers
        -- others
        -- main.go 
     -- myApp3     // project3
        -- models
        -- controllers
        -- others
        -- main.go 

获取第三方Go包

https://github.com/go-sql-driver/mysql为例

代码语言:javascript
复制
go get github.com/go-sql-driver/mysql

指针和结构体

指针

代码语言:javascript
复制
func main() {
    var i int
    i = 1
    var p *int
    p = &i

    fmt.Printf("i=%d;p=%d;*p=%d\n", i, p, *p)

    *p = 2
    fmt.Printf("i=%d;p=%d;*p=%d\n", i, p, *p)

    i = 3
    fmt.Printf("i=%d;p=%d;*p=%d\n", i, p, *p)
}

结构体

代码语言:javascript
复制
type foo int

func main() {
    var a foo
    a = 1
    fmt.Println(a)

    t1 := T{"t1"}

    fmt.Println("M1调用前:", t1.Name)
    t1.M1()
    fmt.Println("M1调用后:", t1.Name)

    fmt.Println("M2调用前:", t1.Name)
    t1.M2()
    fmt.Println("M2调用后:", t1.Name)
}

//想要使用结构体,可以在其类型上添加函数,也可以直接做参数传入函数中

type T struct {
    Name string
}

func (t T) M1() {
    t.Name = "name1"
}

func (t *T) M2() {
    t.Name = "name2"
}

传值与传指针

当我们传一个参数值到被调用函数里面时,实际上是传了这个值的一份copy,当在被调用函数中修改参数值的时候,调用函数中相应实参不会发生任何变化,因为数值变化只作用在copy上。

传指针比较轻量级 (8bytes),只是传内存地址,我们可以用指针传递体积大的结构体。如果用参数值传递的话, 在每次copy上面就会花费相对较多的系统开销(内存和时间)。所以当你要传递大的结构体的时候,用指针是一个明智的选择。

Go语言中string,slice,map这三种类型的实现机制类似指针,所以可以直接传递,而不用取地址后传递指针。(注:若函数需改变slice的长度,则仍需要取地址传递指针)

要访问指针 p 指向的结构体中某个元素 x,不需要显式地使用 * 运算,可以直接 p.x

接口

代码语言:javascript
复制
package main

import (
    "fmt"
)

type apple struct {
}

type pineapple struct {
}

func (a apple) eat() {
    fmt.Println("I'm an apple,I can be eaten")
}

func (p *pineapple) eat() {
    fmt.Println("I'm a pineapple,I can be eaten")
}

type eatable interface {
    eat()
}

func main() {
    apple := apple{}
    pineapple := new(pineapple)
    eat(apple)
    eat(pineapple)
}

func eat(sth eatable) {
    sth.eat()
    switch sth.(type) {
    case *pineapple:
        fmt.Println("Got a pineapple")
    case apple:
        fmt.Println("Got a apple")
    }
}

GC

设想你正在编写一个长期运行的后台服务,就让它是一个 web 应用服务或者某些更复杂的东西。通常来说,在整个运行周期都会需要分配内存。了解如何处理这些内存是必要的。

通常,每 2 分钟会执行一次垃圾收集。如果某个片段持续 5 分钟都没有被使用,回收器会将其释放。

因此,如果你认为内存使用会降低,那么 7 分钟之后再去确认吧。

更多关于GC优化,可以浏览Go’s march to low-latency GC


并发

goroutine

goroutine不是线程、协程、进程等等,传递了不准确的含义。goroutine 有简单的模型:它是与其他 goroutine 并行执行的, 有着相同地址空间的函数。它是轻量的,仅比分配栈空间多一点点。 而初始时栈是很小的,所以它们也是廉价的,并且随着需要在堆空间上分 配(和释放)。

使用go关键字让一个函数以goroutine方式执行

代码语言:javascript
复制
func echo(s string) {
    fmt.Println(s)
}

func main() {
    echo("hi")
    go echo("hi")
    
    // time.Sleep(5 * time.Second)
}

//猜测一下回打印出什么?为什么?

channel

如果不考虑go出去的函数,那么程序就会执行完毕并退出,goroutine也会随之停止,需要引入一个通讯机制,他就是channel。

channel ≈ pipe

channel必须使用make关键字创建

代码语言:javascript
复制
c1 := make(chan int)

// channel可以有长度
c2 := make(chan string, 100)

//channel的使用方法

c1 <- 1 //把int 1 放入 c1
<-c1 //尝试从c1取值
a := <-c1 //取值并赋变量a

结合

在goroutine中我们把一个值写入chan,然后在主进程中尝试从chan中读取数据,如果此时chan中没有数据,程序会被阻塞,只到有值取出。

代码语言:javascript
复制
var c chan int

func ready(w string, sec int) {
    time.Sleep(time.Duration(sec) * time.Second)
    fmt.Println(w, "is ready!")
    c <- 1
}

func main() {
    c = make(chan int)
    go ready("Tea", 2)
    go ready("Coffee", 1)
    fmt.Println("I'm waiting, but not too long")
    <-c
    <-c
}

上面的例子是已经提前知道go出去的goroutine的个数才会这样写,当我们不知道个数的时候呢?

代码语言:javascript
复制
func main() {
    c = make(chan int)
    go ready("Tea", 2)
    go ready("Coffee", 1)
    i := 0
    
    //跳转标记L
L:
    for {
        select {
        case <-c:

            i++
            if i > 1 {
                break L
            }
        }
    }
}

超时机制

代码语言:javascript
复制
func main() {
    c = make(chan string)
    timeout = make(chan bool)
    go ready("Tea", 6)
    go ready("Coffee", 1)
    go func() {
        time.Sleep(time.Second * 3) // 5 秒超时
        timeout <- true
    }()
    fmt.Println("I'm waiting, but not too long")

L:
    for {
        select {
        case done := <-c:
            fmt.Println(done, "is ready!")
        case <-timeout:
            fmt.Println("timeout")
            break L
        }
    }
}

读取文件

方法一

代码语言:javascript
复制
func main() {
    buf := make([]byte, 1024)
    f, _ := os.Open("/etc/passwd")
    defer f.Close()
    for {
        n, _ := f.Read(buf)
        if n == 0 {
            break
        }
        os.Stdout.Write(buf[:n])
    }
}

方法二

代码语言:javascript
复制
func main() {
    fi, err := os.Open("/etc/passwd")
    if err != nil {
        panic(err)
    }
    defer fi.Close()
    fd, err := ioutil.ReadAll(fi)
    fmt.Println(string(fd))
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2017-06-23,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Golang简介
    • Why Golang?
      • 特点
        • 配置运行环境
          • 下载安装
          • 配置
          • 编辑器
        • 基本语法
          • HELLO_WORLD
          • 变量声明
          • 例子
          • 基本类型
        • 保留关键字
          • 对比PHP
        • 控制结构
          • 复合类型
            • array
            • slice
            • map
          • 函数
            • 作用域
            • 返回格式
            • Defer
            • 匿名函数
            • 回调
            • 恐慌和恢复
            • 包名
            • 首字母大小写
            • 工程目录
            • 获取第三方Go包
          • 指针和结构体
            • 指针
            • 结构体
            • 传值与传指针
          • 接口
            • GC
              • 并发
                • goroutine
                • channel
                • 结合
                • 超时机制
              • 读取文件
                • 方法一
                • 方法二
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档