Python程序员想通过示例项目学习Golang

Python程序员想通过示例项目学习Golang 你好

我不是编程新手。过去我使用过 Python 和其他几种语言,因此能够掌握 Go 语言中其他语言也提供的基础知识(循环、条件判断等)。我想通过实际项目来学习 Go 语言,而不是仅仅进行编码练习。您能在这方面给我一些指导吗?

谢谢。

6 回复

你可以用Go语言重写一些应用程序。此外,你可以寻找开源项目并尝试参与贡献。提交拉取请求,查看缺失的功能并添加相应特性等。

更多关于Python程序员想通过示例项目学习Golang的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


我也有同样的想法;不过,我有着TCL和Perl的背景。其中一些概念超出了我目前的编程技能水平,但我相信Go语言——特别是在数组和内存管理方面——将为理解这些概念提供绝佳的示例。

如果你从未使用过,我强烈推荐 Execism.io

其次,gophercises 提供了 20 个优质项目,这些项目会对你大有帮助。

inancgumus:

学习Go语言很容易(可以看看Go语言之旅),但之后就没那么简单了

为什么?能详细说明一下吗?是因为Go语言的惯用法还是像通道这样的特性?

这可能是你会犯的错误之一。学习Go语言很容易(可以看看Go语言指南),但之后就没那么简单了。我见过很多资深程序员在使用Go时碰壁,仅仅因为他们认为自己已经掌握了基本语法。

不过话说回来,如果你想自学的话,可以去Github上看看那些优秀的Go项目找找感觉。阅读它们的源代码,尝试为这些项目做贡献。

对于有Python背景的程序员来说,通过实际项目学习Go语言是个很好的方式。以下是一些适合的示例项目,每个都展示了Go语言的特性和最佳实践:

1. RESTful API 服务

创建一个简单的用户管理API,展示Go的HTTP处理、JSON序列化和结构体使用:

package main

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"strconv"
)

type User struct {
	ID    int    `json:"id"`
	Name  string `json:"name"`
	Email string `json:"email"`
}

var users = []User{
	{ID: 1, Name: "Alice", Email: "alice@example.com"},
	{ID: 2, Name: "Bob", Email: "bob@example.com"},
}

func getUsers(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(users)
}

func getUserByID(w http.ResponseWriter, r *http.Request) {
	idStr := r.URL.Query().Get("id")
	id, err := strconv.Atoi(idStr)
	if err != nil {
		http.Error(w, "Invalid ID", http.StatusBadRequest)
		return
	}

	for _, user := range users {
		if user.ID == id {
			w.Header().Set("Content-Type", "application/json")
			json.NewEncoder(w).Encode(user)
			return
		}
	}
	http.Error(w, "User not found", http.StatusNotFound)
}

func main() {
	http.HandleFunc("/users", getUsers)
	http.HandleFunc("/user", getUserByID)
	
	fmt.Println("Server starting on :8080")
	log.Fatal(http.ListenAndServe(":8080", nil))
}

2. 并发文件处理器

利用Go的goroutine和channel处理文件:

package main

import (
	"bufio"
	"fmt"
	"log"
	"os"
	"sync"
)

func processFile(filename string, results chan<- string, wg *sync.WaitGroup) {
	defer wg.Done()
	
	file, err := os.Open(filename)
	if err != nil {
		results <- fmt.Sprintf("Error opening %s: %v", filename, err)
		return
	}
	defer file.Close()

	scanner := bufio.NewScanner(file)
	lineCount := 0
	for scanner.Scan() {
		lineCount++
	}
	
	if err := scanner.Err(); err != nil {
		results <- fmt.Sprintf("Error reading %s: %v", filename, err)
		return
	}
	
	results <- fmt.Sprintf("%s: %d lines", filename, lineCount)
}

func main() {
	files := []string{"file1.txt", "file2.txt", "file3.txt"}
	results := make(chan string, len(files))
	var wg sync.WaitGroup

	for _, file := range files {
		wg.Add(1)
		go processFile(file, results, &wg)
	}

	go func() {
		wg.Wait()
		close(results)
	}()

	for result := range results {
		fmt.Println(result)
	}
}

3. 简单的CLI工具

创建一个处理CSV文件的命令行工具:

package main

import (
	"encoding/csv"
	"flag"
	"fmt"
	"os"
	"strconv"
)

type Employee struct {
	Name string
	Age  int
	Role string
}

func readCSV(filename string) ([]Employee, error) {
	file, err := os.Open(filename)
	if err != nil {
		return nil, err
	}
	defer file.Close()

	reader := csv.NewReader(file)
	records, err := reader.ReadAll()
	if err != nil {
		return nil, err
	}

	var employees []Employee
	for i, record := range records {
		if i == 0 {
			continue // Skip header
		}
		
		age, _ := strconv.Atoi(record[1])
		employees = append(employees, Employee{
			Name: record[0],
			Age:  age,
			Role: record[2],
		})
	}
	
	return employees, nil
}

func main() {
	filename := flag.String("file", "employees.csv", "CSV file to process")
	filterRole := flag.String("role", "", "Filter by role")
	flag.Parse()

	employees, err := readCSV(*filename)
	if err != nil {
		fmt.Printf("Error reading file: %v\n", err)
		os.Exit(1)
	}

	fmt.Printf("Found %d employees\n", len(employees))
	
	if *filterRole != "" {
		fmt.Printf("Filtering by role: %s\n", *filterRole)
		for _, emp := range employees {
			if emp.Role == *filterRole {
				fmt.Printf("- %s (Age: %d)\n", emp.Name, emp.Age)
			}
		}
	}
}

4. 简单的Web爬虫

展示Go的并发特性和HTTP客户端:

package main

import (
	"fmt"
	"io"
	"net/http"
	"strings"
	"sync"
	"time"
)

func fetchURL(url string, wg *sync.WaitGroup, results chan<- string) {
	defer wg.Done()
	
	client := &http.Client{Timeout: 10 * time.Second}
	resp, err := client.Get(url)
	if err != nil {
		results <- fmt.Sprintf("Error fetching %s: %v", url, err)
		return
	}
	defer resp.Body.Close()

	body, err := io.ReadAll(resp.Body)
	if err != nil {
		results <- fmt.Sprintf("Error reading %s: %v", url, err)
		return
	}

	content := string(body)
	titleStart := strings.Index(content, "<title>")
	titleEnd := strings.Index(content, "</title>")
	
	var title string
	if titleStart != -1 && titleEnd != -1 && titleEnd > titleStart {
		title = content[titleStart+7 : titleEnd]
	} else {
		title = "No title found"
	}
	
	results <- fmt.Sprintf("%s: %s (Status: %d)", url, title, resp.StatusCode)
}

func main() {
	urls := []string{
		"https://httpbin.org/json",
		"https://httpbin.org/xml",
		"https://httpbin.org/html",
	}

	results := make(chan string, len(urls))
	var wg sync.WaitGroup

	for _, url := range urls {
		wg.Add(1)
		go fetchURL(url, &wg, results)
	}

	go func() {
		wg.Wait()
		close(results)
	}()

	for result := range results {
		fmt.Println(result)
	}
}

这些项目涵盖了Go语言的核心特性:结构体、接口、并发、错误处理和标准库的使用。从简单的API开始,逐步尝试更复杂的并发项目,能够有效学习Go语言的编程模式。

回到顶部