mirror of
https://github.com/gopl-zh/gopl-zh.github.com.git
synced 2025-12-18 19:54:21 +08:00
deploy: 06a1bdf735
This commit is contained in:
35
vendor/gopl.io/ch7/bytecounter/main.go
generated
vendored
Normal file
35
vendor/gopl.io/ch7/bytecounter/main.go
generated
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
// See page 173.
|
||||
|
||||
// Bytecounter demonstrates an implementation of io.Writer that counts bytes.
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
//!+bytecounter
|
||||
|
||||
type ByteCounter int
|
||||
|
||||
func (c *ByteCounter) Write(p []byte) (int, error) {
|
||||
*c += ByteCounter(len(p)) // convert int to ByteCounter
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
//!-bytecounter
|
||||
|
||||
func main() {
|
||||
//!+main
|
||||
var c ByteCounter
|
||||
c.Write([]byte("hello"))
|
||||
fmt.Println(c) // "5", = len("hello")
|
||||
|
||||
c = 0 // reset the counter
|
||||
var name = "Dolly"
|
||||
fmt.Fprintf(&c, "hello, %s", name)
|
||||
fmt.Println(c) // "12", = len("hello, Dolly")
|
||||
//!-main
|
||||
}
|
||||
40
vendor/gopl.io/ch7/eval/ast.go
generated
vendored
Normal file
40
vendor/gopl.io/ch7/eval/ast.go
generated
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
package eval
|
||||
|
||||
// An Expr is an arithmetic expression.
|
||||
type Expr interface {
|
||||
// Eval returns the value of this Expr in the environment env.
|
||||
Eval(env Env) float64
|
||||
// Check reports errors in this Expr and adds its Vars to the set.
|
||||
Check(vars map[Var]bool) error
|
||||
}
|
||||
|
||||
//!+ast
|
||||
|
||||
// A Var identifies a variable, e.g., x.
|
||||
type Var string
|
||||
|
||||
// A literal is a numeric constant, e.g., 3.141.
|
||||
type literal float64
|
||||
|
||||
// A unary represents a unary operator expression, e.g., -x.
|
||||
type unary struct {
|
||||
op rune // one of '+', '-'
|
||||
x Expr
|
||||
}
|
||||
|
||||
// A binary represents a binary operator expression, e.g., x+y.
|
||||
type binary struct {
|
||||
op rune // one of '+', '-', '*', '/'
|
||||
x, y Expr
|
||||
}
|
||||
|
||||
// A call represents a function call expression, e.g., sin(x).
|
||||
type call struct {
|
||||
fn string // one of "pow", "sin", "sqrt"
|
||||
args []Expr
|
||||
}
|
||||
|
||||
//!-ast
|
||||
58
vendor/gopl.io/ch7/eval/check.go
generated
vendored
Normal file
58
vendor/gopl.io/ch7/eval/check.go
generated
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
package eval
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
//!+Check
|
||||
|
||||
func (v Var) Check(vars map[Var]bool) error {
|
||||
vars[v] = true
|
||||
return nil
|
||||
}
|
||||
|
||||
func (literal) Check(vars map[Var]bool) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u unary) Check(vars map[Var]bool) error {
|
||||
if !strings.ContainsRune("+-", u.op) {
|
||||
return fmt.Errorf("unexpected unary op %q", u.op)
|
||||
}
|
||||
return u.x.Check(vars)
|
||||
}
|
||||
|
||||
func (b binary) Check(vars map[Var]bool) error {
|
||||
if !strings.ContainsRune("+-*/", b.op) {
|
||||
return fmt.Errorf("unexpected binary op %q", b.op)
|
||||
}
|
||||
if err := b.x.Check(vars); err != nil {
|
||||
return err
|
||||
}
|
||||
return b.y.Check(vars)
|
||||
}
|
||||
|
||||
func (c call) Check(vars map[Var]bool) error {
|
||||
arity, ok := numParams[c.fn]
|
||||
if !ok {
|
||||
return fmt.Errorf("unknown function %q", c.fn)
|
||||
}
|
||||
if len(c.args) != arity {
|
||||
return fmt.Errorf("call to %s has %d args, want %d",
|
||||
c.fn, len(c.args), arity)
|
||||
}
|
||||
for _, arg := range c.args {
|
||||
if err := arg.Check(vars); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var numParams = map[string]int{"pow": 2, "sin": 1, "sqrt": 1}
|
||||
|
||||
//!-Check
|
||||
48
vendor/gopl.io/ch7/eval/coverage_test.go
generated
vendored
Normal file
48
vendor/gopl.io/ch7/eval/coverage_test.go
generated
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
package eval
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"testing"
|
||||
)
|
||||
|
||||
//!+TestCoverage
|
||||
func TestCoverage(t *testing.T) {
|
||||
var tests = []struct {
|
||||
input string
|
||||
env Env
|
||||
want string // expected error from Parse/Check or result from Eval
|
||||
}{
|
||||
{"x % 2", nil, "unexpected '%'"},
|
||||
{"!true", nil, "unexpected '!'"},
|
||||
{"log(10)", nil, `unknown function "log"`},
|
||||
{"sqrt(1, 2)", nil, "call to sqrt has 2 args, want 1"},
|
||||
{"sqrt(A / pi)", Env{"A": 87616, "pi": math.Pi}, "167"},
|
||||
{"pow(x, 3) + pow(y, 3)", Env{"x": 9, "y": 10}, "1729"},
|
||||
{"5 / 9 * (F - 32)", Env{"F": -40}, "-40"},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
expr, err := Parse(test.input)
|
||||
if err == nil {
|
||||
err = expr.Check(map[Var]bool{})
|
||||
}
|
||||
if err != nil {
|
||||
if err.Error() != test.want {
|
||||
t.Errorf("%s: got %q, want %q", test.input, err, test.want)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
got := fmt.Sprintf("%.6g", expr.Eval(test.env))
|
||||
if got != test.want {
|
||||
t.Errorf("%s: %v => %s, want %s",
|
||||
test.input, test.env, got, test.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//!-TestCoverage
|
||||
70
vendor/gopl.io/ch7/eval/eval.go
generated
vendored
Normal file
70
vendor/gopl.io/ch7/eval/eval.go
generated
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
// See page 198.
|
||||
|
||||
// Package eval provides an expression evaluator.
|
||||
package eval
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
)
|
||||
|
||||
//!+env
|
||||
|
||||
type Env map[Var]float64
|
||||
|
||||
//!-env
|
||||
|
||||
//!+Eval1
|
||||
|
||||
func (v Var) Eval(env Env) float64 {
|
||||
return env[v]
|
||||
}
|
||||
|
||||
func (l literal) Eval(_ Env) float64 {
|
||||
return float64(l)
|
||||
}
|
||||
|
||||
//!-Eval1
|
||||
|
||||
//!+Eval2
|
||||
|
||||
func (u unary) Eval(env Env) float64 {
|
||||
switch u.op {
|
||||
case '+':
|
||||
return +u.x.Eval(env)
|
||||
case '-':
|
||||
return -u.x.Eval(env)
|
||||
}
|
||||
panic(fmt.Sprintf("unsupported unary operator: %q", u.op))
|
||||
}
|
||||
|
||||
func (b binary) Eval(env Env) float64 {
|
||||
switch b.op {
|
||||
case '+':
|
||||
return b.x.Eval(env) + b.y.Eval(env)
|
||||
case '-':
|
||||
return b.x.Eval(env) - b.y.Eval(env)
|
||||
case '*':
|
||||
return b.x.Eval(env) * b.y.Eval(env)
|
||||
case '/':
|
||||
return b.x.Eval(env) / b.y.Eval(env)
|
||||
}
|
||||
panic(fmt.Sprintf("unsupported binary operator: %q", b.op))
|
||||
}
|
||||
|
||||
func (c call) Eval(env Env) float64 {
|
||||
switch c.fn {
|
||||
case "pow":
|
||||
return math.Pow(c.args[0].Eval(env), c.args[1].Eval(env))
|
||||
case "sin":
|
||||
return math.Sin(c.args[0].Eval(env))
|
||||
case "sqrt":
|
||||
return math.Sqrt(c.args[0].Eval(env))
|
||||
}
|
||||
panic(fmt.Sprintf("unsupported function call: %s", c.fn))
|
||||
}
|
||||
|
||||
//!-Eval2
|
||||
113
vendor/gopl.io/ch7/eval/eval_test.go
generated
vendored
Normal file
113
vendor/gopl.io/ch7/eval/eval_test.go
generated
vendored
Normal file
@@ -0,0 +1,113 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
package eval
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"testing"
|
||||
)
|
||||
|
||||
//!+Eval
|
||||
func TestEval(t *testing.T) {
|
||||
tests := []struct {
|
||||
expr string
|
||||
env Env
|
||||
want string
|
||||
}{
|
||||
{"sqrt(A / pi)", Env{"A": 87616, "pi": math.Pi}, "167"},
|
||||
{"pow(x, 3) + pow(y, 3)", Env{"x": 12, "y": 1}, "1729"},
|
||||
{"pow(x, 3) + pow(y, 3)", Env{"x": 9, "y": 10}, "1729"},
|
||||
{"5 / 9 * (F - 32)", Env{"F": -40}, "-40"},
|
||||
{"5 / 9 * (F - 32)", Env{"F": 32}, "0"},
|
||||
{"5 / 9 * (F - 32)", Env{"F": 212}, "100"},
|
||||
//!-Eval
|
||||
// additional tests that don't appear in the book
|
||||
{"-1 + -x", Env{"x": 1}, "-2"},
|
||||
{"-1 - x", Env{"x": 1}, "-2"},
|
||||
//!+Eval
|
||||
}
|
||||
var prevExpr string
|
||||
for _, test := range tests {
|
||||
// Print expr only when it changes.
|
||||
if test.expr != prevExpr {
|
||||
fmt.Printf("\n%s\n", test.expr)
|
||||
prevExpr = test.expr
|
||||
}
|
||||
expr, err := Parse(test.expr)
|
||||
if err != nil {
|
||||
t.Error(err) // parse error
|
||||
continue
|
||||
}
|
||||
got := fmt.Sprintf("%.6g", expr.Eval(test.env))
|
||||
fmt.Printf("\t%v => %s\n", test.env, got)
|
||||
if got != test.want {
|
||||
t.Errorf("%s.Eval() in %v = %q, want %q\n",
|
||||
test.expr, test.env, got, test.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//!-Eval
|
||||
|
||||
/*
|
||||
//!+output
|
||||
sqrt(A / pi)
|
||||
map[A:87616 pi:3.141592653589793] => 167
|
||||
|
||||
pow(x, 3) + pow(y, 3)
|
||||
map[x:12 y:1] => 1729
|
||||
map[x:9 y:10] => 1729
|
||||
|
||||
5 / 9 * (F - 32)
|
||||
map[F:-40] => -40
|
||||
map[F:32] => 0
|
||||
map[F:212] => 100
|
||||
//!-output
|
||||
|
||||
// Additional outputs that don't appear in the book.
|
||||
|
||||
-1 - x
|
||||
map[x:1] => -2
|
||||
|
||||
-1 + -x
|
||||
map[x:1] => -2
|
||||
*/
|
||||
|
||||
func TestErrors(t *testing.T) {
|
||||
for _, test := range []struct{ expr, wantErr string }{
|
||||
{"x % 2", "unexpected '%'"},
|
||||
{"math.Pi", "unexpected '.'"},
|
||||
{"!true", "unexpected '!'"},
|
||||
{`"hello"`, "unexpected '\"'"},
|
||||
{"log(10)", `unknown function "log"`},
|
||||
{"sqrt(1, 2)", "call to sqrt has 2 args, want 1"},
|
||||
} {
|
||||
expr, err := Parse(test.expr)
|
||||
if err == nil {
|
||||
vars := make(map[Var]bool)
|
||||
err = expr.Check(vars)
|
||||
if err == nil {
|
||||
t.Errorf("unexpected success: %s", test.expr)
|
||||
continue
|
||||
}
|
||||
}
|
||||
fmt.Printf("%-20s%v\n", test.expr, err) // (for book)
|
||||
if err.Error() != test.wantErr {
|
||||
t.Errorf("got error %s, want %s", err, test.wantErr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
//!+errors
|
||||
x % 2 unexpected '%'
|
||||
math.Pi unexpected '.'
|
||||
!true unexpected '!'
|
||||
"hello" unexpected '"'
|
||||
|
||||
log(10) unknown function "log"
|
||||
sqrt(1, 2) call to sqrt has 2 args, want 1
|
||||
//!-errors
|
||||
*/
|
||||
160
vendor/gopl.io/ch7/eval/parse.go
generated
vendored
Normal file
160
vendor/gopl.io/ch7/eval/parse.go
generated
vendored
Normal file
@@ -0,0 +1,160 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
package eval
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"text/scanner"
|
||||
)
|
||||
|
||||
// ---- lexer ----
|
||||
|
||||
// This lexer is similar to the one described in Chapter 13.
|
||||
type lexer struct {
|
||||
scan scanner.Scanner
|
||||
token rune // current lookahead token
|
||||
}
|
||||
|
||||
func (lex *lexer) next() { lex.token = lex.scan.Scan() }
|
||||
func (lex *lexer) text() string { return lex.scan.TokenText() }
|
||||
|
||||
type lexPanic string
|
||||
|
||||
// describe returns a string describing the current token, for use in errors.
|
||||
func (lex *lexer) describe() string {
|
||||
switch lex.token {
|
||||
case scanner.EOF:
|
||||
return "end of file"
|
||||
case scanner.Ident:
|
||||
return fmt.Sprintf("identifier %s", lex.text())
|
||||
case scanner.Int, scanner.Float:
|
||||
return fmt.Sprintf("number %s", lex.text())
|
||||
}
|
||||
return fmt.Sprintf("%q", rune(lex.token)) // any other rune
|
||||
}
|
||||
|
||||
func precedence(op rune) int {
|
||||
switch op {
|
||||
case '*', '/':
|
||||
return 2
|
||||
case '+', '-':
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// ---- parser ----
|
||||
|
||||
// Parse parses the input string as an arithmetic expression.
|
||||
//
|
||||
// expr = num a literal number, e.g., 3.14159
|
||||
// | id a variable name, e.g., x
|
||||
// | id '(' expr ',' ... ')' a function call
|
||||
// | '-' expr a unary operator (+-)
|
||||
// | expr '+' expr a binary operator (+-*/)
|
||||
//
|
||||
func Parse(input string) (_ Expr, err error) {
|
||||
defer func() {
|
||||
switch x := recover().(type) {
|
||||
case nil:
|
||||
// no panic
|
||||
case lexPanic:
|
||||
err = fmt.Errorf("%s", x)
|
||||
default:
|
||||
// unexpected panic: resume state of panic.
|
||||
panic(x)
|
||||
}
|
||||
}()
|
||||
lex := new(lexer)
|
||||
lex.scan.Init(strings.NewReader(input))
|
||||
lex.scan.Mode = scanner.ScanIdents | scanner.ScanInts | scanner.ScanFloats
|
||||
lex.next() // initial lookahead
|
||||
e := parseExpr(lex)
|
||||
if lex.token != scanner.EOF {
|
||||
return nil, fmt.Errorf("unexpected %s", lex.describe())
|
||||
}
|
||||
return e, nil
|
||||
}
|
||||
|
||||
func parseExpr(lex *lexer) Expr { return parseBinary(lex, 1) }
|
||||
|
||||
// binary = unary ('+' binary)*
|
||||
// parseBinary stops when it encounters an
|
||||
// operator of lower precedence than prec1.
|
||||
func parseBinary(lex *lexer, prec1 int) Expr {
|
||||
lhs := parseUnary(lex)
|
||||
for prec := precedence(lex.token); prec >= prec1; prec-- {
|
||||
for precedence(lex.token) == prec {
|
||||
op := lex.token
|
||||
lex.next() // consume operator
|
||||
rhs := parseBinary(lex, prec+1)
|
||||
lhs = binary{op, lhs, rhs}
|
||||
}
|
||||
}
|
||||
return lhs
|
||||
}
|
||||
|
||||
// unary = '+' expr | primary
|
||||
func parseUnary(lex *lexer) Expr {
|
||||
if lex.token == '+' || lex.token == '-' {
|
||||
op := lex.token
|
||||
lex.next() // consume '+' or '-'
|
||||
return unary{op, parseUnary(lex)}
|
||||
}
|
||||
return parsePrimary(lex)
|
||||
}
|
||||
|
||||
// primary = id
|
||||
// | id '(' expr ',' ... ',' expr ')'
|
||||
// | num
|
||||
// | '(' expr ')'
|
||||
func parsePrimary(lex *lexer) Expr {
|
||||
switch lex.token {
|
||||
case scanner.Ident:
|
||||
id := lex.text()
|
||||
lex.next() // consume Ident
|
||||
if lex.token != '(' {
|
||||
return Var(id)
|
||||
}
|
||||
lex.next() // consume '('
|
||||
var args []Expr
|
||||
if lex.token != ')' {
|
||||
for {
|
||||
args = append(args, parseExpr(lex))
|
||||
if lex.token != ',' {
|
||||
break
|
||||
}
|
||||
lex.next() // consume ','
|
||||
}
|
||||
if lex.token != ')' {
|
||||
msg := fmt.Sprintf("got %q, want ')'", lex.token)
|
||||
panic(lexPanic(msg))
|
||||
}
|
||||
}
|
||||
lex.next() // consume ')'
|
||||
return call{id, args}
|
||||
|
||||
case scanner.Int, scanner.Float:
|
||||
f, err := strconv.ParseFloat(lex.text(), 64)
|
||||
if err != nil {
|
||||
panic(lexPanic(err.Error()))
|
||||
}
|
||||
lex.next() // consume number
|
||||
return literal(f)
|
||||
|
||||
case '(':
|
||||
lex.next() // consume ')'
|
||||
e := parseExpr(lex)
|
||||
if lex.token != ')' {
|
||||
msg := fmt.Sprintf("got %s, want ')'", lex.describe())
|
||||
panic(lexPanic(msg))
|
||||
}
|
||||
lex.next() // consume ')'
|
||||
return e
|
||||
}
|
||||
msg := fmt.Sprintf("unexpected %s", lex.describe())
|
||||
panic(lexPanic(msg))
|
||||
}
|
||||
52
vendor/gopl.io/ch7/eval/print.go
generated
vendored
Normal file
52
vendor/gopl.io/ch7/eval/print.go
generated
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
package eval
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// Format formats an expression as a string.
|
||||
// It does not attempt to remove unnecessary parens.
|
||||
func Format(e Expr) string {
|
||||
var buf bytes.Buffer
|
||||
write(&buf, e)
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
func write(buf *bytes.Buffer, e Expr) {
|
||||
switch e := e.(type) {
|
||||
case literal:
|
||||
fmt.Fprintf(buf, "%g", e)
|
||||
|
||||
case Var:
|
||||
fmt.Fprintf(buf, "%s", e)
|
||||
|
||||
case unary:
|
||||
fmt.Fprintf(buf, "(%c", e.op)
|
||||
write(buf, e.x)
|
||||
buf.WriteByte(')')
|
||||
|
||||
case binary:
|
||||
buf.WriteByte('(')
|
||||
write(buf, e.x)
|
||||
fmt.Fprintf(buf, " %c ", e.op)
|
||||
write(buf, e.y)
|
||||
buf.WriteByte(')')
|
||||
|
||||
case call:
|
||||
fmt.Fprintf(buf, "%s(", e.fn)
|
||||
for i, arg := range e.args {
|
||||
if i > 0 {
|
||||
buf.WriteString(", ")
|
||||
}
|
||||
write(buf, arg)
|
||||
}
|
||||
buf.WriteByte(')')
|
||||
|
||||
default:
|
||||
panic(fmt.Sprintf("unknown Expr: %T", e))
|
||||
}
|
||||
}
|
||||
46
vendor/gopl.io/ch7/http1/main.go
generated
vendored
Normal file
46
vendor/gopl.io/ch7/http1/main.go
generated
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
// See page 191.
|
||||
|
||||
// Http1 is a rudimentary e-commerce server.
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
//!+main
|
||||
|
||||
func main() {
|
||||
db := database{"shoes": 50, "socks": 5}
|
||||
log.Fatal(http.ListenAndServe("localhost:8000", db))
|
||||
}
|
||||
|
||||
type dollars float32
|
||||
|
||||
func (d dollars) String() string { return fmt.Sprintf("$%.2f", d) }
|
||||
|
||||
type database map[string]dollars
|
||||
|
||||
func (db database) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||
for item, price := range db {
|
||||
fmt.Fprintf(w, "%s: %s\n", item, price)
|
||||
}
|
||||
}
|
||||
|
||||
//!-main
|
||||
|
||||
/*
|
||||
//!+handler
|
||||
package http
|
||||
|
||||
type Handler interface {
|
||||
ServeHTTP(w ResponseWriter, r *Request)
|
||||
}
|
||||
|
||||
func ListenAndServe(address string, h Handler) error
|
||||
//!-handler
|
||||
*/
|
||||
48
vendor/gopl.io/ch7/http2/main.go
generated
vendored
Normal file
48
vendor/gopl.io/ch7/http2/main.go
generated
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
// See page 192.
|
||||
|
||||
// Http2 is an e-commerce server with /list and /price endpoints.
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func main() {
|
||||
db := database{"shoes": 50, "socks": 5}
|
||||
log.Fatal(http.ListenAndServe("localhost:8000", db))
|
||||
}
|
||||
|
||||
type dollars float32
|
||||
|
||||
func (d dollars) String() string { return fmt.Sprintf("$%.2f", d) }
|
||||
|
||||
type database map[string]dollars
|
||||
|
||||
//!+handler
|
||||
func (db database) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||
switch req.URL.Path {
|
||||
case "/list":
|
||||
for item, price := range db {
|
||||
fmt.Fprintf(w, "%s: %s\n", item, price)
|
||||
}
|
||||
case "/price":
|
||||
item := req.URL.Query().Get("item")
|
||||
price, ok := db[item]
|
||||
if !ok {
|
||||
w.WriteHeader(http.StatusNotFound) // 404
|
||||
fmt.Fprintf(w, "no such item: %q\n", item)
|
||||
return
|
||||
}
|
||||
fmt.Fprintf(w, "%s\n", price)
|
||||
default:
|
||||
w.WriteHeader(http.StatusNotFound) // 404
|
||||
fmt.Fprintf(w, "no such page: %s\n", req.URL)
|
||||
}
|
||||
}
|
||||
|
||||
//!-handler
|
||||
61
vendor/gopl.io/ch7/http3/main.go
generated
vendored
Normal file
61
vendor/gopl.io/ch7/http3/main.go
generated
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
// See page 194.
|
||||
|
||||
// Http3 is an e-commerce server that registers the /list and /price
|
||||
// endpoints by calling (*http.ServeMux).Handle.
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type dollars float32
|
||||
|
||||
func (d dollars) String() string { return fmt.Sprintf("$%.2f", d) }
|
||||
|
||||
//!+main
|
||||
|
||||
func main() {
|
||||
db := database{"shoes": 50, "socks": 5}
|
||||
mux := http.NewServeMux()
|
||||
mux.Handle("/list", http.HandlerFunc(db.list))
|
||||
mux.Handle("/price", http.HandlerFunc(db.price))
|
||||
log.Fatal(http.ListenAndServe("localhost:8000", mux))
|
||||
}
|
||||
|
||||
type database map[string]dollars
|
||||
|
||||
func (db database) list(w http.ResponseWriter, req *http.Request) {
|
||||
for item, price := range db {
|
||||
fmt.Fprintf(w, "%s: %s\n", item, price)
|
||||
}
|
||||
}
|
||||
|
||||
func (db database) price(w http.ResponseWriter, req *http.Request) {
|
||||
item := req.URL.Query().Get("item")
|
||||
price, ok := db[item]
|
||||
if !ok {
|
||||
w.WriteHeader(http.StatusNotFound) // 404
|
||||
fmt.Fprintf(w, "no such item: %q\n", item)
|
||||
return
|
||||
}
|
||||
fmt.Fprintf(w, "%s\n", price)
|
||||
}
|
||||
|
||||
//!-main
|
||||
|
||||
/*
|
||||
//!+handlerfunc
|
||||
package http
|
||||
|
||||
type HandlerFunc func(w ResponseWriter, r *Request)
|
||||
|
||||
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
|
||||
f(w, r)
|
||||
}
|
||||
//!-handlerfunc
|
||||
*/
|
||||
54
vendor/gopl.io/ch7/http3a/main.go
generated
vendored
Normal file
54
vendor/gopl.io/ch7/http3a/main.go
generated
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
// See page 195.
|
||||
|
||||
// Http3a is an e-commerce server that registers the /list and /price
|
||||
// endpoints by calling (*http.ServeMux).HandleFunc.
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func main() {
|
||||
db := database{"shoes": 50, "socks": 5}
|
||||
mux := http.NewServeMux()
|
||||
//!+main
|
||||
mux.HandleFunc("/list", db.list)
|
||||
mux.HandleFunc("/price", db.price)
|
||||
//!-main
|
||||
log.Fatal(http.ListenAndServe("localhost:8000", mux))
|
||||
}
|
||||
|
||||
type database map[string]int
|
||||
|
||||
func (db database) list(w http.ResponseWriter, req *http.Request) {
|
||||
for item, price := range db {
|
||||
fmt.Fprintf(w, "%s: $%d\n", item, price)
|
||||
}
|
||||
}
|
||||
|
||||
func (db database) price(w http.ResponseWriter, req *http.Request) {
|
||||
item := req.URL.Query().Get("item")
|
||||
if price, ok := db[item]; ok {
|
||||
fmt.Fprintf(w, "$%d\n", price)
|
||||
} else {
|
||||
w.WriteHeader(http.StatusNotFound) // 404
|
||||
fmt.Fprintf(w, "no such item: %q\n", item)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
//!+handlerfunc
|
||||
package http
|
||||
|
||||
type HandlerFunc func(w ResponseWriter, r *Request)
|
||||
|
||||
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
|
||||
f(w, r)
|
||||
}
|
||||
//!-handlerfunc
|
||||
*/
|
||||
47
vendor/gopl.io/ch7/http4/main.go
generated
vendored
Normal file
47
vendor/gopl.io/ch7/http4/main.go
generated
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
// See page 195.
|
||||
|
||||
// Http4 is an e-commerce server that registers the /list and /price
|
||||
// endpoint by calling http.HandleFunc.
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
//!+main
|
||||
|
||||
func main() {
|
||||
db := database{"shoes": 50, "socks": 5}
|
||||
http.HandleFunc("/list", db.list)
|
||||
http.HandleFunc("/price", db.price)
|
||||
log.Fatal(http.ListenAndServe("localhost:8000", nil))
|
||||
}
|
||||
|
||||
//!-main
|
||||
|
||||
type dollars float32
|
||||
|
||||
func (d dollars) String() string { return fmt.Sprintf("$%.2f", d) }
|
||||
|
||||
type database map[string]dollars
|
||||
|
||||
func (db database) list(w http.ResponseWriter, req *http.Request) {
|
||||
for item, price := range db {
|
||||
fmt.Fprintf(w, "%s: %s\n", item, price)
|
||||
}
|
||||
}
|
||||
|
||||
func (db database) price(w http.ResponseWriter, req *http.Request) {
|
||||
item := req.URL.Query().Get("item")
|
||||
if price, ok := db[item]; ok {
|
||||
fmt.Fprintf(w, "%s\n", price)
|
||||
} else {
|
||||
w.WriteHeader(http.StatusNotFound) // 404
|
||||
fmt.Fprintf(w, "no such item: %q\n", item)
|
||||
}
|
||||
}
|
||||
25
vendor/gopl.io/ch7/sleep/sleep.go
generated
vendored
Normal file
25
vendor/gopl.io/ch7/sleep/sleep.go
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
// See page 179.
|
||||
|
||||
// The sleep program sleeps for a specified period of time.
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
//!+sleep
|
||||
var period = flag.Duration("period", 1*time.Second, "sleep period")
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
fmt.Printf("Sleeping for %v...", *period)
|
||||
time.Sleep(*period)
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
//!-sleep
|
||||
167
vendor/gopl.io/ch7/sorting/main.go
generated
vendored
Normal file
167
vendor/gopl.io/ch7/sorting/main.go
generated
vendored
Normal file
@@ -0,0 +1,167 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
// See page 187.
|
||||
|
||||
// Sorting sorts a music playlist into a variety of orders.
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"sort"
|
||||
"text/tabwriter"
|
||||
"time"
|
||||
)
|
||||
|
||||
//!+main
|
||||
type Track struct {
|
||||
Title string
|
||||
Artist string
|
||||
Album string
|
||||
Year int
|
||||
Length time.Duration
|
||||
}
|
||||
|
||||
var tracks = []*Track{
|
||||
{"Go", "Delilah", "From the Roots Up", 2012, length("3m38s")},
|
||||
{"Go", "Moby", "Moby", 1992, length("3m37s")},
|
||||
{"Go Ahead", "Alicia Keys", "As I Am", 2007, length("4m36s")},
|
||||
{"Ready 2 Go", "Martin Solveig", "Smash", 2011, length("4m24s")},
|
||||
}
|
||||
|
||||
func length(s string) time.Duration {
|
||||
d, err := time.ParseDuration(s)
|
||||
if err != nil {
|
||||
panic(s)
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
//!-main
|
||||
|
||||
//!+printTracks
|
||||
func printTracks(tracks []*Track) {
|
||||
const format = "%v\t%v\t%v\t%v\t%v\t\n"
|
||||
tw := new(tabwriter.Writer).Init(os.Stdout, 0, 8, 2, ' ', 0)
|
||||
fmt.Fprintf(tw, format, "Title", "Artist", "Album", "Year", "Length")
|
||||
fmt.Fprintf(tw, format, "-----", "------", "-----", "----", "------")
|
||||
for _, t := range tracks {
|
||||
fmt.Fprintf(tw, format, t.Title, t.Artist, t.Album, t.Year, t.Length)
|
||||
}
|
||||
tw.Flush() // calculate column widths and print table
|
||||
}
|
||||
|
||||
//!-printTracks
|
||||
|
||||
//!+artistcode
|
||||
type byArtist []*Track
|
||||
|
||||
func (x byArtist) Len() int { return len(x) }
|
||||
func (x byArtist) Less(i, j int) bool { return x[i].Artist < x[j].Artist }
|
||||
func (x byArtist) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
|
||||
|
||||
//!-artistcode
|
||||
|
||||
//!+yearcode
|
||||
type byYear []*Track
|
||||
|
||||
func (x byYear) Len() int { return len(x) }
|
||||
func (x byYear) Less(i, j int) bool { return x[i].Year < x[j].Year }
|
||||
func (x byYear) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
|
||||
|
||||
//!-yearcode
|
||||
|
||||
func main() {
|
||||
fmt.Println("byArtist:")
|
||||
sort.Sort(byArtist(tracks))
|
||||
printTracks(tracks)
|
||||
|
||||
fmt.Println("\nReverse(byArtist):")
|
||||
sort.Sort(sort.Reverse(byArtist(tracks)))
|
||||
printTracks(tracks)
|
||||
|
||||
fmt.Println("\nbyYear:")
|
||||
sort.Sort(byYear(tracks))
|
||||
printTracks(tracks)
|
||||
|
||||
fmt.Println("\nCustom:")
|
||||
//!+customcall
|
||||
sort.Sort(customSort{tracks, func(x, y *Track) bool {
|
||||
if x.Title != y.Title {
|
||||
return x.Title < y.Title
|
||||
}
|
||||
if x.Year != y.Year {
|
||||
return x.Year < y.Year
|
||||
}
|
||||
if x.Length != y.Length {
|
||||
return x.Length < y.Length
|
||||
}
|
||||
return false
|
||||
}})
|
||||
//!-customcall
|
||||
printTracks(tracks)
|
||||
}
|
||||
|
||||
/*
|
||||
//!+artistoutput
|
||||
Title Artist Album Year Length
|
||||
----- ------ ----- ---- ------
|
||||
Go Ahead Alicia Keys As I Am 2007 4m36s
|
||||
Go Delilah From the Roots Up 2012 3m38s
|
||||
Ready 2 Go Martin Solveig Smash 2011 4m24s
|
||||
Go Moby Moby 1992 3m37s
|
||||
//!-artistoutput
|
||||
|
||||
//!+artistrevoutput
|
||||
Title Artist Album Year Length
|
||||
----- ------ ----- ---- ------
|
||||
Go Moby Moby 1992 3m37s
|
||||
Ready 2 Go Martin Solveig Smash 2011 4m24s
|
||||
Go Delilah From the Roots Up 2012 3m38s
|
||||
Go Ahead Alicia Keys As I Am 2007 4m36s
|
||||
//!-artistrevoutput
|
||||
|
||||
//!+yearoutput
|
||||
Title Artist Album Year Length
|
||||
----- ------ ----- ---- ------
|
||||
Go Moby Moby 1992 3m37s
|
||||
Go Ahead Alicia Keys As I Am 2007 4m36s
|
||||
Ready 2 Go Martin Solveig Smash 2011 4m24s
|
||||
Go Delilah From the Roots Up 2012 3m38s
|
||||
//!-yearoutput
|
||||
|
||||
//!+customout
|
||||
Title Artist Album Year Length
|
||||
----- ------ ----- ---- ------
|
||||
Go Moby Moby 1992 3m37s
|
||||
Go Delilah From the Roots Up 2012 3m38s
|
||||
Go Ahead Alicia Keys As I Am 2007 4m36s
|
||||
Ready 2 Go Martin Solveig Smash 2011 4m24s
|
||||
//!-customout
|
||||
*/
|
||||
|
||||
//!+customcode
|
||||
type customSort struct {
|
||||
t []*Track
|
||||
less func(x, y *Track) bool
|
||||
}
|
||||
|
||||
func (x customSort) Len() int { return len(x.t) }
|
||||
func (x customSort) Less(i, j int) bool { return x.less(x.t[i], x.t[j]) }
|
||||
func (x customSort) Swap(i, j int) { x.t[i], x.t[j] = x.t[j], x.t[i] }
|
||||
|
||||
//!-customcode
|
||||
|
||||
func init() {
|
||||
//!+ints
|
||||
values := []int{3, 1, 4, 1}
|
||||
fmt.Println(sort.IntsAreSorted(values)) // "false"
|
||||
sort.Ints(values)
|
||||
fmt.Println(values) // "[1 1 3 4]"
|
||||
fmt.Println(sort.IntsAreSorted(values)) // "true"
|
||||
sort.Sort(sort.Reverse(sort.IntSlice(values)))
|
||||
fmt.Println(values) // "[4 3 1 1]"
|
||||
fmt.Println(sort.IntsAreSorted(values)) // "false"
|
||||
//!-ints
|
||||
}
|
||||
112
vendor/gopl.io/ch7/surface/surface.go
generated
vendored
Normal file
112
vendor/gopl.io/ch7/surface/surface.go
generated
vendored
Normal file
@@ -0,0 +1,112 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
// See page 203.
|
||||
|
||||
// The surface program plots the 3-D surface of a user-provided function.
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"math"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
//!+parseAndCheck
|
||||
import "gopl.io/ch7/eval"
|
||||
|
||||
//!-parseAndCheck
|
||||
|
||||
// -- copied from gopl.io/ch3/surface --
|
||||
|
||||
const (
|
||||
width, height = 600, 320 // canvas size in pixels
|
||||
cells = 100 // number of grid cells
|
||||
xyrange = 30.0 // x, y axis range (-xyrange..+xyrange)
|
||||
xyscale = width / 2 / xyrange // pixels per x or y unit
|
||||
zscale = height * 0.4 // pixels per z unit
|
||||
)
|
||||
|
||||
var sin30, cos30 = 0.5, math.Sqrt(3.0 / 4.0) // sin(30°), cos(30°)
|
||||
|
||||
func corner(f func(x, y float64) float64, i, j int) (float64, float64) {
|
||||
// find point (x,y) at corner of cell (i,j)
|
||||
x := xyrange * (float64(i)/cells - 0.5)
|
||||
y := xyrange * (float64(j)/cells - 0.5)
|
||||
|
||||
z := f(x, y) // compute surface height z
|
||||
|
||||
// project (x,y,z) isometrically onto 2-D SVG canvas (sx,sy)
|
||||
sx := width/2 + (x-y)*cos30*xyscale
|
||||
sy := height/2 + (x+y)*sin30*xyscale - z*zscale
|
||||
return sx, sy
|
||||
}
|
||||
|
||||
func surface(w io.Writer, f func(x, y float64) float64) {
|
||||
fmt.Fprintf(w, "<svg xmlns='http://www.w3.org/2000/svg' "+
|
||||
"style='stroke: grey; fill: white; stroke-width: 0.7' "+
|
||||
"width='%d' height='%d'>", width, height)
|
||||
for i := 0; i < cells; i++ {
|
||||
for j := 0; j < cells; j++ {
|
||||
ax, ay := corner(f, i+1, j)
|
||||
bx, by := corner(f, i, j)
|
||||
cx, cy := corner(f, i, j+1)
|
||||
dx, dy := corner(f, i+1, j+1)
|
||||
fmt.Fprintf(w, "<polygon points='%g,%g %g,%g %g,%g %g,%g'/>\n",
|
||||
ax, ay, bx, by, cx, cy, dx, dy)
|
||||
}
|
||||
}
|
||||
fmt.Fprintln(w, "</svg>")
|
||||
}
|
||||
|
||||
// -- main code for gopl.io/ch7/surface --
|
||||
|
||||
//!+parseAndCheck
|
||||
func parseAndCheck(s string) (eval.Expr, error) {
|
||||
if s == "" {
|
||||
return nil, fmt.Errorf("empty expression")
|
||||
}
|
||||
expr, err := eval.Parse(s)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
vars := make(map[eval.Var]bool)
|
||||
if err := expr.Check(vars); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for v := range vars {
|
||||
if v != "x" && v != "y" && v != "r" {
|
||||
return nil, fmt.Errorf("undefined variable: %s", v)
|
||||
}
|
||||
}
|
||||
return expr, nil
|
||||
}
|
||||
|
||||
//!-parseAndCheck
|
||||
|
||||
//!+plot
|
||||
func plot(w http.ResponseWriter, r *http.Request) {
|
||||
r.ParseForm()
|
||||
expr, err := parseAndCheck(r.Form.Get("expr"))
|
||||
if err != nil {
|
||||
http.Error(w, "bad expr: "+err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
w.Header().Set("Content-Type", "image/svg+xml")
|
||||
surface(w, func(x, y float64) float64 {
|
||||
r := math.Hypot(x, y) // distance from (0,0)
|
||||
return expr.Eval(eval.Env{"x": x, "y": y, "r": r})
|
||||
})
|
||||
}
|
||||
|
||||
//!-plot
|
||||
|
||||
//!+main
|
||||
func main() {
|
||||
http.HandleFunc("/plot", plot)
|
||||
log.Fatal(http.ListenAndServe("localhost:8000", nil))
|
||||
}
|
||||
|
||||
//!-main
|
||||
66
vendor/gopl.io/ch7/tempconv/tempconv.go
generated
vendored
Normal file
66
vendor/gopl.io/ch7/tempconv/tempconv.go
generated
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
// See page 180.
|
||||
|
||||
// Package tempconv performs Celsius and Fahrenheit temperature computations.
|
||||
package tempconv
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type Celsius float64
|
||||
type Fahrenheit float64
|
||||
|
||||
func CToF(c Celsius) Fahrenheit { return Fahrenheit(c*9.0/5.0 + 32.0) }
|
||||
func FToC(f Fahrenheit) Celsius { return Celsius((f - 32.0) * 5.0 / 9.0) }
|
||||
|
||||
func (c Celsius) String() string { return fmt.Sprintf("%g°C", c) }
|
||||
|
||||
/*
|
||||
//!+flagvalue
|
||||
package flag
|
||||
|
||||
// Value is the interface to the value stored in a flag.
|
||||
type Value interface {
|
||||
String() string
|
||||
Set(string) error
|
||||
}
|
||||
//!-flagvalue
|
||||
*/
|
||||
|
||||
//!+celsiusFlag
|
||||
// *celsiusFlag satisfies the flag.Value interface.
|
||||
type celsiusFlag struct{ Celsius }
|
||||
|
||||
func (f *celsiusFlag) Set(s string) error {
|
||||
var unit string
|
||||
var value float64
|
||||
fmt.Sscanf(s, "%f%s", &value, &unit) // no error check needed
|
||||
switch unit {
|
||||
case "C", "°C":
|
||||
f.Celsius = Celsius(value)
|
||||
return nil
|
||||
case "F", "°F":
|
||||
f.Celsius = FToC(Fahrenheit(value))
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("invalid temperature %q", s)
|
||||
}
|
||||
|
||||
//!-celsiusFlag
|
||||
|
||||
//!+CelsiusFlag
|
||||
|
||||
// CelsiusFlag defines a Celsius flag with the specified name,
|
||||
// default value, and usage, and returns the address of the flag variable.
|
||||
// The flag argument must have a quantity and a unit, e.g., "100C".
|
||||
func CelsiusFlag(name string, value Celsius, usage string) *Celsius {
|
||||
f := celsiusFlag{value}
|
||||
flag.CommandLine.Var(&f, name, usage)
|
||||
return &f.Celsius
|
||||
}
|
||||
|
||||
//!-CelsiusFlag
|
||||
64
vendor/gopl.io/ch7/tempconv/tempconv.go.~master~
generated
vendored
Normal file
64
vendor/gopl.io/ch7/tempconv/tempconv.go.~master~
generated
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
|
||||
// Package tempconv performs Celsius and Fahrenheit temperature computations.
|
||||
package tempconv
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type Celsius float64
|
||||
type Fahrenheit float64
|
||||
|
||||
func CToF(c Celsius) Fahrenheit { return Fahrenheit(c*9.0/5.0 + 32.0) }
|
||||
func FToC(f Fahrenheit) Celsius { return Celsius((f - 32.0) * 5.0 / 9.0) }
|
||||
|
||||
func (c Celsius) String() string { return fmt.Sprintf("%g°C", c) }
|
||||
|
||||
/*
|
||||
//!+flagvalue
|
||||
package flag
|
||||
|
||||
// Value is the interface to the value stored in a flag.
|
||||
type Value interface {
|
||||
String() string
|
||||
Set(string) error
|
||||
}
|
||||
//!-flagvalue
|
||||
*/
|
||||
|
||||
//!+celsiusflag
|
||||
// *celsiusFlag satisfies the flag.Value interface.
|
||||
type celsiusFlag struct{ Celsius }
|
||||
|
||||
func (f *celsiusFlag) Set(s string) error {
|
||||
var unit string
|
||||
var value float64
|
||||
fmt.Sscanf(s, "%f%s", &value, &unit) // no error check needed
|
||||
switch unit {
|
||||
case "C", "°C":
|
||||
f.Celsius = Celsius(value)
|
||||
return nil
|
||||
case "F", "°F":
|
||||
f.Celsius = FToC(Fahrenheit(value))
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("invalid temperature %q", s)
|
||||
}
|
||||
|
||||
//!-celsiusflag
|
||||
|
||||
//!+Celsiusflag
|
||||
// CelsiusFlag defines a Celsius flag with the specified name,
|
||||
// default value, and usage, and returns the address of the flag variable.
|
||||
// The flag argument must have a quantity and a unit, e.g., "100C".
|
||||
func CelsiusFlag(name string, value Celsius, usage string) *Celsius {
|
||||
f := celsiusFlag{value}
|
||||
flag.CommandLine.Var(&f, name, usage)
|
||||
return &f.Celsius
|
||||
}
|
||||
|
||||
//!-Celsiusflag
|
||||
24
vendor/gopl.io/ch7/tempflag/tempflag.go
generated
vendored
Normal file
24
vendor/gopl.io/ch7/tempflag/tempflag.go
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
// See page 181.
|
||||
|
||||
// Tempflag prints the value of its -temp (temperature) flag.
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
|
||||
"gopl.io/ch7/tempconv"
|
||||
)
|
||||
|
||||
//!+
|
||||
var temp = tempconv.CelsiusFlag("temp", 20.0, "the temperature")
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
fmt.Println(*temp)
|
||||
}
|
||||
|
||||
//!-
|
||||
56
vendor/gopl.io/ch7/xmlselect/main.go
generated
vendored
Normal file
56
vendor/gopl.io/ch7/xmlselect/main.go
generated
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
// See page 214.
|
||||
//!+
|
||||
|
||||
// Xmlselect prints the text of selected elements of an XML document.
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func main() {
|
||||
dec := xml.NewDecoder(os.Stdin)
|
||||
var stack []string // stack of element names
|
||||
for {
|
||||
tok, err := dec.Token()
|
||||
if err == io.EOF {
|
||||
break
|
||||
} else if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "xmlselect: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
switch tok := tok.(type) {
|
||||
case xml.StartElement:
|
||||
stack = append(stack, tok.Name.Local) // push
|
||||
case xml.EndElement:
|
||||
stack = stack[:len(stack)-1] // pop
|
||||
case xml.CharData:
|
||||
if containsAll(stack, os.Args[1:]) {
|
||||
fmt.Printf("%s: %s\n", strings.Join(stack, " "), tok)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// containsAll reports whether x contains the elements of y, in order.
|
||||
func containsAll(x, y []string) bool {
|
||||
for len(y) <= len(x) {
|
||||
if len(y) == 0 {
|
||||
return true
|
||||
}
|
||||
if x[0] == y[0] {
|
||||
y = y[1:]
|
||||
}
|
||||
x = x[1:]
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
//!-
|
||||
Reference in New Issue
Block a user