PPysolate SpineREAD THE CODE · UNDERSTAND THE SYSTEM
课程与章节
源码索引 / CURRENT IMPLEMENTATION

learning/go-patterns/stages/03-errors-tests/main.go

61 行 · 点击行号可定位;函数链接随声明位置更新,不手填行号。

跳到函数 / 声明
// Stage 03 adds stable error identity and tests the wrapped error chain.
// Run it with: go run .
package main

import (
	"errors"
	"fmt"
)

var ErrUnknownItem = errors.New("unknown item")
var ErrSourceUnavailable = errors.New("price source unavailable")

type Price struct {
	Item  string
	Cents int
}

type PriceSource interface {
	Lookup(item string) (Price, error)
}

type Catalog map[string]Price

func (c Catalog) Lookup(item string) (Price, error) {
	price, ok := c[item]
	if !ok {
		return Price{}, fmt.Errorf("%w: %q", ErrUnknownItem, item)
	}
	return price, nil
}

type Service struct {
	source PriceSource
}

func NewService(source PriceSource) Service {
	return Service{source: source}
}

// Quote adds operation and input context while %w preserves the cause.
func (s Service) Quote(item string) (Price, error) {
	price, err := s.source.Lookup(item)
	if err != nil {
		return Price{}, fmt.Errorf("quote %q: %w", item, err)
	}
	return price, nil
}

func main() {
	service := NewService(Catalog{"book": {Item: "book", Cents: 2100}})
	if price, err := service.Quote("book"); err != nil {
		fmt.Println("quote failed:", err)
	} else {
		fmt.Printf("%s: %d cents\n", price.Item, price.Cents)
	}

	if _, err := service.Quote("notebook"); err != nil {
		fmt.Println("wrapped error:", err)
		fmt.Println("is unknown item:", errors.Is(err, ErrUnknownItem))
	}
}