百度360必应搜狗淘宝本站头条
当前位置:网站首页 > IT知识 > 正文

Go语言零基础入门指南(下篇)(go语言入门书)

liuian 2025-05-09 20:02 25 浏览

1. 并发编程

goroutine基础

Go版本:

func say(s string) {
    for i := 0; i < 3; i++ {
        time.Sleep(100 * time.Millisecond)
        fmt.Println(s)
    }
}

func main() {
    go say("world") // 启动goroutine
    say("hello")
}

对比Python线程:

import threading

def say(s):
    for i in range(3):
        time.sleep(0.1)
        print(s)

threading.Thread(target=say, args=("world",)).start()
say("hello")

对比JavaScript异步:

async function say(s) {
    for (let i = 0; i < 3; i++) {
        await new Promise(resolve => setTimeout(resolve, 100));
        console.log(s);
    }
}

say("world");
say("hello");

关键区别:

  1. goroutine比线程更轻量(初始仅2KB栈)
  2. Go运行时自动调度goroutine到OS线程
  3. 语法简单,只需go关键字

channel通信

Go版本:

func sum(s []int, c chan int) {
    sum := 0
    for _, v := range s {
        sum += v
    }
    c <- sum // 发送结果到channel
}

func main() {
    s := []int{7, 2, 8, -9, 4, 0}
    c := make(chan int)
    go sum(s[:len(s)/2], c)
    go sum(s[len(s)/2:], c)
    x, y := <-c, <-c // 从channel接收
    fmt.Println(x, y, x+y)
}

对比Python多进程:

from multiprocessing import Pipe

def sum(s, conn):
    conn.send(sum(s))
    conn.close()

parent_conn, child_conn = Pipe()
p1 = Process(target=sum, args=(s[:len(s)//2], child_conn))
p2 = Process(target=sum, args=(s[len(s)//2:], child_conn))
p1.start(); p2.start()
print(parent_conn.recv(), parent_conn.recv())

关键区别:

  1. channel是Go内置的线程安全通信机制
  2. 可以带缓冲(make(chan int, 100))
  3. 支持关闭channel和range遍历

select多路复用

Go版本:

func fibonacci(c, quit chan int) {
    x, y := 0, 1
    for {
        select {
        case c <- x:
            x, y = y, x+y
        case <-quit:
            fmt.Println("quit")
            return
        }
    }
}

func main() {
    c := make(chan int)
    quit := make(chan int)
    go func() {
        for i := 0; i < 10; i++ {
            fmt.Println(<-c)
        }
        quit <- 0
    }()
    fibonacci(c, quit)
}

对比JavaScript Promise.race:

async function fibonacci(callback, quitSignal) {
    let x = 0, y = 1;
    while (true) {
        const result = await Promise.race([
            new Promise(res => callback(res, x)),
            quitSignal
        ]);
        if (result === 'quit') return;
        [x, y] = [y, x + y];
    }
}

关键区别:

  1. select可以同时监控多个channel
  2. 常用于超时控制:
   select {
   case res := <-c:
       fmt.Println(res)
   case <-time.After(1 * time.Second):
       fmt.Println("timeout")
   }

2. 文件操作与IO

文件读写

Go版本:

// 读取文件
data, err := os.ReadFile("test.txt")
if err != nil {
    log.Fatal(err)
}
fmt.Println(string(data))

// 写入文件
err = os.WriteFile("output.txt", []byte("Hello"), 0644)
if err != nil {
    log.Fatal(err)
}

对比Python:

with open('test.txt') as f:
    data = f.read()

with open('output.txt', 'w') as f:
    f.write("Hello")

对比JavaScript:

const fs = require('fs');
fs.readFile('test.txt', (err, data) => {
    console.log(data.toString());
});

fs.writeFile('output.txt', 'Hello', err => {});

JSON处理

Go版本:

type Person struct {
    Name string `json:"name"`
    Age  int    `json:"age"`
}

// 编码
p := Person{"Alice", 25}
jsonData, _ := json.Marshal(p)

// 解码
var p2 Person
json.Unmarshal(jsonData, &p2)

对比Python:

import json

data = json.dumps({"name": "Alice", "age": 25})
p = json.loads(data)

对比JavaScript:

const data = JSON.stringify({name: "Alice", age: 25});
const p = JSON.parse(data);

关键区别:

  1. Go需要定义结构体对应JSON结构
  2. 字段标签控制JSON属性名
  3. 编解码可能返回错误需要处理

3. 测试与性能

单元测试

Go版本:

// math.go
func Add(a, b int) int {
    return a + b
}

// math_test.go
func TestAdd(t *testing.T) {
    result := Add(2, 3)
    if result != 5 {
        t.Errorf("Expected 5, got %d", result)
    }
}

运行测试:

go test

对比Python unittest:

import unittest

def add(a, b):
    return a + b

class TestMath(unittest.TestCase):
    def test_add(self):
        self.assertEqual(add(2, 3), 5)

基准测试

Go版本:

func BenchmarkAdd(b *testing.B) {
    for i := 0; i < b.N; i++ {
        Add(1, 2)
    }
}

运行基准测试:

go test -bench=.

4. 项目实践

简单HTTP服务

Go版本:

func helloHandler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hello, %s!", r.URL.Path[1:])
}

func main() {
    http.HandleFunc("/", helloHandler)
    http.ListenAndServe(":8080", nil)
}

对比Python Flask:

from flask import Flask
app = Flask(__name__)

@app.route('/<name>')
def hello(name):
    return f"Hello, {name}!"

app.run(port=8080)

对比JavaScript Express:

const express = require('express');
const app = express();

app.get('/:name', (req, res) => {
    res.send(`Hello, ${req.params.name}!`);
});

app.listen(8080);

项目结构建议

典型Go项目布局:

myapp/
├── cmd/
│   └── myapp/
│       └── main.go
├── internal/
│   ├── handler/
│   ├── service/
│   └── repository/
├── pkg/
│   └── utils/
├── go.mod
├── go.sum
└── README.md

进一步学习资源

  1. 官方文档:https://golang.org/doc/
  2. 标准库参考:https://pkg.go.dev/std
  3. 经典书籍:《Go程序设计语言》《Go语言实战》
  4. 开源项目:Docker, Kubernetes, Etcd等Go项目源码

下篇介绍了Go最强大的并发特性和实际项目开发中的关键技能。Go通过goroutine和channel提供了独特的并发编程模型,相比其他语言的线程/异步方案更加简单高效。建议通过实际项目练习来巩固这些概念,逐步掌握Go语言的精髓。

相关推荐

python入门到脱坑函数—定义函数_如何定义函数python

Python函数定义:从入门到精通一、函数的基本概念函数是组织好的、可重复使用的代码块,用于执行特定任务。在Python中,函数可以提高代码的模块性和重复利用率。二、定义函数的基本语法def函数名(...

javascript函数的call、apply和bind的原理及作用详解

javascript函数的call、apply和bind本质是用来实现继承的,专业点说法就是改变函数体内部this的指向,当一个对象没有某个功能时,就可以用这3个来从有相关功能的对象里借用过来...

JS中 call()、apply()、bind() 的用法

其实是一个很简单的东西,认真看十分钟就从一脸懵B到完全理解!先看明白下面:例1obj.objAge;//17obj.myFun()//小张年龄undefined例2shows(...

Pandas每日函数学习之apply函数_apply函数python

apply函数是Pandas中的一个非常强大的工具,它允许你对DataFrame或Series中的数据应用一个函数,可以是自定义的函数,也可以是内置的函数。apply可以作用于DataF...

Win10搜索不习惯 换个设定就好了_window10搜索用不了怎么办

Windows10的搜索功能是真的方便,这点用惯了Windows10的小伙伴应该都知道,不过它有个小问题,就是Windows10虽然会自动联网搜索,但默认使用微软自家的Bing搜索引擎和Edge...

面试秘籍:call、bind、apply的区别,面试官为什么总爱问这三位?

引言你有没有发现,每次JavaScript面试,面试官总爱问你call、bind和apply的区别?好像这三个方法成了通关密码,掌握了它们,就能顺利过关。其实不难理解,面试官问这些问题,不...

记住这8招,帮你掌握“追拍“摄影技法—摄影早自习第422日

杨海英同学提问:请问叶梓老师,我练习追拍时,总也不能把运动的人物拍清晰,速度一般掌握在1/40-1/60,请问您如何把追拍拍的清晰?这跟不同的运动形式有关系吗?请您给讲讲要点,谢谢您!摄影:Damia...

[Sony] 有点残酷的测试A7RII PK FS7

都是好机!手中利器!主要是最近天天研究fs5,想知道fs5与a7rii后期匹配问题,苦等朋友的fs5月底到货,于是先拿手里现有的fs7小测一下,十九八九也能看到fs5的影子,另外也了解一下fs5k标配...

AndroidStudio_Android使用OkHttp发起Http请求

这个okHttp的使用,其实网络上有很多的案例的,但是,如果以前没用过,copy别人的直接用的话,可以发现要么导包导不进来,要么,人家给的代码也不完整,这里自己整理一下.1.引入OkHttp的jar...

ESL-通过事件控制FreeSWITCH_es事务控制

通过事件提供的最底层控制机制,允许我们有效地利用工具箱,适时选择使用其中的单个工具。FreeSWITCH是一个核心交换与混合矩阵,它周围有几十个模块提供各种功能特性。我们完全控制了所有的即时信息,这些...

【调试】perf和火焰图_perf生成火焰图

简介perf是linux上的性能分析工具,perf可以对event进行统计得到event的发生次数,或者对event进行采样,得到每次event发生时的相关数据(cpu、进程id、运行栈等),利用这些...

文本检索控件也玩安卓?dtSearch Engine发布Android测试版

dtSearchEngineforLinux(原生64-bit/32-bitC++和JavaAPIs)和dtSearchEngineforWin&.NET(原生64-bi...

网站后台莫名增加N个管理员,记一次SQL注入攻击

网站没流量,但却经常被SQL注入光顾。最近,网站真的很奇怪,网站后台不光莫名多了很多“管理员”,所有的Wordpres插件还会被自动暂停,导致一些插件支持的页面,如WooCommerce无法正常访问、...

多元回归树分析Multivariate Regression Trees,MRT

多元回归树(MultivariateRegressionTrees,MRT)是单元回归树的拓展,是一种对一系列连续型变量递归划分成多个类群的聚类方法,是在决策树(decision-trees)基础...

JMETER性能测试_JMETER性能测试指标

jmeter为性能测试提供了一下特色:jmeter可以对测试静态资源(例如js、html等)以及动态资源(例如php、jsp、ajax等等)进行性能测试jmeter可以挖掘出系统最大能处...