golang 官方代码 汇总
go1.22.2
--
序章
golang 官网的 代码汇总,汇总到一起,方便查阅。
注,如有侵权,请通知我 处理🥂。
go.dev 首页
同 https://golang.google.cn 首页。
说明,go.dev 访问时,可能存在访问失败的情况。
搜索:Try Go
package main
import "fmt"
func main() {
fmt.Println("Hello, 世界")
}
// An implementation of Conway's Game of Life.
package main
import (
"bytes"
"fmt"
"math/rand"
"time"
)
// Field represents a two-dimensional field of cells.
type Field struct {
s [][]bool
w, h int
}
// NewField returns an empty field of the specified width and height.
func NewField(w, h int) *Field {
s := make([][]bool, h)
for i := range s {
s[i] = make([]bool, w)
}
return &Field{s: s, w: w, h: h}
}
// Set sets the state of the specified cell to the given value.
func (f *Field) Set(x, y int, b bool) {
f.s[y][x] = b
}
// Alive reports whether the specified cell is alive.
// If the x or y coordinates are outside the field boundaries they are wrapped
// toroidally. For instance, an x value of -1 is treated as width-1.
func (f *Field) Alive(x, y int) bool {
x += f.w
x %= f.w
y += f.h
y %= f.h
return f.s[y][x]
}
// Next returns the state of the specified cell at the next time step.
func (f *Field) Next(x, y int) bool {
// Count the adjacent cells that are alive.
alive := 0
for i := -1; i <= 1; i++ {
for j := -1; j <= 1; j++ {
if (j != 0 || i != 0) && f.Alive(x+i, y+j) {
alive++
}
}
}
// Return next state according to the game rules:
// exactly 3 neighbors: on,
// exactly 2 neighbors: maintain current state,
// otherwise: off.
return alive == 3 || alive == 2 && f.Alive(x, y)
}
// Life stores the state of a round of Conway's Game of Life.
type Life struct {
a, b *Field
w, h int
}
// NewLife returns a new Life game state with a random initial state.
func NewLife(w, h int) *Life {
a := NewField(w, h)
for i := 0; i < (w * h / 4); i++ {
a.Set(rand.Intn(w), rand.Intn(h), true)
}
return &Life{
a: a, b: NewField(w, h),
w: w, h: h,
}
}
// Step advances the game by one instant, recomputing and updating all cells.
func (l *Life) Step() {
// Update the state of the next field (b) from the current field (a).
for y := 0; y < l.h; y++ {
for x := 0; x < l.w; x++ {
l.b.Set(x, y, l.a.Next(x, y))
}
}
// Swap fields a and b.
l.a, l.b = l.b, l.a
}
// String returns the game board as a string.
func (l *Life) String() string {
var buf bytes.Buffer
for y := 0; y < l.h; y++ {
for x := 0; x < l.w; x++ {
b := byte(' ')
if l.a.Alive(x, y) {
b = '*'
}
buf.WriteByte(b)
}
buf.WriteByte('\n')
}
return buf.String()
}
func main() {
l := NewLife(40, 15)
for i := 0; i < 300; i++ {
l.Step()
fmt.Print("\x0c", l) // Clear screen and print field.
time.Sleep(time.Second / 30)
}
}
package main
import "fmt"
// fib returns a function that returns
// successive Fibonacci numbers.
func fib() func() int {
a, b := 0, 1
return func() int {
a, b = b, a+b
return a
}
}
func main() {
f := fib()
// Function calls are evaluated left-to-right.
fmt.Println(f(), f(), f(), f(), f())
}
// This program demonstrates that Go's automatic
// stack management can handle heavily recursive
// computations.
package main
import "fmt"
// Number is a pointer to a Number
type Number *Number
// The arithmetic value of a Number is the
// count of the nodes comprising the list.
// (See the count function below.)
// -------------------------------------
// Peano primitives
func zero() *Number {
return nil
}
func isZero(x *Number) bool {
return x == nil
}
func add1(x *Number) *Number {
e := new(Number)
*e = x
return e
}
func sub1(x *Number) *Number {
return *x
}
func add(x, y *Number) *Number {
if isZero(y) {
return x
}
return add(add1(x), sub1(y))
}
func mul(x, y *Number) *Number {
if isZero(x) || isZero(y) {
return zero()
}
return add(mul(x, sub1(y)), x)
}
func fact(n *Number) *Number {
if isZero(n) {
return add1(zero())
}
return mul(fact(sub1(n)), n)
}
// -------------------------------------
// Helpers to generate/count Peano integers
func gen(n int) *Number {
if n > 0 {
return add1(gen(n - 1))
}
return zero()
}
func count(x *Number) int {
if isZero(x) {
return 0
}
return count(sub1(x)) + 1
}
// -------------------------------------
// Print i! for i in [0,9]
func main() {
for i := 0; i <= 9; i++ {
f := count(fact(gen(i)))
fmt.Println(i, "! =", f)
}
}
// Concurrent computation of pi.
// The implementation uses the Nilakantha Series.
//
// This demonstrates Go's ability to handle
// large numbers of concurrent processes.
// It is an unreasonable way to calculate pi.
package main
import (
"fmt"
"math"
)
func main() {
fmt.Println(" math.Pi:", math.Pi)
fmt.Println("Nilakantha Series:", pi(5000))
}
// pi launches n goroutines to compute an
// approximation of pi.
func pi(n int) float64 {
ch := make(chan float64)
for k := 0; k < n; k++ {
go term(ch, float64(k))
}
f := 3.0
for k := 0; k < n; k++ {
f += <-ch
}
return f
}
func term(ch chan float64, k float64) {
ch <- 4 * math.Pow(-1, k) / ((2*k + 2) * (2*k + 3) * (2*k + 4))
}
// A concurrent prime sieve
package main
import "fmt"
// Send the sequence 2, 3, 4, ... to channel 'ch'.
func Generate(ch chan<- int) {
for i := 2; ; i++ {
ch <- i // Send 'i' to channel 'ch'.
}
}
// Copy the values from channel 'in' to channel 'out',
// removing those divisible by 'prime'.
func Filter(in <-chan int, out chan<- int, prime int) {
for {
i := <-in // Receive value from 'in'.
if i%prime != 0 {
out <- i // Send 'i' to 'out'.
}
}
}
// The prime sieve: Daisy-chain Filter processes.
func main() {
ch := make(chan int) // Create a new channel.
go Generate(ch) // Launch Generate goroutine.
for i := 0; i < 10; i++ {
prime := <-ch
fmt.Println(prime)
ch1 := make(chan int)
go Filter(ch, ch1, prime)
ch = ch1
}
}
// This program solves the (English) peg
// solitaire board game.
// http://en.wikipedia.org/wiki/Peg_solitaire
package main
import "fmt"
const N = 11 + 1 // length of a row (+1 for \n)
// The board must be surrounded by 2 illegal
// fields in each direction so that move()
// doesn't need to check the board boundaries.
// Periods represent illegal fields,
// ● are pegs, and ○ are holes.
var board = []rune(
`...........
...........
....●●●....
....●●●....
..●●●●●●●..
..●●●○●●●..
..●●●●●●●..
....●●●....
....●●●....
...........
...........
`)
// center is the position of the center hole if
// there is a single one; otherwise it is -1.
var center int
func init() {
n := 0
for pos, field := range board {
if field == '○' {
center = pos
n++
}
}
if n != 1 {
center = -1 // no single hole
}
}
var moves int // number of times move is called
// move tests if there is a peg at position pos that
// can jump over another peg in direction dir. If the
// move is valid, it is executed and move returns true.
// Otherwise, move returns false.
func move(pos, dir int) bool {
moves++
if board[pos] == '●' && board[pos+dir] == '●' && board[pos+2*dir] == '○' {
board[pos] = '○'
board[pos+dir] = '○'
board[pos+2*dir] = '●'
return true
}
return false
}
// unmove reverts a previously executed valid move.
func unmove(pos, dir int) {
board[pos] = '●'
board[pos+dir] = '●'
board[pos+2*dir] = '○'
}
// solve tries to find a sequence of moves such that
// there is only one peg left at the end; if center is
// >= 0, that last peg must be in the center position.
// If a solution is found, solve prints the board after
// each move in a backward fashion (i.e., the last
// board position is printed first, all the way back to
// the starting board position).
func solve() bool {
var last, n int
for pos, field := range board {
// try each board position
if field == '●' {
// found a peg
for _, dir := range [...]int{-1, -N, +1, +N} {
// try each direction
if move(pos, dir) {
// a valid move was found and executed,
// see if this new board has a solution
if solve() {
unmove(pos, dir)
fmt.Println(string(board))
return true
}
unmove(pos, dir)
}
}
last = pos
n++
}
}
// tried each possible move
if n == 1 && (center < 0 || last == center) {
// there's only one peg left
fmt.Println(string(board))
return true
}
// no solution found for this board
return false
}
func main() {
if !solve() {
fmt.Println("no solution found")
}
fmt.Println(moves, "moves tried")
}
// Go's concurrency primitives make it easy to
// express concurrent concepts, such as
// this binary tree comparison.
//
// Trees may be of different shapes,
// but have the same contents. For example:
//
// 4 6
// 2 6 4 7
// 1 3 5 7 2 5
// 1 3
//
// This program compares a pair of trees by
// walking each in its own goroutine,
// sending their contents through a channel
// to a third goroutine that compares them.
package main
import (
"fmt"
"math/rand"
)
// A Tree is a binary tree with integer values.
type Tree struct {
Left *Tree
Value int
Right *Tree
}
// Walk traverses a tree depth-first,
// sending each Value on a channel.
func Walk(t *Tree, ch chan int) {
if t == nil {
return
}
Walk(t.Left, ch)
ch <- t.Value
Walk(t.Right, ch)
}
// Walker launches Walk in a new goroutine,
// and returns a read-only channel of values.
func Walker(t *Tree) <-chan int {
ch := make(chan int)
go func() {
Walk(t, ch)
close(ch)
}()
return ch
}
// Compare reads values from two Walkers
// that run simultaneously, and returns true
// if t1 and t2 have the same contents.
func Compare(t1, t2 *Tree) bool {
c1, c2 := Walker(t1), Walker(t2)
for {
v1, ok1 := <-c1
v2, ok2 := <-c2
if !ok1 || !ok2 {
return ok1 == ok2
}
if v1 != v2 {
break
}
}
return false
}
// New returns a new, random binary tree
// holding the values 1k, 2k, ..., nk.
func New(n, k int) *Tree {
var t *Tree
for _, v := range rand.Perm(n) {
t = insert(t, (1+v)*k)
}
return t
}
func insert(t *Tree, v int) *Tree {
if t == nil {
return &Tree{nil, v, nil}
}
if v < t.Value {
t.Left = insert(t.Left, v)
return t
}
t.Right = insert(t.Right, v)
return t
}
func main() {
t1 := New(100, 1)
fmt.Println(Compare(t1, New(100, 1)), "Same Contents")
fmt.Println(Compare(t1, New(99, 1)), "Differing Sizes")
fmt.Println(Compare(t1, New(100, 2)), "Differing Values")
fmt.Println(Compare(t1, New(101, 2)), "Dissimilar")
}
Go Tutorials
https://golang.google.cn/doc/tutorial/
注,其中 【Create a module】 下有多个页面。
Getting started
package main
import "fmt"
func main() {
fmt.Println("Hello, World!")
}
package main
import "fmt"
import "rsc.io/quote"
func main() {
fmt.Println(quote.Go())
}
Create a module
package greetings
import "fmt"
// Hello returns a greeting for the named person.
func Hello(name string) string {
// Return a greeting that embeds the name in a message.
message := fmt.Sprintf("Hi, %v. Welcome!", name)
return message
}
package main
import (
"fmt"
"example.com/greetings"
)
func main() {
// Get a greeting message and print it.
message := greetings.Hello("Gladys")
fmt.Println(message)
}
package greetings
import (
"errors"
"fmt"
)
// Hello returns a greeting for the named person.
func Hello(name string) (string, error) {
// If no name was given, return an error with a message.
if name == "" {
return "", errors.New("empty name")
}
// If a name was received, return a value that embeds the name
// in a greeting message.
message := fmt.Sprintf("Hi, %v. Welcome!", name)
return message, nil
}
package main
import (
"fmt"
"log"
"example.com/greetings"
)
func main() {
// Set properties of the predefined Logger, including
// the log entry prefix and a flag to disable printing
// the time, source file, and line number.
log.SetPrefix("greetings: ")
log.SetFlags(0)
// Request a greeting message.
message, err := greetings.Hello("")
// If an error was returned, print it to the console and
// exit the program.
if err != nil {
log.Fatal(err)
}
// If no error was returned, print the returned message
// to the console.
fmt.Println(message)
}
package greetings
import (
"errors"
"fmt"
"math/rand"
)
// Hello returns a greeting for the named person.
func Hello(name string) (string, error) {
// If no name was given, return an error with a message.
if name == "" {
return name, errors.New("empty name")
}
// Create a message using a random format.
message := fmt.Sprintf(randomFormat(), name)
return message, nil
}
// randomFormat returns one of a set of greeting messages. The returned
// message is selected at random.
func randomFormat() string {
// A slice of message formats.
formats := []string{
"Hi, %v. Welcome!",
"Great to see you, %v!",
"Hail, %v! Well met!",
}
// Return a randomly selected message format by specifying
// a random index for the slice of formats.
return formats[rand.Intn(len(formats))]
}
package main
import (
"fmt"
"log"
"example.com/greetings"
)
func main() {
// Set properties of the predefined Logger, including
// the log entry prefix and a flag to disable printing
// the time, source file, and line number.
log.SetPrefix("greetings: ")
log.SetFlags(0)
// Request a greeting message.
message, err := greetings.Hello("Gladys")
// If an error was returned, print it to the console and
// exit the program.
if err != nil {
log.Fatal(err)
}
// If no error was returned, print the returned message
// to the console.
fmt.Println(message)
}
package greetings
import (
"errors"
"fmt"
"math/rand"
)
// Hello returns a greeting for the named person.
func Hello(name string) (string, error) {
// If no name was given, return an error with a message.
if name == "" {
return name, errors.New("empty name")
}
// Create a message using a random format.
message := fmt.Sprintf(randomFormat(), name)
return message, nil
}
// Hellos returns a map that associates each of the named people
// with a greeting message.
func Hellos(names []string) (map[string]string, error) {
// A map to associate names with messages.
messages := make(map[string]string)
// Loop through the received slice of names, calling
// the Hello function to get a message for each name.
for _, name := range names {
message, err := Hello(name)
if err != nil {
return nil, err
}
// In the map, associate the retrieved message with
// the name.
messages[name] = message
}
return messages, nil
}
// randomFormat returns one of a set of greeting messages. The returned
// message is selected at random.
func randomFormat() string {
// A slice of message formats.
formats := []string{
"Hi, %v. Welcome!",
"Great to see you, %v!",
"Hail, %v! Well met!",
}
// Return one of the message formats selected at random.
return formats[rand.Intn(len(formats))]
}
package main
import (
"fmt"
"log"
"example.com/greetings"
)
func main() {
// Set properties of the predefined Logger, including
// the log entry prefix and a flag to disable printing
// the time, source file, and line number.
log.SetPrefix("greetings: ")
log.SetFlags(0)
// A slice of names.
names := []string{"Gladys", "Samantha", "Darrin"}
// Request greeting messages for the names.
messages, err := greetings.Hellos(names)
if err != nil {
log.Fatal(err)
}
// If no error was returned, print the returned map of
// messages to the console.
fmt.Println(messages)
}
Add a test
package greetings
import (
"testing"
"regexp"
)
// TestHelloName calls greetings.Hello with a name, checking
// for a valid return value.
func TestHelloName(t *testing.T) {
name := "Gladys"
want := regexp.MustCompile(`\b`+name+`\b`)
msg, err := Hello("Gladys")
if !want.MatchString(msg) || err != nil {
t.Fatalf(`Hello("Gladys") = %q, %v, want match for %#q, nil`, msg, err, want)
}
}
// TestHelloEmpty calls greetings.Hello with an empty string,
// checking for an error.
func TestHelloEmpty(t *testing.T) {
msg, err := Hello("")
if msg != "" || err == nil {
t.Fatalf(`Hello("") = %q, %v, want "", error`, msg, err)
}
}
// Hello returns a greeting for the named person.
func Hello(name string) (string, error) {
// If no name was given, return an error with a message.
if name == "" {
return name, errors.New("empty name")
}
// Create a message using a random format.
// message := fmt.Sprintf(randomFormat(), name)
message := fmt.Sprint(randomFormat())
return message, nil
}
Getting started with multi-module workspaces
package main
import (
"fmt"
"golang.org/x/example/hello/reverse"
)
func main() {
fmt.Println(reverse.String("Hello"))
}
package reverse
import "strconv"
// Int returns the decimal reversal of the integer i.
func Int(i int) int {
i, _ = strconv.Atoi(String(strconv.Itoa(i)))
return i
}
package main
import (
"fmt"
"golang.org/x/example/hello/reverse"
)
func main() {
fmt.Println(reverse.String("Hello"), reverse.Int(24601))
}
Accessing a relational database
# mysql
var db *sql.DB
func main() {
// Capture connection properties.
cfg := mysql.Config{
User: os.Getenv("DBUSER"),
Passwd: os.Getenv("DBPASS"),
Net: "tcp",
Addr: "127.0.0.1:3306",
DBName: "recordings",
}
// Get a database handle.
var err error
db, err = sql.Open("mysql", cfg.FormatDSN())
if err != nil {
log.Fatal(err)
}
pingErr := db.Ping()
if pingErr != nil {
log.Fatal(pingErr)
}
fmt.Println("Connected!")
}
package main
import (
"database/sql"
"fmt"
"log"
"os"
"github.com/go-sql-driver/mysql"
)
完整代码 Completed code
package main
import (
"database/sql"
"fmt"
"log"
"os"
"github.com/go-sql-driver/mysql"
)
var db *sql.DB
type Album struct {
ID int64
Title string
Artist string
Price float32
}
func main() {
// Capture connection properties.
cfg := mysql.Config{
User: os.Getenv("DBUSER"),
Passwd: os.Getenv("DBPASS"),
Net: "tcp",
Addr: "127.0.0.1:3306",
DBName: "recordings",
}
// Get a database handle.
var err error
db, err = sql.Open("mysql", cfg.FormatDSN())
if err != nil {
log.Fatal(err)
}
pingErr := db.Ping()
if pingErr != nil {
log.Fatal(pingErr)
}
fmt.Println("Connected!")
albums, err := albumsByArtist("John Coltrane")
if err != nil {
log.Fatal(err)
}
fmt.Printf("Albums found: %v\n", albums)
// Hard-code ID 2 here to test the query.
alb, err := albumByID(2)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Album found: %v\n", alb)
albID, err := addAlbum(Album{
Title: "The Modern Sound of Betty Carter",
Artist: "Betty Carter",
Price: 49.99,
})
if err != nil {
log.Fatal(err)
}
fmt.Printf("ID of added album: %v\n", albID)
}
// albumsByArtist queries for albums that have the specified artist name.
func albumsByArtist(name string) ([]Album, error) {
// An albums slice to hold data from returned rows.
var albums []Album
rows, err := db.Query("SELECT * FROM album WHERE artist = ?", name)
if err != nil {
return nil, fmt.Errorf("albumsByArtist %q: %v", name, err)
}
defer rows.Close()
// Loop through rows, using Scan to assign column data to struct fields.
for rows.Next() {
var alb Album
if err := rows.Scan(&alb.ID, &alb.Title, &alb.Artist, &alb.Price); err != nil {
return nil, fmt.Errorf("albumsByArtist %q: %v", name, err)
}
albums = append(albums, alb)
}
if err := rows.Err(); err != nil {
return nil, fmt.Errorf("albumsByArtist %q: %v", name, err)
}
return albums, nil
}
// albumByID queries for the album with the specified ID.
func albumByID(id int64) (Album, error) {
// An album to hold data from the returned row.
var alb Album
row := db.QueryRow("SELECT * FROM album WHERE id = ?", id)
if err := row.Scan(&alb.ID, &alb.Title, &alb.Artist, &alb.Price); err != nil {
if err == sql.ErrNoRows {
return alb, fmt.Errorf("albumsById %d: no such album", id)
}
return alb, fmt.Errorf("albumsById %d: %v", id, err)
}
return alb, nil
}
// addAlbum adds the specified album to the database,
// returning the album ID of the new entry
func addAlbum(alb Album) (int64, error) {
result, err := db.Exec("INSERT INTO album (title, artist, price) VALUES (?, ?, ?)", alb.Title, alb.Artist, alb.Price)
if err != nil {
return 0, fmt.Errorf("addAlbum: %v", err)
}
id, err := result.LastInsertId()
if err != nil {
return 0, fmt.Errorf("addAlbum: %v", err)
}
return id, nil
}
Developing a RESTful API with Go and Gin
完整代码 Completed code
package main
import (
"net/http"
"github.com/gin-gonic/gin"
)
// album represents data about a record album.
type album struct {
ID string `json:"id"`
Title string `json:"title"`
Artist string `json:"artist"`
Price float64 `json:"price"`
}
// albums slice to seed record album data.
var albums = []album{
{ID: "1", Title: "Blue Train", Artist: "John Coltrane", Price: 56.99},
{ID: "2", Title: "Jeru", Artist: "Gerry Mulligan", Price: 17.99},
{ID: "3", Title: "Sarah Vaughan and Clifford Brown", Artist: "Sarah Vaughan", Price: 39.99},
}
func main() {
router := gin.Default()
router.GET("/albums", getAlbums)
router.GET("/albums/:id", getAlbumByID)
router.POST("/albums", postAlbums)
router.Run("localhost:8080")
}
// getAlbums responds with the list of all albums as JSON.
func getAlbums(c *gin.Context) {
c.IndentedJSON(http.StatusOK, albums)
}
// postAlbums adds an album from JSON received in the request body.
func postAlbums(c *gin.Context) {
var newAlbum album
// Call BindJSON to bind the received JSON to
// newAlbum.
if err := c.BindJSON(&newAlbum); err != nil {
return
}
// Add the new album to the slice.
albums = append(albums, newAlbum)
c.IndentedJSON(http.StatusCreated, newAlbum)
}
// getAlbumByID locates the album whose ID value matches the id
// parameter sent by the client, then returns that album as a response.
func getAlbumByID(c *gin.Context) {
id := c.Param("id")
// Loop through the list of albums, looking for
// an album whose ID value matches the parameter.
for _, a := range albums {
if a.ID == id {
c.IndentedJSON(http.StatusOK, a)
return
}
}
c.IndentedJSON(http.StatusNotFound, gin.H{"message": "album not found"})
}
Getting started with generics
# 泛型
完整代码 Completed code
package main
import "fmt"
type Number interface {
int64 | float64
}
func main() {
// Initialize a map for the integer values
ints := map[string]int64{
"first": 34,
"second": 12,
}
// Initialize a map for the float values
floats := map[string]float64{
"first": 35.98,
"second": 26.99,
}
fmt.Printf("Non-Generic Sums: %v and %v\n",
SumInts(ints),
SumFloats(floats))
fmt.Printf("Generic Sums: %v and %v\n",
SumIntsOrFloats[string, int64](ints),
SumIntsOrFloats[string, float64](floats))
fmt.Printf("Generic Sums, type parameters inferred: %v and %v\n",
SumIntsOrFloats(ints),
SumIntsOrFloats(floats))
fmt.Printf("Generic Sums with Constraint: %v and %v\n",
SumNumbers(ints),
SumNumbers(floats))
}
// SumInts adds together the values of m.
func SumInts(m map[string]int64) int64 {
var s int64
for _, v := range m {
s += v
}
return s
}
// SumFloats adds together the values of m.
func SumFloats(m map[string]float64) float64 {
var s float64
for _, v := range m {
s += v
}
return s
}
// SumIntsOrFloats sums the values of map m. It supports both floats and integers
// as map values.
func SumIntsOrFloats[K comparable, V int64 | float64](m map[K]V) V {
var s V
for _, v := range m {
s += v
}
return s
}
// SumNumbers sums the values of map m. Its supports both integers
// and floats as map values.
func SumNumbers[K comparable, V Number](m map[K]V) V {
var s V
for _, v := range m {
s += v
}
return s
}
Getting started with fuzzing
完整代码 Completed code
// main.go
package main
import (
"errors"
"fmt"
"unicode/utf8"
)
func main() {
input := "The quick brown fox jumped over the lazy dog"
rev, revErr := Reverse(input)
doubleRev, doubleRevErr := Reverse(rev)
fmt.Printf("original: %q\n", input)
fmt.Printf("reversed: %q, err: %v\n", rev, revErr)
fmt.Printf("reversed again: %q, err: %v\n", doubleRev, doubleRevErr)
}
func Reverse(s string) (string, error) {
if !utf8.ValidString(s) {
return s, errors.New("input is not valid UTF-8")
}
r := []rune(s)
for i, j := 0, len(r)-1; i < len(r)/2; i, j = i+1, j-1 {
r[i], r[j] = r[j], r[i]
}
return string(r), nil
}
// reverse_test.go
package main
import (
"testing"
"unicode/utf8"
)
func FuzzReverse(f *testing.F) {
testcases := []string{"Hello, world", " ", "!12345"}
for _, tc := range testcases {
f.Add(tc) // Use f.Add to provide a seed corpus
}
f.Fuzz(func(t *testing.T, orig string) {
rev, err1 := Reverse(orig)
if err1 != nil {
return
}
doubleRev, err2 := Reverse(rev)
if err2 != nil {
return
}
if orig != doubleRev {
t.Errorf("Before: %q, after: %q", orig, doubleRev)
}
if utf8.ValidString(orig) && !utf8.ValidString(rev) {
t.Errorf("Reverse produced invalid UTF-8 string %q", rev)
}
})
}
Getting started with govulncheck
漏洞 检测 和 修复
命令 $ mkdir vuln-tutorial $ go install golang.org/x/vuln/cmd/govulncheck@latest $ govulncheck ./... |
测试代码:
// main.go
package main
import (
"fmt"
"os"
"golang.org/x/text/language"
)
func main() {
for _, arg := range os.Args[1:] {
tag, err := language.Parse(arg)
if err != nil {
fmt.Printf("%s: error: %v\n", arg, err)
} else if tag == language.Und {
fmt.Printf("%s: undefined\n", arg)
} else {
fmt.Printf("%s: tag %s\n", arg, tag)
}
}
}
Find and fix vulnerable dependencies with VS Code Go
测试代码 同上
Go Web Examples
Web 开发相关 示例。
Hello World
package main
import (
"fmt"
"net/http"
)
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello, you've requested: %s\n", r.URL.Path)
})
http.ListenAndServe(":80", nil)
}
HTTP Server
https://gowebexamples.com/http-server/
package main
import (
"fmt"
"net/http"
)
func main() {
http.HandleFunc("/", func (w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Welcome to my website!")
})
fs := http.FileServer(http.Dir("static/"))
http.Handle("/static/", http.StripPrefix("/static/", fs))
http.ListenAndServe(":80", nil)
}
Routing (using gorilla/mux)
https://gowebexamples.com/routes-using-gorilla-mux/
go get -u github.com/gorilla/mux |
package main
import (
"fmt"
"net/http"
"github.com/gorilla/mux"
)
func main() {
r := mux.NewRouter()
r.HandleFunc("/books/{title}/page/{page}", func(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
title := vars["title"]
page := vars["page"]
fmt.Fprintf(w, "You've requested the book: %s on page %s\n", title, page)
})
http.ListenAndServe(":80", r)
}
// Restrict the request handler to specific HTTP methods.
r.HandleFunc("/books/{title}", CreateBook).Methods("POST")
r.HandleFunc("/books/{title}", ReadBook).Methods("GET")
r.HandleFunc("/books/{title}", UpdateBook).Methods("PUT")
r.HandleFunc("/books/{title}", DeleteBook).Methods("DELETE")
// Restrict the request handler to specific hostnames or subdomains.
r.HandleFunc("/books/{title}", BookHandler).Host("www.mybookstore.com")
// Restrict the request handler to http/https.
r.HandleFunc("/secure", SecureHandler).Schemes("https")
r.HandleFunc("/insecure", InsecureHandler).Schemes("http")
// Restrict the request handler to specific path prefixes.
bookrouter := r.PathPrefix("/books").Subrouter()
bookrouter.HandleFunc("/", AllBooks)
bookrouter.HandleFunc("/{title}", GetBook)
MySQL Database
https://gowebexamples.com/mysql-database/
go get -u github.com/go-sql-driver/mysql |
package main
import (
"database/sql"
"fmt"
"log"
"time"
_ "github.com/go-sql-driver/mysql"
)
func main() {
db, err := sql.Open("mysql", "root:root@(127.0.0.1:3306)/root?parseTime=true")
if err != nil {
log.Fatal(err)
}
if err := db.Ping(); err != nil {
log.Fatal(err)
}
{ // Create a new table
query := `
CREATE TABLE users (
id INT AUTO_INCREMENT,
username TEXT NOT NULL,
password TEXT NOT NULL,
created_at DATETIME,
PRIMARY KEY (id)
);`
if _, err := db.Exec(query); err != nil {
log.Fatal(err)
}
}
{ // Insert a new user
username := "johndoe"
password := "secret"
createdAt := time.Now()
result, err := db.Exec(`INSERT INTO users (username, password, created_at) VALUES (?, ?, ?)`, username, password, createdAt)
if err != nil {
log.Fatal(err)
}
id, err := result.LastInsertId()
fmt.Println(id)
}
{ // Query a single user
var (
id int
username string
password string
createdAt time.Time
)
query := "SELECT id, username, password, created_at FROM users WHERE id = ?"
if err := db.QueryRow(query, 1).Scan(&id, &username, &password, &createdAt); err != nil {
log.Fatal(err)
}
fmt.Println(id, username, password, createdAt)
}
{ // Query all users
type user struct {
id int
username string
password string
createdAt time.Time
}
rows, err := db.Query(`SELECT id, username, password, created_at FROM users`)
if err != nil {
log.Fatal(err)
}
defer rows.Close()
var users []user
for rows.Next() {
var u user
err := rows.Scan(&u.id, &u.username, &u.password, &u.createdAt)
if err != nil {
log.Fatal(err)
}
users = append(users, u)
}
if err := rows.Err(); err != nil {
log.Fatal(err)
}
fmt.Printf("%#v", users)
}
{
_, err := db.Exec(`DELETE FROM users WHERE id = ?`, 1)
if err != nil {
log.Fatal(err)
}
}
}
Templates - 略
Assets and Files
https://gowebexamples.com/static-files/
// static-files.go
package main
import "net/http"
func main() {
fs := http.FileServer(http.Dir("assets/"))
http.Handle("/static/", http.StripPrefix("/static/", fs))
http.ListenAndServe(":8080", nil)
}
Forms
https://gowebexamples.com/forms/
// forms.go
package main
import (
"html/template"
"net/http"
)
type ContactDetails struct {
Email string
Subject string
Message string
}
func main() {
tmpl := template.Must(template.ParseFiles("forms.html"))
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
tmpl.Execute(w, nil)
return
}
details := ContactDetails{
Email: r.FormValue("email"),
Subject: r.FormValue("subject"),
Message: r.FormValue("message"),
}
// do something with details
_ = details
tmpl.Execute(w, struct{ Success bool }{true})
})
http.ListenAndServe(":8080", nil)
}
Middleware (Basic)
https://gowebexamples.com/basic-middleware/
// basic-middleware.go
package main
import (
"fmt"
"log"
"net/http"
)
func logging(f http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
log.Println(r.URL.Path)
f(w, r)
}
}
func foo(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "foo")
}
func bar(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "bar")
}
func main() {
http.HandleFunc("/foo", logging(foo))
http.HandleFunc("/bar", logging(bar))
http.ListenAndServe(":8080", nil)
}
Middleware (Advanced)
https://gowebexamples.com/advanced-middleware/
// advanced-middleware.go
package main
import (
"fmt"
"log"
"net/http"
"time"
)
type Middleware func(http.HandlerFunc) http.HandlerFunc
// Logging logs all requests with its path and the time it took to process
func Logging() Middleware {
// Create a new Middleware
return func(f http.HandlerFunc) http.HandlerFunc {
// Define the http.HandlerFunc
return func(w http.ResponseWriter, r *http.Request) {
// Do middleware things
start := time.Now()
defer func() { log.Println(r.URL.Path, time.Since(start)) }()
// Call the next middleware/handler in chain
f(w, r)
}
}
}
// Method ensures that url can only be requested with a specific method, else returns a 400 Bad Request
func Method(m string) Middleware {
// Create a new Middleware
return func(f http.HandlerFunc) http.HandlerFunc {
// Define the http.HandlerFunc
return func(w http.ResponseWriter, r *http.Request) {
// Do middleware things
if r.Method != m {
http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
return
}
// Call the next middleware/handler in chain
f(w, r)
}
}
}
// Chain applies middlewares to a http.HandlerFunc
func Chain(f http.HandlerFunc, middlewares ...Middleware) http.HandlerFunc {
for _, m := range middlewares {
f = m(f)
}
return f
}
func Hello(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "hello world")
}
func main() {
http.HandleFunc("/", Chain(Hello, Method("GET"), Logging()))
http.ListenAndServe(":8080", nil)
}
Sessions
https://gowebexamples.com/sessions/
// sessions.go
package main
import (
"fmt"
"net/http"
"github.com/gorilla/sessions"
)
var (
// key must be 16, 24 or 32 bytes long (AES-128, AES-192 or AES-256)
key = []byte("super-secret-key")
store = sessions.NewCookieStore(key)
)
func secret(w http.ResponseWriter, r *http.Request) {
session, _ := store.Get(r, "cookie-name")
// Check if user is authenticated
if auth, ok := session.Values["authenticated"].(bool); !ok || !auth {
http.Error(w, "Forbidden", http.StatusForbidden)
return
}
// Print secret message
fmt.Fprintln(w, "The cake is a lie!")
}
func login(w http.ResponseWriter, r *http.Request) {
session, _ := store.Get(r, "cookie-name")
// Authentication goes here
// ...
// Set user as authenticated
session.Values["authenticated"] = true
session.Save(r, w)
}
func logout(w http.ResponseWriter, r *http.Request) {
session, _ := store.Get(r, "cookie-name")
// Revoke users authentication
session.Values["authenticated"] = false
session.Save(r, w)
}
func main() {
http.HandleFunc("/secret", secret)
http.HandleFunc("/login", login)
http.HandleFunc("/logout", logout)
http.ListenAndServe(":8080", nil)
}
JSON
https://gowebexamples.com/json/
This example will show how to encode and decode JSON data using the encoding/json package.
// json.go
package main
import (
"encoding/json"
"fmt"
"net/http"
)
type User struct {
Firstname string `json:"firstname"`
Lastname string `json:"lastname"`
Age int `json:"age"`
}
func main() {
http.HandleFunc("/decode", func(w http.ResponseWriter, r *http.Request) {
var user User
json.NewDecoder(r.Body).Decode(&user)
fmt.Fprintf(w, "%s %s is %d years old!", user.Firstname, user.Lastname, user.Age)
})
http.HandleFunc("/encode", func(w http.ResponseWriter, r *http.Request) {
peter := User{
Firstname: "John",
Lastname: "Doe",
Age: 25,
}
json.NewEncoder(w).Encode(peter)
})
http.ListenAndServe(":8080", nil)
}
Websockets
https://gowebexamples.com/websockets/
$ go get github.com/gorilla/websocket |
// websockets.go
package main
import (
"fmt"
"net/http"
"github.com/gorilla/websocket"
)
var upgrader = websocket.Upgrader{
ReadBufferSize: 1024,
WriteBufferSize: 1024,
}
func main() {
http.HandleFunc("/echo", func(w http.ResponseWriter, r *http.Request) {
conn, _ := upgrader.Upgrade(w, r, nil) // error ignored for sake of simplicity
for {
// Read message from browser
msgType, msg, err := conn.ReadMessage()
if err != nil {
return
}
// Print the message to the console
fmt.Printf("%s sent: %s\n", conn.RemoteAddr(), string(msg))
// Write message back to browser
if err = conn.WriteMessage(msgType, msg); err != nil {
return
}
}
})
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
http.ServeFile(w, r, "websockets.html")
})
http.ListenAndServe(":8080", nil)
}
Password Hashing
https://gowebexamples.com/password-hashing/
$ go get golang.org/x/crypto/bcrypt |
// passwords.go
package main
import (
"fmt"
"golang.org/x/crypto/bcrypt"
)
func HashPassword(password string) (string, error) {
bytes, err := bcrypt.GenerateFromPassword([]byte(password), 14)
return string(bytes), err
}
func CheckPasswordHash(password, hash string) bool {
err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password))
return err == nil
}
func main() {
password := "secret"
hash, _ := HashPassword(password) // ignore error for the sake of simplicity
fmt.Println("Password:", password)
fmt.Println("Hash: ", hash)
match := CheckPasswordHash(password, hash)
fmt.Println("Match: ", match)
}
END
本文链接:
https://www.cnblogs.com/luo630/p/18169977
ben 发布于博客园
ben 发布于博客园