diff --git a/Makefile b/Makefile index ddbc508..d547d40 100644 --- a/Makefile +++ b/Makefile @@ -1,13 +1,19 @@ dev: build npm run test:dev -build: clean +gotypes: + go run ./cmd/gotypes + +gentestdata: + go run ./cmd/gentestdata + +build: clean gotypes npm run build clean: rm -rf dist -test: build +test: build gentestdata npm run test publish: test diff --git a/cmd/gentestdata/main.go b/cmd/gentestdata/main.go new file mode 100644 index 0000000..38b4ad1 --- /dev/null +++ b/cmd/gentestdata/main.go @@ -0,0 +1,71 @@ +package main + +import ( + "context" + "encoding/json" + "log" + "os" + "path/filepath" + "time" + + "github.com/gopherguides/hype" + "golang.org/x/sync/errgroup" +) + +func main() { + if err := run(); err != nil { + log.Fatal(err) + } +} + +func run() error { + pwd, err := os.Getwd() + if err != nil { + return err + } + + op := filepath.Join(pwd, "src", "testdata") + + ctx := context.Background() + ctx, cancel := context.WithTimeout(ctx, 60*time.Second) + defer cancel() + + root := "/Users/markbates/Dropbox/dev/guides/content/book/chapters" + chaps := []string{ + "09-errors", + "10-generics", + "12-context", + } + + var wg errgroup.Group + + for _, c := range chaps { + wg.Go(func() error { + fp := filepath.Join(root, c) + p := hype.NewParser(os.DirFS(fp)) + p.Root = fp + + doc, err := p.ParseExecuteFile(ctx, "module.md") + if err != nil { + return err + } + + f, err := os.Create(filepath.Join(op, c+".json")) + if err != nil { + return err + } + defer f.Close() + + enc := json.NewEncoder(f) + enc.SetIndent("", " ") + err = enc.Encode(doc) + if err != nil { + return err + } + + return nil + }) + } + + return wg.Wait() +} diff --git a/cmd/gotypes/generate.go b/cmd/gotypes/generate.go new file mode 100644 index 0000000..d92080c --- /dev/null +++ b/cmd/gotypes/generate.go @@ -0,0 +1,93 @@ +package main + +import ( + "fmt" + "io" + "os/exec" + "regexp" + "strings" +) + +type GoType struct { + Full string + Name string + Type string +} + +type TypeMap map[string][]GoType + +func generate(w io.Writer) error { + types, err := findTypes() + if err != nil { + return err + } + fmt.Fprintln(w, "let gotypes = {") + for _, k := range types["types"] { + printType(w, k) + } + fmt.Fprintln(w, "}") + + fmt.Fprintln(w) + + fmt.Fprintln(w, "let goerrors = {") + for _, k := range types["errors"] { + printType(w, k) + } + fmt.Fprintln(w, "}") + + fmt.Fprintln(w) + + fmt.Fprintln(w, "export { gotypes, goerrors }") + return nil +} + +func printType(w io.Writer, k GoType) { + if k.Type == "func" { + return + } + + v := fmt.Sprintf("hype.%s", k.Name) + fmt.Fprintf(w, "\t%s: \"%s\",\n", k.Name, v) +} + +func findTypes() (TypeMap, error) { + cmd := exec.Command("go", "doc", "github.com/gopherguides/hype") + out, err := cmd.Output() + if err != nil { + return nil, err + } + + gx, err := regexp.Compile(`type\s([a-zA-Z0-9_]+)\s([^{|(]+)`) + if err != nil { + return nil, err + } + + res := TypeMap{} + + lines := strings.Split(string(out), "\n") + for _, line := range lines { + mm := gx.FindStringSubmatch(line) + if len(mm) < 1 { + continue + } + + full := mm[0] + key := mm[1] + ty := mm[2] + + tt := GoType{ + Full: full, + Name: key, + Type: ty, + } + + if strings.HasSuffix(key, "Error") || strings.HasPrefix(key, "Err") { + res["errors"] = append(res["errors"], tt) + } else { + res["types"] = append(res["types"], tt) + } + + } + + return res, nil +} diff --git a/cmd/gotypes/generate_test.go b/cmd/gotypes/generate_test.go new file mode 100644 index 0000000..8312cc6 --- /dev/null +++ b/cmd/gotypes/generate_test.go @@ -0,0 +1,99 @@ +package main + +import ( + "bytes" + "strings" + "testing" + + "github.com/stretchr/testify/require" +) + +func Test_generate(t *testing.T) { + t.Parallel() + r := require.New(t) + + bb := &bytes.Buffer{} + + r.NoError(generate(bb)) + + act := bb.String() + act = strings.TrimSpace(act) + + exp := `let gotypes = { + Atom: "hype.Atom", + Atomable: "hype.Atomable", + AtomableNode: "hype.AtomableNode", + AttrNode: "hype.AttrNode", + Attributes: "hype.Attributes", + Body: "hype.Body", + Cmd: "hype.Cmd", + CmdResult: "hype.CmdResult", + Comment: "hype.Comment", + Document: "hype.Document", + Documents: "hype.Documents", + Element: "hype.Element", + EmptyableNode: "hype.EmptyableNode", + ExecutableNode: "hype.ExecutableNode", + FencedCode: "hype.FencedCode", + Figcaption: "hype.Figcaption", + Figure: "hype.Figure", + HTMLNode: "hype.HTMLNode", + Heading: "hype.Heading", + Image: "hype.Image", + Include: "hype.Include", + InlineCode: "hype.InlineCode", + LI: "hype.LI", + Link: "hype.Link", + MDNode: "hype.MDNode", + Metadata: "hype.Metadata", + Node: "hype.Node", + Nodes: "hype.Nodes", + Now: "hype.Now", + OL: "hype.OL", + Page: "hype.Page", + Paragraph: "hype.Paragraph", + Parser: "hype.Parser", + PostExecuter: "hype.PostExecuter", + PostParser: "hype.PostParser", + PreExecuter: "hype.PreExecuter", + PreParser: "hype.PreParser", + PreParsers: "hype.PreParsers", + Ref: "hype.Ref", + RefProcessor: "hype.RefProcessor", + Snippet: "hype.Snippet", + Snippets: "hype.Snippets", + SourceCode: "hype.SourceCode", + TD: "hype.TD", + TH: "hype.TH", + THead: "hype.THead", + TR: "hype.TR", + Table: "hype.Table", + Tag: "hype.Tag", + Tags: "hype.Tags", + Text: "hype.Text", + ToC: "hype.ToC", + UL: "hype.UL", + Var: "hype.Var", + WaitGrouper: "hype.WaitGrouper", +} + +let goerrors = { + CmdError: "hype.CmdError", + ErrAttrEmpty: "hype.ErrAttrEmpty", + ErrAttrNotFound: "hype.ErrAttrNotFound", + ErrIsNil: "hype.ErrIsNil", + ExecuteError: "hype.ExecuteError", + ParseError: "hype.ParseError", + PostExecuteError: "hype.PostExecuteError", + PostParseError: "hype.PostParseError", + PreExecuteError: "hype.PreExecuteError", + PreParseError: "hype.PreParseError", +} + +export { gotypes, goerrors }` + + exp = strings.TrimSpace(exp) + + r.Equal(exp, act) + +} diff --git a/cmd/gotypes/main.go b/cmd/gotypes/main.go new file mode 100644 index 0000000..4e830b1 --- /dev/null +++ b/cmd/gotypes/main.go @@ -0,0 +1,26 @@ +package main + +import ( + "log" + "os" + "path/filepath" +) + +func main() { + pwd, err := os.Getwd() + if err != nil { + log.Fatal(err) + } + + pwd = filepath.Join(pwd, "src", "gotypes.ts") + + f, err := os.Create(pwd) + if err != nil { + log.Fatal(err) + } + defer f.Close() + + if err := generate(f); err != nil { + log.Fatal(err) + } +} diff --git a/dist/cmd_error.d.ts b/dist/cmd_error.d.ts index cfba6f7..683f787 100644 --- a/dist/cmd_error.d.ts +++ b/dist/cmd_error.d.ts @@ -2,7 +2,7 @@ import { Parser } from "./parser"; export declare class CmdError { args: string[]; env: string[]; - err: any; + error: any; exit: number; filename: string; output: string; diff --git a/dist/cmd_error.js b/dist/cmd_error.js index ade6575..ba87587 100644 --- a/dist/cmd_error.js +++ b/dist/cmd_error.js @@ -8,7 +8,7 @@ export class CmdError { this.output = data.output; this.root = data.root; parser = parser || new Parser(); - this.err = parser.parseError(data.err); + this.error = parser.parseError(data.err); } } // args: [ 'ech', 'Hello World' ], diff --git a/dist/execute_error.d.ts b/dist/execute_error.d.ts index 77f39f0..ae789d1 100644 --- a/dist/execute_error.d.ts +++ b/dist/execute_error.d.ts @@ -2,6 +2,6 @@ import { Parser } from "./parser"; export declare class ExecuteError { filename: string; root: string; - err: any; + error: any; constructor(data: any, parser?: Parser); } diff --git a/dist/execute_error.js b/dist/execute_error.js index 74ac26c..acf6cf4 100644 --- a/dist/execute_error.js +++ b/dist/execute_error.js @@ -4,6 +4,6 @@ export class ExecuteError { this.filename = data.filename; this.root = data.root; parser = parser || new Parser(); - this.err = parser.parseError(data.err); + this.error = parser.parseError(data.err); } } diff --git a/dist/gotypes.d.ts b/dist/gotypes.d.ts index 9590ea0..b9bb450 100644 --- a/dist/gotypes.d.ts +++ b/dist/gotypes.d.ts @@ -1,34 +1,70 @@ declare let gotypes: { + Atom: string; + Atomable: string; + AtomableNode: string; + AttrNode: string; + Attributes: string; Body: string; Cmd: string; - CmdError: string; CmdResult: string; + Comment: string; + Document: string; + Documents: string; Element: string; - ExecuteError: string; + EmptyableNode: string; + ExecutableNode: string; FencedCode: string; Figcaption: string; Figure: string; + HTMLNode: string; Heading: string; - HypeError: string; Image: string; Include: string; InlineCode: string; LI: string; Link: string; + MDNode: string; + Metadata: string; + Node: string; + Nodes: string; + Now: string; OL: string; Page: string; Paragraph: string; - ParseError: string; + Parser: string; + PostExecuter: string; + PostParser: string; + PreExecuter: string; + PreParser: string; + PreParsers: string; Ref: string; - RunError: string; + RefProcessor: string; Snippet: string; + Snippets: string; SourceCode: string; TD: string; TH: string; THead: string; TR: string; Table: string; + Tag: string; + Tags: string; Text: string; + ToC: string; UL: string; + Var: string; + WaitGrouper: string; +}; +declare let goerrors: { + CmdError: string; + ErrAttrEmpty: string; + ErrAttrNotFound: string; + ErrIsNil: string; + ExecuteError: string; + ParseError: string; + PostExecuteError: string; + PostParseError: string; + PreExecuteError: string; + PreParseError: string; }; -export { gotypes }; +export { gotypes, goerrors }; diff --git a/dist/gotypes.js b/dist/gotypes.js index edb7fd5..f55d48a 100644 --- a/dist/gotypes.js +++ b/dist/gotypes.js @@ -1,34 +1,70 @@ let gotypes = { - Body: "*hype.Body", - Cmd: "*hype.Cmd", - CmdError: "hype.CmdError", - CmdResult: "*hype.CmdResult", - Element: "*hype.Element", - ExecuteError: "hype.ExecuteError", - FencedCode: "*hype.FencedCode", - Figcaption: "*hype.Figcaption", - Figure: "*hype.Figure", + Atom: "hype.Atom", + Atomable: "hype.Atomable", + AtomableNode: "hype.AtomableNode", + AttrNode: "hype.AttrNode", + Attributes: "hype.Attributes", + Body: "hype.Body", + Cmd: "hype.Cmd", + CmdResult: "hype.CmdResult", + Comment: "hype.Comment", + Document: "hype.Document", + Documents: "hype.Documents", + Element: "hype.Element", + EmptyableNode: "hype.EmptyableNode", + ExecutableNode: "hype.ExecutableNode", + FencedCode: "hype.FencedCode", + Figcaption: "hype.Figcaption", + Figure: "hype.Figure", + HTMLNode: "hype.HTMLNode", Heading: "hype.Heading", - HypeError: "hype.HypeError", - Image: "*hype.Image", - Include: "*hype.Include", - InlineCode: "*hype.InlineCode", - LI: "*hype.LI", - Link: "*hype.Link", - OL: "*hype.OL", - Page: "*hype.Page", - Paragraph: "*hype.Paragraph", - ParseError: "hype.ParseError", - Ref: "*hype.Ref", - RunError: "clam.RunError", + Image: "hype.Image", + Include: "hype.Include", + InlineCode: "hype.InlineCode", + LI: "hype.LI", + Link: "hype.Link", + MDNode: "hype.MDNode", + Metadata: "hype.Metadata", + Node: "hype.Node", + Nodes: "hype.Nodes", + Now: "hype.Now", + OL: "hype.OL", + Page: "hype.Page", + Paragraph: "hype.Paragraph", + Parser: "hype.Parser", + PostExecuter: "hype.PostExecuter", + PostParser: "hype.PostParser", + PreExecuter: "hype.PreExecuter", + PreParser: "hype.PreParser", + PreParsers: "hype.PreParsers", + Ref: "hype.Ref", + RefProcessor: "hype.RefProcessor", Snippet: "hype.Snippet", - SourceCode: "*hype.SourceCode", - TD: "*hype.TD", - TH: "*hype.TH", - THead: "*hype.THead", - TR: "*hype.TR", - Table: "*hype.Table", + Snippets: "hype.Snippets", + SourceCode: "hype.SourceCode", + TD: "hype.TD", + TH: "hype.TH", + THead: "hype.THead", + TR: "hype.TR", + Table: "hype.Table", + Tag: "hype.Tag", + Tags: "hype.Tags", Text: "hype.Text", - UL: "*hype.UL", + ToC: "hype.ToC", + UL: "hype.UL", + Var: "hype.Var", + WaitGrouper: "hype.WaitGrouper", +}; +let goerrors = { + CmdError: "hype.CmdError", + ErrAttrEmpty: "hype.ErrAttrEmpty", + ErrAttrNotFound: "hype.ErrAttrNotFound", + ErrIsNil: "hype.ErrIsNil", + ExecuteError: "hype.ExecuteError", + ParseError: "hype.ParseError", + PostExecuteError: "hype.PostExecuteError", + PostParseError: "hype.PostParseError", + PreExecuteError: "hype.PreExecuteError", + PreParseError: "hype.PreParseError", }; -export { gotypes }; +export { gotypes, goerrors }; diff --git a/dist/index.d.ts b/dist/index.d.ts index bba8532..1aabd06 100644 --- a/dist/index.d.ts +++ b/dist/index.d.ts @@ -1,8 +1,10 @@ export { Cmd } from "./cmd"; +export { CmdError } from "./cmd_error"; export { CmdResult } from "./cmd_result"; export { Document } from "./document"; export { Element } from "./element"; export { EmptyModule } from "./empty_mod"; +export { ExecuteError } from "./execute_error"; export { FencedCode } from "./fenced_code"; export { FigCaption } from "./fig_caption"; export { Figure } from "./figure"; @@ -21,6 +23,7 @@ export { NewUL } from "./ul"; export { Node } from "./node"; export { OL } from "./ol"; export { Page } from "./page"; +export { ParseError } from "./parse_error"; export { Parser } from "./parser"; export { Ref } from "./ref"; export { Snippet } from "./snippet"; diff --git a/dist/index.js b/dist/index.js index f5c7146..97839d8 100644 --- a/dist/index.js +++ b/dist/index.js @@ -2,37 +2,73 @@ import { v4 } from 'uuid'; import path from 'path-browserify'; let gotypes = { - Body: "*hype.Body", - Cmd: "*hype.Cmd", - CmdError: "hype.CmdError", - CmdResult: "*hype.CmdResult", - Element: "*hype.Element", - ExecuteError: "hype.ExecuteError", - FencedCode: "*hype.FencedCode", - Figcaption: "*hype.Figcaption", - Figure: "*hype.Figure", + Atom: "hype.Atom", + Atomable: "hype.Atomable", + AtomableNode: "hype.AtomableNode", + AttrNode: "hype.AttrNode", + Attributes: "hype.Attributes", + Body: "hype.Body", + Cmd: "hype.Cmd", + CmdResult: "hype.CmdResult", + Comment: "hype.Comment", + Document: "hype.Document", + Documents: "hype.Documents", + Element: "hype.Element", + EmptyableNode: "hype.EmptyableNode", + ExecutableNode: "hype.ExecutableNode", + FencedCode: "hype.FencedCode", + Figcaption: "hype.Figcaption", + Figure: "hype.Figure", + HTMLNode: "hype.HTMLNode", Heading: "hype.Heading", - HypeError: "hype.HypeError", - Image: "*hype.Image", - Include: "*hype.Include", - InlineCode: "*hype.InlineCode", - LI: "*hype.LI", - Link: "*hype.Link", - OL: "*hype.OL", - Page: "*hype.Page", - Paragraph: "*hype.Paragraph", - ParseError: "hype.ParseError", - Ref: "*hype.Ref", - RunError: "clam.RunError", + Image: "hype.Image", + Include: "hype.Include", + InlineCode: "hype.InlineCode", + LI: "hype.LI", + Link: "hype.Link", + MDNode: "hype.MDNode", + Metadata: "hype.Metadata", + Node: "hype.Node", + Nodes: "hype.Nodes", + Now: "hype.Now", + OL: "hype.OL", + Page: "hype.Page", + Paragraph: "hype.Paragraph", + Parser: "hype.Parser", + PostExecuter: "hype.PostExecuter", + PostParser: "hype.PostParser", + PreExecuter: "hype.PreExecuter", + PreParser: "hype.PreParser", + PreParsers: "hype.PreParsers", + Ref: "hype.Ref", + RefProcessor: "hype.RefProcessor", Snippet: "hype.Snippet", - SourceCode: "*hype.SourceCode", - TD: "*hype.TD", - TH: "*hype.TH", - THead: "*hype.THead", - TR: "*hype.TR", - Table: "*hype.Table", + Snippets: "hype.Snippets", + SourceCode: "hype.SourceCode", + TD: "hype.TD", + TH: "hype.TH", + THead: "hype.THead", + TR: "hype.TR", + Table: "hype.Table", + Tag: "hype.Tag", + Tags: "hype.Tags", Text: "hype.Text", - UL: "*hype.UL", + ToC: "hype.ToC", + UL: "hype.UL", + Var: "hype.Var", + WaitGrouper: "hype.WaitGrouper", +}; +let goerrors = { + CmdError: "hype.CmdError", + ErrAttrEmpty: "hype.ErrAttrEmpty", + ErrAttrNotFound: "hype.ErrAttrNotFound", + ErrIsNil: "hype.ErrIsNil", + ExecuteError: "hype.ExecuteError", + ParseError: "hype.ParseError", + PostExecuteError: "hype.PostExecuteError", + PostParseError: "hype.PostParseError", + PreExecuteError: "hype.PreExecuteError", + PreParseError: "hype.PreParseError", }; class Element { @@ -141,6 +177,44 @@ class Document extends Element { } } +class ExecuteError { + constructor(data, parser) { + this.filename = data.filename; + this.root = data.root; + parser = parser || new Parser(); + this.error = parser.parseError(data.err); + } +} + +class FencedCode extends Element { + constructor(fc) { + super(fc); + this.lang = fc.lang; + } +} + +class FigCaption extends Element { + constructor(fc) { + super(fc); + } +} + +class Figure extends Element { + constructor(f) { + super(f); + if (f.style === "") { + f.style = "listing"; + } + if (f.pos < 1) { + f.pos = 1; + } + f.section_id ? f.section_id : 1; + this.pos = f.pos; + this.style = f.style; + this.section_id = f.section_id; + } +} + class Heading extends Element { constructor(n) { super(n); @@ -152,6 +226,31 @@ class Heading extends Element { } } +class Image extends Element { + constructor(img) { + super(img); + } +} + +class Include extends Element { + constructor(el) { + super(el); + this.dir = el.dir; + } +} + +class InlineCode extends Element { + constructor(t) { + super(t); + } +} + +class LI extends Element { + constructor(li) { + super(li); + } +} + // Code generated by gen.go. DO NOT EDIT. let atoms = { A: "a", @@ -554,149 +653,6 @@ function NewLink(url, attrs) { }); } -function VisitAtom(atom, n, fn) { - var _a; - if (n === undefined) { - return; - } - (_a = n.nodes) === null || _a === void 0 ? void 0 : _a.forEach((e) => { - VisitAtom(atom, e, fn); - }); - let atoms = []; - if (Array.isArray(atom)) { - atoms = atom; - } - else { - atoms.push(atom); - } - atoms.forEach((a) => { - if (a === n.atom) { - fn(n); - } - }); - return; -} - -class Toc extends Element { - constructor() { - super({ - nodes: [], - atom: atoms.Ul, - type: gotypes.UL, - attributes: { - class: "hype-toc", - } - }); - this.ids = []; - this.nodes = []; - } - perform(doc, gen) { - VisitAtom(atoms.Headings, doc, (n) => { - let h = new Heading(n); - // this.headings.push(h); - let id = gen ? gen() : newUUID(); - this.ids.push(id); - let a = NewLink(`#${id}`); - let li = NewElement(atoms.Li, { class: `hype-toc-lvl-${h.level}` }); - a.nodes = h.nodes; - li.nodes = [a]; - this.nodes.push(li); - let nodes = n.nodes; - let b = NewElement(atoms.A); - b.attributes = { name: id }; - n.nodes = [b, ...nodes]; - }); - } -} -function newUUID() { - return `heading-${v4()}`; -} - -class CmdError { - constructor(data, parser) { - this.args = data.args; - this.env = data.env; - this.exit = data.exit; - this.filename = data.filename; - this.output = data.output; - this.root = data.root; - parser = parser || new Parser(); - this.err = parser.parseError(data.err); - } -} -// args: [ 'ech', 'Hello World' ], -// env: [ -// ], -// err: 'exec: "ech": executable file not found in $PATH', -// exit: -1, -// filename: 'usage.md', -// output: '', -// root: '/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer', -// type: 'hype.CmdError' - -class ExecuteError { - constructor(data, parser) { - this.filename = data.filename; - this.root = data.root; - parser = parser || new Parser(); - this.err = parser.parseError(data.err); - } -} - -class FencedCode extends Element { - constructor(fc) { - super(fc); - this.lang = fc.lang; - } -} - -class FigCaption extends Element { - constructor(fc) { - super(fc); - } -} - -class Figure extends Element { - constructor(f) { - super(f); - if (f.style === "") { - f.style = "listing"; - } - if (f.pos < 1) { - f.pos = 1; - } - f.section_id ? f.section_id : 1; - this.pos = f.pos; - this.style = f.style; - this.section_id = f.section_id; - } -} - -class Image extends Element { - constructor(img) { - super(img); - } -} - -class Include extends Element { - constructor(el) { - super(el); - this.dir = el.dir; - } -} - -class InlineCode extends Element { - constructor(t) { - super(t); - } -} - -class LI extends Element { - constructor(li) { - super(li); - } -} - class OL extends Element { constructor(ol) { super(ol); @@ -714,7 +670,7 @@ class ParseError { this.filename = data.filename; this.root = data.root; parser = parser || new Parser(); - this.err = parser.parseError(data.err); + this.error = parser.parseError(data.err); } } @@ -786,35 +742,40 @@ function NewUL(attrs) { }); } +class PostParseError { + constructor(data, parser) { + this.filename = data.filename; + this.postparser = data.postparser; + this.root = data.root; + this.type = data.type; + parser = parser || new Parser(); + this.error = parser.parseError(data.error); + this.orig_error = parser.parseError(data.orig_error); + } +} + class Parser { constructor() { this.handlers = {}; - this.handlers[gotypes.Body] = newElement; - this.handlers[gotypes.Element] = newElement; - this.handlers[gotypes.Paragraph] = newElement; - this.handlers[gotypes.TD] = newElement; - this.handlers[gotypes.TH] = newElement; - this.handlers[gotypes.THead] = newElement; - this.handlers[gotypes.TR] = newElement; - this.handlers[gotypes.CmdResult] = (n) => new CmdResult(n); - this.handlers[gotypes.Cmd] = (n) => new Cmd(n); - this.handlers[gotypes.FencedCode] = (n) => new FencedCode(n); - this.handlers[gotypes.Figcaption] = (n) => new FigCaption(n); - this.handlers[gotypes.Figure] = (n) => new Figure(n); - this.handlers[gotypes.Heading] = (n) => new Heading(n); - this.handlers[gotypes.Image] = (n) => new Image(n); - this.handlers[gotypes.Include] = (n) => new Include(n); - this.handlers[gotypes.InlineCode] = (n) => new InlineCode(n); - this.handlers[gotypes.LI] = (n) => new LI(n); - this.handlers[gotypes.Link] = (n) => new Link(n); - this.handlers[gotypes.OL] = (n) => new OL(n); - this.handlers[gotypes.Page] = (n) => new Page(n); - this.handlers[gotypes.Ref] = (n) => new Ref(n); - this.handlers[gotypes.Snippet] = (n) => new Snippet(n); - this.handlers[gotypes.SourceCode] = (n) => new SourceCode(n); - this.handlers[gotypes.Table] = (n) => new Table(n); - this.handlers[gotypes.Text] = (n) => new Text(n); - this.handlers[gotypes.UL] = (n) => new UL(n); + this.handlers[gotypes.CmdResult] = (n) => [new CmdResult(n)]; + this.handlers[gotypes.Cmd] = (n) => [new Cmd(n)]; + this.handlers[gotypes.FencedCode] = (n) => [new FencedCode(n)]; + this.handlers[gotypes.Figcaption] = (n) => [new FigCaption(n)]; + this.handlers[gotypes.Figure] = (n) => [new Figure(n)]; + this.handlers[gotypes.Heading] = (n) => [new Heading(n)]; + this.handlers[gotypes.Image] = (n) => [new Image(n)]; + this.handlers[gotypes.Include] = (n) => [new Include(n)]; + this.handlers[gotypes.InlineCode] = (n) => [new InlineCode(n)]; + this.handlers[gotypes.LI] = (n) => [new LI(n)]; + this.handlers[gotypes.Link] = (n) => [new Link(n)]; + this.handlers[gotypes.OL] = (n) => [new OL(n)]; + this.handlers[gotypes.Page] = (n) => [new Page(n)]; + this.handlers[gotypes.Ref] = (n) => [new Ref(n)]; + this.handlers[gotypes.Snippet] = (n) => [new Snippet(n)]; + this.handlers[gotypes.SourceCode] = (n) => [new SourceCode(n)]; + this.handlers[gotypes.Table] = (n) => [new Table(n)]; + this.handlers[gotypes.Text] = (n) => [new Text(n)]; + this.handlers[gotypes.UL] = (n) => [new UL(n)]; } parse(data) { data = structuredClone(data); @@ -823,17 +784,25 @@ class Parser { } parseError(data) { switch (data.type) { - case gotypes.ExecuteError: + case goerrors.ExecuteError: return new ExecuteError(data, this); - case gotypes.CmdError: + case goerrors.CmdError: return new CmdError(data, this); - case gotypes.ParseError: + case goerrors.ParseError: return new ParseError(data, this); + case goerrors.PostParseError: + return new PostParseError(data, this); + case goerrors.PostExecuteError: + throw new Error("not implemented: " + data.type); + case goerrors.PreExecuteError: + throw new Error("not implemented: " + data.type); + case goerrors.PreParseError: + throw new Error("not implemented: " + data.type); default: if (data.type === undefined) { return data; } - console.warn("parseError: unknown type: ", data.type); + // console.warn("parseError: unknown type: ", data.type) return data; } } @@ -851,17 +820,97 @@ class Parser { n.nodes = this.parseNodes(n.nodes); let fn = this.handlers[n.type]; if (fn === undefined) { - console.warn("unknown node type: " + n.type); + // console.warn("unknown node type: " + n.type) fn = newElement; } - ret.push(fn(n)); + ret.push(...fn(n)); } }); return ret; } } function newElement(n) { - return new Element(n); + return [new Element(n)]; +} + +class CmdError { + constructor(data, parser) { + this.args = data.args; + this.env = data.env; + this.exit = data.exit; + this.filename = data.filename; + this.output = data.output; + this.root = data.root; + parser = parser || new Parser(); + this.error = parser.parseError(data.err); + } +} +// args: [ 'ech', 'Hello World' ], +// env: [ +// ], +// err: 'exec: "ech": executable file not found in $PATH', +// exit: -1, +// filename: 'usage.md', +// output: '', +// root: '/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer', +// type: 'hype.CmdError' + +function VisitAtom(atom, n, fn) { + var _a; + if (n === undefined) { + return; + } + (_a = n.nodes) === null || _a === void 0 ? void 0 : _a.forEach((e) => { + VisitAtom(atom, e, fn); + }); + let atoms = []; + if (Array.isArray(atom)) { + atoms = atom; + } + else { + atoms.push(atom); + } + atoms.forEach((a) => { + if (a === n.atom) { + fn(n); + } + }); + return; +} + +class Toc extends Element { + constructor() { + super({ + nodes: [], + atom: atoms.Ul, + type: gotypes.UL, + attributes: { + class: "hype-toc", + } + }); + this.ids = []; + this.nodes = []; + } + perform(doc, gen) { + VisitAtom(atoms.Headings, doc, (n) => { + let h = new Heading(n); + // this.headings.push(h); + let id = gen ? gen() : newUUID(); + this.ids.push(id); + let a = NewLink(`#${id}`); + let li = NewElement(atoms.Li, { class: `hype-toc-lvl-${h.level}` }); + a.nodes = h.nodes; + li.nodes = [a]; + this.nodes.push(li); + let nodes = n.nodes; + let b = NewElement(atoms.A); + b.attributes = { name: id }; + n.nodes = [b, ...nodes]; + }); + } +} +function newUUID() { + return `heading-${v4()}`; } class Module { @@ -947,4 +996,4 @@ class Modules { } } -export { Cmd, CmdResult, Document, Element, EmptyModule, FencedCode, FigCaption, Figure, Heading, Image, Include, InlineCode, LI, Link, Module, Modules, NewElement, NewLink, NewText, NewUL, OL, Page, Parser, Ref, Snippet, SourceCode, Table, Text, Toc, UL, VisitAtom, atoms, gotypes }; +export { Cmd, CmdError, CmdResult, Document, Element, EmptyModule, ExecuteError, FencedCode, FigCaption, Figure, Heading, Image, Include, InlineCode, LI, Link, Module, Modules, NewElement, NewLink, NewText, NewUL, OL, Page, ParseError, Parser, Ref, Snippet, SourceCode, Table, Text, Toc, UL, VisitAtom, atoms, gotypes }; diff --git a/dist/parse_error.d.ts b/dist/parse_error.d.ts index e7cc227..e2e5276 100644 --- a/dist/parse_error.d.ts +++ b/dist/parse_error.d.ts @@ -2,6 +2,6 @@ import { Parser } from "./parser"; export declare class ParseError { filename: string; root: string; - err: any; + error: any; constructor(data: any, parser?: Parser); } diff --git a/dist/parse_error.js b/dist/parse_error.js index 92670fe..64571ee 100644 --- a/dist/parse_error.js +++ b/dist/parse_error.js @@ -4,6 +4,6 @@ export class ParseError { this.filename = data.filename; this.root = data.root; parser = parser || new Parser(); - this.err = parser.parseError(data.err); + this.error = parser.parseError(data.err); } } diff --git a/dist/parser.d.ts b/dist/parser.d.ts index 1b482d8..ee81ae4 100644 --- a/dist/parser.d.ts +++ b/dist/parser.d.ts @@ -1,8 +1,13 @@ +import type { Node } from "./node"; import { Document } from "./document"; +type NodeParseFn = (n: any) => Node[]; export declare class Parser { - handlers: any; + handlers: { + [key: string]: NodeParseFn; + }; constructor(); parse(data: any): Document; parseError(data: any): any; private parseNodes; } +export {}; diff --git a/dist/parser.js b/dist/parser.js index 63ac658..48c0566 100644 --- a/dist/parser.js +++ b/dist/parser.js @@ -22,36 +22,30 @@ import { SourceCode } from "./source_code"; import { Table } from "./table"; import { Text } from "./text"; import { UL } from "./ul"; -import { gotypes } from "./gotypes"; +import { gotypes, goerrors } from "./gotypes"; +import { PostParseError } from "./post_parse_error"; export class Parser { constructor() { this.handlers = {}; - this.handlers[gotypes.Body] = newElement; - this.handlers[gotypes.Element] = newElement; - this.handlers[gotypes.Paragraph] = newElement; - this.handlers[gotypes.TD] = newElement; - this.handlers[gotypes.TH] = newElement; - this.handlers[gotypes.THead] = newElement; - this.handlers[gotypes.TR] = newElement; - this.handlers[gotypes.CmdResult] = (n) => new CmdResult(n); - this.handlers[gotypes.Cmd] = (n) => new Cmd(n); - this.handlers[gotypes.FencedCode] = (n) => new FencedCode(n); - this.handlers[gotypes.Figcaption] = (n) => new FigCaption(n); - this.handlers[gotypes.Figure] = (n) => new Figure(n); - this.handlers[gotypes.Heading] = (n) => new Heading(n); - this.handlers[gotypes.Image] = (n) => new Image(n); - this.handlers[gotypes.Include] = (n) => new Include(n); - this.handlers[gotypes.InlineCode] = (n) => new InlineCode(n); - this.handlers[gotypes.LI] = (n) => new LI(n); - this.handlers[gotypes.Link] = (n) => new Link(n); - this.handlers[gotypes.OL] = (n) => new OL(n); - this.handlers[gotypes.Page] = (n) => new Page(n); - this.handlers[gotypes.Ref] = (n) => new Ref(n); - this.handlers[gotypes.Snippet] = (n) => new Snippet(n); - this.handlers[gotypes.SourceCode] = (n) => new SourceCode(n); - this.handlers[gotypes.Table] = (n) => new Table(n); - this.handlers[gotypes.Text] = (n) => new Text(n); - this.handlers[gotypes.UL] = (n) => new UL(n); + this.handlers[gotypes.CmdResult] = (n) => [new CmdResult(n)]; + this.handlers[gotypes.Cmd] = (n) => [new Cmd(n)]; + this.handlers[gotypes.FencedCode] = (n) => [new FencedCode(n)]; + this.handlers[gotypes.Figcaption] = (n) => [new FigCaption(n)]; + this.handlers[gotypes.Figure] = (n) => [new Figure(n)]; + this.handlers[gotypes.Heading] = (n) => [new Heading(n)]; + this.handlers[gotypes.Image] = (n) => [new Image(n)]; + this.handlers[gotypes.Include] = (n) => [new Include(n)]; + this.handlers[gotypes.InlineCode] = (n) => [new InlineCode(n)]; + this.handlers[gotypes.LI] = (n) => [new LI(n)]; + this.handlers[gotypes.Link] = (n) => [new Link(n)]; + this.handlers[gotypes.OL] = (n) => [new OL(n)]; + this.handlers[gotypes.Page] = (n) => [new Page(n)]; + this.handlers[gotypes.Ref] = (n) => [new Ref(n)]; + this.handlers[gotypes.Snippet] = (n) => [new Snippet(n)]; + this.handlers[gotypes.SourceCode] = (n) => [new SourceCode(n)]; + this.handlers[gotypes.Table] = (n) => [new Table(n)]; + this.handlers[gotypes.Text] = (n) => [new Text(n)]; + this.handlers[gotypes.UL] = (n) => [new UL(n)]; } parse(data) { let doc; @@ -61,17 +55,25 @@ export class Parser { } parseError(data) { switch (data.type) { - case gotypes.ExecuteError: + case goerrors.ExecuteError: return new ExecuteError(data, this); - case gotypes.CmdError: + case goerrors.CmdError: return new CmdError(data, this); - case gotypes.ParseError: + case goerrors.ParseError: return new ParseError(data, this); + case goerrors.PostParseError: + return new PostParseError(data, this); + case goerrors.PostExecuteError: + throw new Error("not implemented: " + data.type); + case goerrors.PreExecuteError: + throw new Error("not implemented: " + data.type); + case goerrors.PreParseError: + throw new Error("not implemented: " + data.type); default: if (data.type === undefined) { return data; } - console.warn("parseError: unknown type: ", data.type); + // console.warn("parseError: unknown type: ", data.type) return data; } } @@ -89,15 +91,15 @@ export class Parser { n.nodes = this.parseNodes(n.nodes); let fn = this.handlers[n.type]; if (fn === undefined) { - console.warn("unknown node type: " + n.type); + // console.warn("unknown node type: " + n.type) fn = newElement; } - ret.push(fn(n)); + ret.push(...fn(n)); } }); return ret; } } function newElement(n) { - return new Element(n); + return [new Element(n)]; } diff --git a/dist/post_parse_error.d.ts b/dist/post_parse_error.d.ts new file mode 100644 index 0000000..026926b --- /dev/null +++ b/dist/post_parse_error.d.ts @@ -0,0 +1,10 @@ +import { Parser } from './parser'; +export declare class PostParseError { + error: any; + filename: string; + orig_error: any; + postparser: string; + root: string; + type: string; + constructor(data: any, parser?: Parser); +} diff --git a/dist/post_parse_error.js b/dist/post_parse_error.js new file mode 100644 index 0000000..d3ff4da --- /dev/null +++ b/dist/post_parse_error.js @@ -0,0 +1,12 @@ +import { Parser } from './parser'; +export class PostParseError { + constructor(data, parser) { + this.filename = data.filename; + this.postparser = data.postparser; + this.root = data.root; + this.type = data.type; + parser = parser || new Parser(); + this.error = parser.parseError(data.error); + this.orig_error = parser.parseError(data.orig_error); + } +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..9eea379 --- /dev/null +++ b/go.mod @@ -0,0 +1,28 @@ +module github.com/gopherjs/hypejs + +go 1.22 + +require ( + github.com/gopherguides/hype v0.1.2 + github.com/markbates/hepa v0.0.0-20211129002629-856d16f89b9d + github.com/stretchr/testify v1.8.4 + golang.org/x/sync v0.6.0 +) + +require ( + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/gobuffalo/flect v1.0.2 // indirect + github.com/gofrs/uuid/v5 v5.0.0 // indirect + github.com/markbates/clam v0.0.0-20240219024730-b98cdab94ec3 // indirect + github.com/markbates/sweets v0.0.0-20210926032915-062eb9bcc0e5 // indirect + github.com/markbates/syncx v1.5.1 // indirect + github.com/markbates/table v0.0.0-20230314205021-441ed58296d1 // indirect + github.com/mattn/go-shellwords v1.0.12 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/russross/blackfriday/v2 v2.1.0 // indirect + golang.org/x/exp v0.0.0-20240213143201-ec583247a57a // indirect + golang.org/x/net v0.21.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) + +replace github.com/gopherguides/hype => ../hype diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..f837be0 --- /dev/null +++ b/go.sum @@ -0,0 +1,47 @@ +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/gobuffalo/flect v1.0.2 h1:eqjPGSo2WmjgY2XlpGwo2NXgL3RucAKo4k4qQMNA5sA= +github.com/gobuffalo/flect v1.0.2/go.mod h1:A5msMlrHtLqh9umBSnvabjsMrCcCpAyzglnDvkbYKHs= +github.com/gofrs/uuid/v5 v5.0.0 h1:p544++a97kEL+svbcFbCQVM9KFu0Yo25UoISXGNNH9M= +github.com/gofrs/uuid/v5 v5.0.0/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8= +github.com/gopherguides/hype v0.1.2 h1:9/z2wBlU3A2dgtM0/IlrMCMUAM2PzKin4w3cklXJCA8= +github.com/gopherguides/hype v0.1.2/go.mod h1:Qwkl3ojdz2+cdgEikNQck/TxnengkfzgAbeTfyTis8w= +github.com/markbates/clam v0.0.0-20220808175708-ef60f46826fb h1:9V50gZSw997pZqgLCjhyApFsS8JA1sIZmD+3+MLJcl4= +github.com/markbates/clam v0.0.0-20220808175708-ef60f46826fb/go.mod h1:5bD7elUD4b404zK6eOn4Q0wKJYb0mxL6yDeQZSRn9Hk= +github.com/markbates/clam v0.0.0-20240219024730-b98cdab94ec3 h1:dD7cV95C3jWtuBfJycK6D8uuli0FJK4md9RSRV2/LHU= +github.com/markbates/clam v0.0.0-20240219024730-b98cdab94ec3/go.mod h1:sLg6WXuDjdORMJaWZHBuzW6IcfjaYLaktEtdXxdM/Sk= +github.com/markbates/hepa v0.0.0-20211129002629-856d16f89b9d h1:+2OKR5x2iAJTQ2/u8Uyk1hOnJ8pneNV298dhJ0DO0nU= +github.com/markbates/hepa v0.0.0-20211129002629-856d16f89b9d/go.mod h1:YCs1lt0wCv6j/HTzT2V/bUWKgdXlOXwTz0118HvMGAo= +github.com/markbates/sweets v0.0.0-20210926032915-062eb9bcc0e5 h1:od8GvggTptD2HUz8nGaQQe6n1zAHDbsG+82hfHPNExY= +github.com/markbates/sweets v0.0.0-20210926032915-062eb9bcc0e5/go.mod h1:NMNrJiINR9aeBgn5wfzZMJOnwWnDaj4hDOGpGoVV3XE= +github.com/markbates/syncx v1.5.1 h1:Kv0hrHUOU0FQ27QgiYf2SDo0JSQ04KcaLysyOtBYrcY= +github.com/markbates/syncx v1.5.1/go.mod h1:bOJr9+255qZxDuYK+YupRlTNDVZBJvcpuWRqomeM39o= +github.com/markbates/table v0.0.0-20230314205021-441ed58296d1 h1:pai/4PecxeuRlO1Nyljteq/vH02eVoLrlx4UwEucBSE= +github.com/markbates/table v0.0.0-20230314205021-441ed58296d1/go.mod h1:j43uhc/bgGCB5WR8/r0ta0GL/PgRXKvoBl3bXnsX7AE= +github.com/mattn/go-shellwords v1.0.12 h1:M2zGm7EW6UQJvDeQxo4T51eKPurbeFbe8WtebGE2xrk= +github.com/mattn/go-shellwords v1.0.12/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +golang.org/x/exp v0.0.0-20240205201215-2c58cdc269a3 h1:/RIbNt/Zr7rVhIkQhooTxCxFcdWLGIKnZA4IXNFSrvo= +golang.org/x/exp v0.0.0-20240205201215-2c58cdc269a3/go.mod h1:idGWGoKP1toJGkd5/ig9ZLuPcZBC3ewk7SzmH0uou08= +golang.org/x/exp v0.0.0-20240213143201-ec583247a57a h1:HinSgX1tJRX3KsL//Gxynpw5CTOAIPhgL4W8PNiIpVE= +golang.org/x/exp v0.0.0-20240213143201-ec583247a57a/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc= +golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4= +golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= +golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= +golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/index.d.ts b/index.d.ts index 4f33f1b..887c6de 100644 --- a/index.d.ts +++ b/index.d.ts @@ -26,18 +26,6 @@ declare class Cmd extends Element { constructor(c: any); } -declare class CmdResult extends Element { - result: { - args: string[]; - dir: string; - stdout: string; - duration: number; - exit: number; - stderr: string; - }; - constructor(cr: any); -} - declare class Document extends Element { id: string; root: string; @@ -55,21 +43,47 @@ declare class Document extends Element { toHtml(): string; } -declare class Toc extends Element { - ids: string[]; - nodes: Node[]; - constructor(); - perform(doc: Document, gen?: () => string): void; -} - +type NodeParseFn = (n: any) => Node[]; declare class Parser { - handlers: any; + handlers: { + [key: string]: NodeParseFn; + }; constructor(); parse(data: any): Document; parseError(data: any): any; private parseNodes; } +declare class CmdError { + args: string[]; + env: string[]; + error: any; + exit: number; + filename: string; + output: string; + root: string; + constructor(data: any, parser?: Parser); +} + +declare class CmdResult extends Element { + result: { + args: string[]; + dir: string; + stdout: string; + duration: number; + exit: number; + stderr: string; + }; + constructor(cr: any); +} + +declare class Toc extends Element { + ids: string[]; + nodes: Node[]; + constructor(); + perform(doc: Document, gen?: () => string): void; +} + declare class Module { id: string; filepath: string; @@ -85,6 +99,13 @@ declare class Module { declare function EmptyModule(): Module; +declare class ExecuteError { + filename: string; + root: string; + error: any; + constructor(data: any, parser?: Parser); +} + declare class FencedCode extends Element { lang: string; constructor(fc: any); @@ -163,6 +184,13 @@ declare class Page extends Element { constructor(n: any); } +declare class ParseError { + filename: string; + root: string; + error: any; + constructor(data: any, parser?: Parser); +} + declare class Ref extends Element { constructor(r: any); } @@ -572,37 +600,61 @@ declare let atoms: { }; declare let gotypes: { + Atom: string; + Atomable: string; + AtomableNode: string; + AttrNode: string; + Attributes: string; Body: string; Cmd: string; - CmdError: string; CmdResult: string; + Comment: string; + Document: string; + Documents: string; Element: string; - ExecuteError: string; + EmptyableNode: string; + ExecutableNode: string; FencedCode: string; Figcaption: string; Figure: string; + HTMLNode: string; Heading: string; - HypeError: string; Image: string; Include: string; InlineCode: string; LI: string; Link: string; + MDNode: string; + Metadata: string; + Node: string; + Nodes: string; + Now: string; OL: string; Page: string; Paragraph: string; - ParseError: string; + Parser: string; + PostExecuter: string; + PostParser: string; + PreExecuter: string; + PreParser: string; + PreParsers: string; Ref: string; - RunError: string; + RefProcessor: string; Snippet: string; + Snippets: string; SourceCode: string; TD: string; TH: string; THead: string; TR: string; Table: string; + Tag: string; + Tags: string; Text: string; + ToC: string; UL: string; + Var: string; + WaitGrouper: string; }; -export { Cmd, CmdResult, Document, Element, EmptyModule, FencedCode, FigCaption, Figure, Heading, Image, Include, InlineCode, LI, Link, Module, Modules, NewElement, NewLink, NewText, NewUL, type Node, OL, Page, Parser, Ref, Snippet, SourceCode, Table, Text, Toc, UL, VisitAtom, type VisitNode, atoms, gotypes }; +export { Cmd, CmdError, CmdResult, Document, Element, EmptyModule, ExecuteError, FencedCode, FigCaption, Figure, Heading, Image, Include, InlineCode, LI, Link, Module, Modules, NewElement, NewLink, NewText, NewUL, type Node, OL, Page, ParseError, Parser, Ref, Snippet, SourceCode, Table, Text, Toc, UL, VisitAtom, type VisitNode, atoms, gotypes }; diff --git a/src/cmd_error.ts b/src/cmd_error.ts index 93fc0f1..342419c 100644 --- a/src/cmd_error.ts +++ b/src/cmd_error.ts @@ -4,7 +4,7 @@ import { Parser } from "./parser"; export class CmdError { args: string[]; env: string[]; - err: any; + error: any; exit: number; filename: string; output: string; @@ -19,7 +19,7 @@ export class CmdError { this.root = data.root; parser = parser || new Parser(); - this.err = parser.parseError(data.err); + this.error = parser.parseError(data.err); } } // args: [ 'ech', 'Hello World' ], diff --git a/src/document.spec.ts b/src/document.spec.ts index a1022a1..e8c5e6f 100644 --- a/src/document.spec.ts +++ b/src/document.spec.ts @@ -1,5 +1,6 @@ import exp from "constants"; import { Parser } from "./parser"; +import { gotypes } from "./gotypes"; describe('document', () => { @@ -12,34 +13,19 @@ describe('document', () => { } let tcs: tc[] = [ - { - name: "arrays", - input: require('./testdata/arrays.json'), - title: "Arrays, Slices, and Iteration" - }, { name: "errors", - input: require('./testdata/errors.json'), + input: require('./testdata/09-errors.json'), title: "Errors", }, { name: "generics", - input: require('./testdata/generics.json'), + input: require('./testdata/10-generics.json'), title: "Generics", }, - { - name: "files", - input: require('./testdata/files.json'), - title: "Working With Files", - }, - { - name: "channels", - input: require('./testdata/channels.json'), - title: "Channels", - }, { name: "context", - input: require('./testdata/context.json'), + input: require('./testdata/12-context.json'), title: "Context", } ] @@ -51,7 +37,7 @@ describe('document', () => { expect(d.id).toBeDefined(); expect(d.atom).toBeUndefined(); - expect(d.type).toEqual("*hype.Document"); + expect(d.type).toEqual(gotypes.Document); expect(d.title).toEqual(tc.title); expect(d.nodes?.length).toEqual(1); diff --git a/src/execute_error.ts b/src/execute_error.ts index 528a600..07a8eba 100644 --- a/src/execute_error.ts +++ b/src/execute_error.ts @@ -4,13 +4,13 @@ import { Parser } from "./parser"; export class ExecuteError { filename: string; root: string; - err: any; + error: any; constructor(data: any, parser?: Parser) { this.filename = data.filename; this.root = data.root; parser = parser || new Parser(); - this.err = parser.parseError(data.err); + this.error = parser.parseError(data.err); } } \ No newline at end of file diff --git a/src/gotypes.ts b/src/gotypes.ts index dc5f4fc..0b869ff 100644 --- a/src/gotypes.ts +++ b/src/gotypes.ts @@ -1,35 +1,72 @@ let gotypes = { - Body: "*hype.Body", - Cmd: "*hype.Cmd", - CmdError: "hype.CmdError", - CmdResult: "*hype.CmdResult", - Element: "*hype.Element", - ExecuteError: "hype.ExecuteError", - FencedCode: "*hype.FencedCode", - Figcaption: "*hype.Figcaption", - Figure: "*hype.Figure", - Heading: "hype.Heading", - HypeError: "hype.HypeError", - Image: "*hype.Image", - Include: "*hype.Include", - InlineCode: "*hype.InlineCode", - LI: "*hype.LI", - Link: "*hype.Link", - OL: "*hype.OL", - Page: "*hype.Page", - Paragraph: "*hype.Paragraph", - ParseError: "hype.ParseError", - Ref: "*hype.Ref", - RunError: "clam.RunError", - Snippet: "hype.Snippet", - SourceCode: "*hype.SourceCode", - TD: "*hype.TD", - TH: "*hype.TH", - THead: "*hype.THead", - TR: "*hype.TR", - Table: "*hype.Table", - Text: "hype.Text", - UL: "*hype.UL", + Atom: "hype.Atom", + Atomable: "hype.Atomable", + AtomableNode: "hype.AtomableNode", + AttrNode: "hype.AttrNode", + Attributes: "hype.Attributes", + Body: "hype.Body", + Cmd: "hype.Cmd", + CmdResult: "hype.CmdResult", + Comment: "hype.Comment", + Document: "hype.Document", + Documents: "hype.Documents", + Element: "hype.Element", + EmptyableNode: "hype.EmptyableNode", + ExecutableNode: "hype.ExecutableNode", + FencedCode: "hype.FencedCode", + Figcaption: "hype.Figcaption", + Figure: "hype.Figure", + HTMLNode: "hype.HTMLNode", + Heading: "hype.Heading", + Image: "hype.Image", + Include: "hype.Include", + InlineCode: "hype.InlineCode", + LI: "hype.LI", + Link: "hype.Link", + MDNode: "hype.MDNode", + Metadata: "hype.Metadata", + Node: "hype.Node", + Nodes: "hype.Nodes", + Now: "hype.Now", + OL: "hype.OL", + Page: "hype.Page", + Paragraph: "hype.Paragraph", + Parser: "hype.Parser", + PostExecuter: "hype.PostExecuter", + PostParser: "hype.PostParser", + PreExecuter: "hype.PreExecuter", + PreParser: "hype.PreParser", + PreParsers: "hype.PreParsers", + Ref: "hype.Ref", + RefProcessor: "hype.RefProcessor", + Snippet: "hype.Snippet", + Snippets: "hype.Snippets", + SourceCode: "hype.SourceCode", + TD: "hype.TD", + TH: "hype.TH", + THead: "hype.THead", + TR: "hype.TR", + Table: "hype.Table", + Tag: "hype.Tag", + Tags: "hype.Tags", + Text: "hype.Text", + ToC: "hype.ToC", + UL: "hype.UL", + Var: "hype.Var", + WaitGrouper: "hype.WaitGrouper", } -export { gotypes } \ No newline at end of file +let goerrors = { + CmdError: "hype.CmdError", + ErrAttrEmpty: "hype.ErrAttrEmpty", + ErrAttrNotFound: "hype.ErrAttrNotFound", + ErrIsNil: "hype.ErrIsNil", + ExecuteError: "hype.ExecuteError", + ParseError: "hype.ParseError", + PostExecuteError: "hype.PostExecuteError", + PostParseError: "hype.PostParseError", + PreExecuteError: "hype.PreExecuteError", + PreParseError: "hype.PreParseError", +} + +export { gotypes, goerrors } diff --git a/src/module.spec.ts b/src/module.spec.ts index 40f64db..0ebf2a0 100644 --- a/src/module.spec.ts +++ b/src/module.spec.ts @@ -6,7 +6,7 @@ import { Toc } from "./toc" describe('module', () => { - let data = require("./testdata/context.json") + let data = require("./testdata/12-context.json") test("should parse", () => { let mod: Module = new Module(data) diff --git a/src/parse_error.spec.ts b/src/parse_error.spec.ts index 172782d..897a6f7 100644 --- a/src/parse_error.spec.ts +++ b/src/parse_error.spec.ts @@ -4,10 +4,12 @@ import { ExecuteError } from "./execute_error"; import { CmdError } from "./cmd_error"; import { Parser } from "./parser"; import { parse } from "path"; +import { PostParseError } from "./post_parse_error"; describe("ParseError", () => { let cmdData = require("./testdata/errors/cmd.json") let parseData = require("./testdata/errors/parse.json") + let postParseData = require("./testdata/errors/post_parse.json") let parser = new Parser(); @@ -17,7 +19,7 @@ describe("ParseError", () => { expect(err.root).toBe(cmdData.root); expect(err).toBeInstanceOf(ExecuteError); - expect(err.err).toBeInstanceOf(CmdError); + expect(err.error).toBeInstanceOf(CmdError); }); test("parse error", () => { @@ -26,6 +28,15 @@ describe("ParseError", () => { expect(err.root).toBe(parseData.root); expect(err).toBeInstanceOf(ParseError); - expect(err.err).toBeDefined(); + expect(err.error).toBeDefined(); + }); + + test("parse post parse error", () => { + let err = parser.parseError(postParseData); + expect(err.filename).toBe(postParseData.filename); + expect(err.root).toBe(postParseData.root); + + expect(err).toBeInstanceOf(PostParseError); + expect(err.error).toBeDefined(); }); }); \ No newline at end of file diff --git a/src/parse_error.ts b/src/parse_error.ts index 32098e0..465a467 100644 --- a/src/parse_error.ts +++ b/src/parse_error.ts @@ -6,13 +6,13 @@ import { Parser } from "./parser"; export class ParseError { filename: string; root: string; - err: any; + error: any; constructor(data: any, parser?: Parser) { this.filename = data.filename; this.root = data.root; parser = parser || new Parser(); - this.err = parser.parseError(data.err); + this.error = parser.parseError(data.err); } } \ No newline at end of file diff --git a/src/parser.spec.ts b/src/parser.spec.ts index 5f58b55..1630165 100644 --- a/src/parser.spec.ts +++ b/src/parser.spec.ts @@ -1,4 +1,5 @@ import exp from "constants"; +import { gotypes } from "./gotypes"; import { Parser } from "./parser"; import { Element } from "./element"; @@ -14,13 +15,13 @@ describe('parser', () => { let data = require("./testdata/custom.json") let p: Parser = new Parser(); - p.handlers["CustomTag"] = (n: any) => new CustomTag(n) + p.handlers["CustomTag"] = (n: any) => [new CustomTag(n)] let d = p.parse(data); expect(d.id).toBeDefined(); expect(d.atom).toBeUndefined(); - expect(d.type).toEqual("*hype.Document"); + expect(d.type).toEqual(gotypes.Document); expect(d.title).toEqual("Custom Tags"); expect(d.nodes?.length).toEqual(1); }) diff --git a/src/parser.ts b/src/parser.ts index 94c991d..dda71b6 100644 --- a/src/parser.ts +++ b/src/parser.ts @@ -23,39 +23,47 @@ import { SourceCode } from "./source_code"; import { Table } from "./table"; import { Text } from "./text"; import { UL } from "./ul"; -import { gotypes } from "./gotypes"; +import { gotypes, goerrors } from "./gotypes"; +import { PostParseError } from "./post_parse_error"; + +type NodeParseFn = (n: any) => Node[]; export class Parser { - handlers: any = {} + handlers: { [key: string]: NodeParseFn } = {} constructor() { - this.handlers[gotypes.Body] = newElement - this.handlers[gotypes.Element] = newElement - this.handlers[gotypes.Paragraph] = newElement - this.handlers[gotypes.TD] = newElement - this.handlers[gotypes.TH] = newElement - this.handlers[gotypes.THead] = newElement - this.handlers[gotypes.TR] = newElement - this.handlers[gotypes.CmdResult] = (n: any) => new CmdResult(n) - this.handlers[gotypes.Cmd] = (n: any) => new Cmd(n) - this.handlers[gotypes.FencedCode] = (n: any) => new FencedCode(n) - this.handlers[gotypes.Figcaption] = (n: any) => new FigCaption(n) - this.handlers[gotypes.Figure] = (n: any) => new Figure(n) - this.handlers[gotypes.Heading] = (n: any) => new Heading(n) - this.handlers[gotypes.Image] = (n: any) => new Image(n) - this.handlers[gotypes.Include] = (n: any) => new Include(n) - this.handlers[gotypes.InlineCode] = (n: any) => new InlineCode(n) - this.handlers[gotypes.LI] = (n: any) => new LI(n) - this.handlers[gotypes.Link] = (n: any) => new Link(n) - this.handlers[gotypes.OL] = (n: any) => new OL(n) - this.handlers[gotypes.Page] = (n: any) => new Page(n) - this.handlers[gotypes.Ref] = (n: any) => new Ref(n) - this.handlers[gotypes.Snippet] = (n: any) => new Snippet(n) - this.handlers[gotypes.SourceCode] = (n: any) => new SourceCode(n) - this.handlers[gotypes.Table] = (n: any) => new Table(n) - this.handlers[gotypes.Text] = (n: any) => new Text(n) - this.handlers[gotypes.UL] = (n: any) => new UL(n) + this.handlers[gotypes.CmdResult] = (n: any) => [new CmdResult(n)] + this.handlers[gotypes.Cmd] = (n: any) => [new Cmd(n)] + this.handlers[gotypes.FencedCode] = (n: any) => [new FencedCode(n)] + this.handlers[gotypes.Figcaption] = (n: any) => [new FigCaption(n)] + this.handlers[gotypes.Figure] = (n: any) => [new Figure(n)] + this.handlers[gotypes.Heading] = (n: any) => [new Heading(n)] + this.handlers[gotypes.Image] = (n: any) => [new Image(n)] + this.handlers[gotypes.Include] = (n: any) => [new Include(n)] + this.handlers[gotypes.InlineCode] = (n: any) => [new InlineCode(n)] + this.handlers[gotypes.LI] = (n: any) => [new LI(n)] + this.handlers[gotypes.Link] = (n: any) => [new Link(n)] + this.handlers[gotypes.OL] = (n: any) => [new OL(n)] + this.handlers[gotypes.Page] = (n: any) => [new Page(n)] + this.handlers[gotypes.Ref] = (n: any) => [new Ref(n)] + this.handlers[gotypes.Snippet] = (n: any) => [new Snippet(n)] + this.handlers[gotypes.SourceCode] = (n: any) => [new SourceCode(n)] + this.handlers[gotypes.Table] = (n: any) => [new Table(n)] + this.handlers[gotypes.Text] = (n: any) => [new Text(n)] + this.handlers[gotypes.UL] = (n: any) => [new UL(n)] + + this.handlers[gotypes.Metadata] = (n: any) => { throw new Error("not implemented: " + gotypes.Metadata); } + this.handlers[gotypes.Now] = (n: any) => { throw new Error("not implemented: " + gotypes.Now); } + this.handlers[gotypes.Paragraph] = (n: any) => { throw new Error("not implemented: " + gotypes.Paragraph); } + this.handlers[gotypes.Snippets] = (n: any) => { throw new Error("not implemented: " + gotypes.Snippets); } + this.handlers[gotypes.TD] = (n: any) => { throw new Error("not implemented: " + gotypes.TD); } + this.handlers[gotypes.TH] = (n: any) => { throw new Error("not implemented: " + gotypes.TH); } + this.handlers[gotypes.THead] = (n: any) => { throw new Error("not implemented: " + gotypes.THead); } + this.handlers[gotypes.TR] = (n: any) => { throw new Error("not implemented: " + gotypes.TR); } + this.handlers[gotypes.ToC] = (n: any) => { throw new Error("not implemented: " + gotypes.ToC); } + this.handlers[gotypes.Var] = (n: any) => { throw new Error("not implemented: " + gotypes.Var); } + } parse(data: any): Document { @@ -70,19 +78,27 @@ export class Parser { parseError(data: any): any { switch (data.type) { - case gotypes.ExecuteError: - return new ExecuteError(data, this); - case gotypes.CmdError: + case goerrors.CmdError: return new CmdError(data, this); - case gotypes.ParseError: + case goerrors.ExecuteError: + return new ExecuteError(data, this); + case goerrors.ParseError: return new ParseError(data, this); + case goerrors.PostParseError: + return new PostParseError(data, this); + case goerrors.PostExecuteError: + throw new Error("not implemented: " + data.type); + case goerrors.PreExecuteError: + throw new Error("not implemented: " + data.type); + case goerrors.PreParseError: + throw new Error("not implemented: " + data.type); default: if (data.type === undefined) { return data; } - console.warn("parseError: unknown type: ", data.type) - return data + // console.warn("parseError: unknown type: ", data.type) + throw new Error("not implemented: " + data.type); } } @@ -103,11 +119,11 @@ export class Parser { let fn = this.handlers[n.type]; if (fn === undefined) { - console.warn("unknown node type: " + n.type) + // console.warn("unknown node type: " + n.type) fn = newElement } - ret.push(fn(n)) + ret.push(...fn(n)) } }); @@ -117,6 +133,6 @@ export class Parser { } -function newElement(n: any): Element { - return new Element(n) +function newElement(n: any): Node[] { + return [new Element(n)] } \ No newline at end of file diff --git a/src/post_parse_error.ts b/src/post_parse_error.ts new file mode 100644 index 0000000..95076df --- /dev/null +++ b/src/post_parse_error.ts @@ -0,0 +1,22 @@ +import { Parser } from './parser'; + +export class PostParseError { + error: any; + filename: string; + orig_error: any; + postparser: string; + root: string; + type: string; + + constructor(data: any, parser?: Parser) { + this.filename = data.filename; + this.postparser = data.postparser; + this.root = data.root; + this.type = data.type; + + parser = parser || new Parser(); + + this.error = parser.parseError(data.error); + this.orig_error = parser.parseError(data.orig_error); + } +} \ No newline at end of file diff --git a/src/testdata/09-errors.json b/src/testdata/09-errors.json new file mode 100644 index 0000000..7ba58ef --- /dev/null +++ b/src/testdata/09-errors.json @@ -0,0 +1,39569 @@ +{ + "filename": "module.md", + "id": "26a6655c-9112-4254-b46a-49db1fef3508", + "nodes": [ + { + "atom": "", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "", + "data_atom": "", + "namespace": "", + "node_type": "html.DocumentNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "html", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "html", + "data_atom": "html", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "head", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "head", + "data_atom": "head", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [], + "tag": "\u003chead\u003e", + "type": "hype.Element" + }, + [ + { + "atom": "body", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "body", + "data_atom": "body", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "page", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "page", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "atom": "h1", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "h1", + "data_atom": "h1", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "level": 1, + "nodes": [ + { + "text": "Errors", + "type": "hype.Text" + } + ], + "tag": "\u003ch1\u003e", + "type": "hype.Heading" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "This ", + "type": "hype.Text" + }, + { + "atom": "binding", + "attributes": { + "part": "" + }, + "filename": "module.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "part", + "Val": "" + } + ], + "data": "binding", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [], + "tag": "\u003cbinding part=\"\"\u003e", + "type": "hype.Element" + }, + { + "text": " will cover the benefits of how Go's error model results in more reliable code. We will cover how to handle basic errors and return errors as an interface that satisfies the error type. Additionally, concepts such as custom error types, panics, recovering from panics, and sentinel errors are also covered.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "tag": "\u003cpage\u003e", + "title": "Errors", + "type": "hype.Page" + } + ], + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "atom": "include", + "attributes": { + "src": "errors/basics.md" + }, + "dir": "errors", + "filename": "module.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "errors/basics.md" + } + ], + "data": "include", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "page", + "attributes": {}, + "filename": "errors/basics.md", + "html_node": { + "data": "page", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "atom": "h1", + "attributes": {}, + "filename": "errors/basics.md", + "html_node": { + "data": "h1", + "data_atom": "h1", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "level": 1, + "nodes": [ + { + "text": "Errors", + "type": "hype.Text" + } + ], + "tag": "\u003ch1\u003e", + "type": "hype.Heading" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "errors/basics.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "A lot of languages use the concept of ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "href": "https://en.wikipedia.org/wiki/Exception_handling", + "target": "_blank" + }, + "filename": "errors/basics.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "href", + "Val": "https://en.wikipedia.org/wiki/Exception_handling" + } + ], + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "exceptions", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"https://en.wikipedia.org/wiki/Exception_handling\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://en.wikipedia.org/wiki/Exception_handling" + } + ], + { + "text": ". When something goes wrong, an exception will be thrown. This exception then needs to be caught. When catching an exception you have the opportunity to log the exception and possibly move on with an alternate code path, or re-raise the exception and let the developer upstream deal with the problem.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "errors/basics.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-1" + }, + "filename": "errors/basics.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "java" + } + ], + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-1" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.1", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-1\"\u003e", + "type": "hype.Link", + "url": "#listing-1-1" + } + ], + "tag": "\u003cref id=\"listing-1-1\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": " shows an example of how to handle exceptions in Java.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-1", + "type": "listing" + }, + "filename": "errors/basics.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "java" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + { + "atom": "pre", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": { + "class": "language-java", + "language": "java", + "src": "errors/src/handling-java/main.java#example" + }, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/handling-java/main.java#example" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "java", + "nodes": [ + { + "content": "public static void main(String args[]) {\n try {\n // Open the file\n FileInputStream fstream = new FileInputStream(\"example.txt\");\n\n // Get the object of DataInputStream\n DataInputStream in = new DataInputStream(fstream);\n BufferedReader br = new BufferedReader(new InputStreamReader(in));\n String strLine;\n\n // Read File Line By Line\n while ((strLine = br.readLine()) != null) {\n // Print the content on the console\n System.out.println(strLine);\n }\n\n // Close the input stream\n in.close();\n } catch (IOException e) {\n System.err.println(\"IO Error: \" + e.getMessage());\n } catch (Exception e) {\n // Catch exception if any\n System.err.println(\"Error: \" + e.getMessage());\n }\n}", + "file": "errors/src/handling-java/main.java", + "lang": "java", + "name": "example", + "start": 5, + "end": 31 + } + ], + "tag": "\u003ccode class=\"language-java\" language=\"java\" src=\"errors/src/handling-java/main.java#example\"\u003e", + "type": "hype.SourceCode" + } + ] + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + }, + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.1:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "Exceptions in Java.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 1, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-1\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "errors/basics.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Go takes a different approach and treats errors as values. These values are returned and managed instead of throwing and capturing exceptions, ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-2" + }, + "filename": "errors/basics.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "go" + } + ], + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-2" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.2", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-2\"\u003e", + "type": "hype.Link", + "url": "#listing-1-2" + } + ], + "tag": "\u003cref id=\"listing-1-2\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ".", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-2", + "type": "listing" + }, + "filename": "errors/basics.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "go" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + { + "atom": "pre", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "src": "errors/src/handling/main.go#example" + }, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/handling/main.go#example" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "content": "func readFile() error {\n\n\t// open the file\n\tf, err := os.Open(\"example.txt\")\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// close the file when done\n\tdefer f.Close()\n\n\t// open buffered scanner with file\n\tscanner := bufio.NewScanner(f)\n\n\t// scan through each line of the file\n\tfor scanner.Scan() {\n\n\t\t// print line to the console\n\t\tfmt.Println(scanner.Text())\n\t}\n\n\t// if there was an error while scanning\n\t// return the error to the calling function\n\tif err := scanner.Err(); err != nil {\n\t\treturn err\n\t}\n\n\t// everything was good, return nil\n\treturn nil\n}", + "file": "errors/src/handling/main.go", + "lang": "go", + "name": "example", + "start": 17, + "end": 49 + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" src=\"errors/src/handling/main.go#example\"\u003e", + "type": "hype.SourceCode" + } + ] + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + }, + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.2:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "Errors in Go.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 2, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-2\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "h2", + "attributes": {}, + "filename": "errors/basics.md", + "html_node": { + "data": "h2", + "data_atom": "h2", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "level": 2, + "nodes": [ + { + "text": "The \"error\" Interface", + "type": "hype.Text" + } + ], + "tag": "\u003ch2\u003e", + "type": "hype.Heading" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "errors/basics.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "In Go errors are represented by the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "builtin#error", + "href": "https://pkg.go.dev/builtin#error", + "target": "_blank" + }, + "filename": "errors/basics.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/basics.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "error", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"builtin#error\" href=\"https://pkg.go.dev/builtin#error\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/builtin#error" + } + ], + { + "text": " interface.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-3", + "type": "listing" + }, + "filename": "errors/basics.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "error.doc" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "args": [ + "go", + "doc", + "builtin.error" + ], + "atom": "cmd", + "attributes": { + "data-go-version": "go1.22.0", + "doc": "builtin.error", + "exec": "go doc builtin.error" + }, + "expected_exit": 0, + "filename": "errors", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "data-go-version", + "Val": "go1.22.0" + }, + { + "Namespace": "", + "Key": "doc", + "Val": "builtin.error" + }, + { + "Namespace": "", + "Key": "exec", + "Val": "go doc builtin.error" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "doc", + "builtin.error" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypejs", + "duration": "1.932719708s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go doc builtin.error\n\npackage builtin // import \u0026#34;builtin\u0026#34;\n\ntype error interface {\n\tError() string\n}\n The error built-in interface type is the conventional interface for\n representing an error condition, with the nil value representing no error.", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "package builtin // import \"builtin\"\n\ntype error interface {\n\tError() string\n}\n The error built-in interface type is the conventional interface for\n representing an error condition, with the nil value representing no error.", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "doc", + "builtin.error" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypejs", + "duration": "1.932719708s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go doc builtin.error\n\npackage builtin // import \u0026#34;builtin\u0026#34;\n\ntype error interface {\n\tError() string\n}\n The error built-in interface type is the conventional interface for\n representing an error condition, with the nil value representing no error.", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "package builtin // import \"builtin\"\n\ntype error interface {\n\tError() string\n}\n The error built-in interface type is the conventional interface for\n representing an error condition, with the nil value representing no error.", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd data-go-version=\"go1.22.0\" doc=\"builtin.error\" exec=\"go doc builtin.error\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.3:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "The ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "builtin#error", + "href": "https://pkg.go.dev/builtin#error", + "target": "_blank" + }, + "filename": "errors", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "for", + "Val": "builtin#error" + }, + { + "Namespace": "", + "Key": "href", + "Val": "https://pkg.go.dev/builtin#error" + }, + { + "Namespace": "", + "Key": "target", + "Val": "_blank" + } + ], + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "error", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ] + ], + "tag": "\u003ca for=\"builtin#error\" href=\"https://pkg.go.dev/builtin#error\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/builtin#error" + } + ], + { + "text": " interface.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 3, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-3\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "h3", + "attributes": {}, + "filename": "errors/basics.md", + "html_node": { + "data": "h3", + "data_atom": "h3", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "level": 3, + "nodes": [ + { + "text": "Creating Errors with \"errors.New\"", + "type": "hype.Text" + } + ], + "tag": "\u003ch3\u003e", + "type": "hype.Heading" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "errors/basics.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Go provides two quick ways to implement the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "builtin#error", + "href": "https://pkg.go.dev/builtin#error", + "target": "_blank" + }, + "filename": "errors/basics.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/basics.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "error", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"builtin#error\" href=\"https://pkg.go.dev/builtin#error\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/builtin#error" + } + ], + { + "text": " interface in our code.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "errors/basics.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "The first is through the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "errors#New", + "href": "https://pkg.go.dev/errors#New", + "target": "_blank" + }, + "filename": "errors/basics.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/basics.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "errors.New", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"errors#New\" href=\"https://pkg.go.dev/errors#New\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/errors#New" + } + ], + { + "text": " function, ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-4" + }, + "filename": "errors/basics.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "errors.new" + } + ], + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-4" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.4", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-4\"\u003e", + "type": "hype.Link", + "url": "#listing-1-4" + } + ], + "tag": "\u003cref id=\"listing-1-4\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ". This function takes a string and returns an implementation of ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "builtin#error", + "href": "https://pkg.go.dev/builtin#error", + "target": "_blank" + }, + "filename": "errors/basics.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/basics.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "error", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"builtin#error\" href=\"https://pkg.go.dev/builtin#error\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/builtin#error" + } + ], + { + "text": " that uses the supplied string as the error message.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-4", + "type": "listing" + }, + "filename": "errors/basics.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "errors.new" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "args": [ + "go", + "doc", + "errors.New" + ], + "atom": "cmd", + "attributes": { + "data-go-version": "go1.22.0", + "doc": "errors.New", + "exec": "go doc errors.New" + }, + "expected_exit": 0, + "filename": "errors", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "data-go-version", + "Val": "go1.22.0" + }, + { + "Namespace": "", + "Key": "doc", + "Val": "errors.New" + }, + { + "Namespace": "", + "Key": "exec", + "Val": "go doc errors.New" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "doc", + "errors.New" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypejs", + "duration": "1.077639042s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go doc errors.New\n\npackage errors // import \u0026#34;errors\u0026#34;\n\nfunc New(text string) error\n New returns an error that formats as the given text. Each call to New\n returns a distinct error value even if the text is identical.", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "package errors // import \"errors\"\n\nfunc New(text string) error\n New returns an error that formats as the given text. Each call to New\n returns a distinct error value even if the text is identical.", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "doc", + "errors.New" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypejs", + "duration": "1.077639042s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go doc errors.New\n\npackage errors // import \u0026#34;errors\u0026#34;\n\nfunc New(text string) error\n New returns an error that formats as the given text. Each call to New\n returns a distinct error value even if the text is identical.", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "package errors // import \"errors\"\n\nfunc New(text string) error\n New returns an error that formats as the given text. Each call to New\n returns a distinct error value even if the text is identical.", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd data-go-version=\"go1.22.0\" doc=\"errors.New\" exec=\"go doc errors.New\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.4:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "The ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "errors#New", + "href": "https://pkg.go.dev/errors#New", + "target": "_blank" + }, + "filename": "errors", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "for", + "Val": "errors#New" + }, + { + "Namespace": "", + "Key": "href", + "Val": "https://pkg.go.dev/errors#New" + }, + { + "Namespace": "", + "Key": "target", + "Val": "_blank" + } + ], + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "errors.New", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ] + ], + "tag": "\u003ca for=\"errors#New\" href=\"https://pkg.go.dev/errors#New\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/errors#New" + } + ], + { + "text": " function.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 4, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-4\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "h3", + "attributes": {}, + "filename": "errors/basics.md", + "html_node": { + "data": "h3", + "data_atom": "h3", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "level": 3, + "nodes": [ + { + "text": "Creating Errors with \"fmt.Errorf\" (Recommended)", + "type": "hype.Text" + } + ], + "tag": "\u003ch3\u003e", + "type": "hype.Heading" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "errors/basics.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "When creating errors, it is common to want to create a string that contains the error message and the values of variables that caused the error.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-5", + "type": "listing" + }, + "filename": "errors/basics.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "newing" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + { + "atom": "pre", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "src": "errors/src/newing/main.go#new" + }, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/newing/main.go#new" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "content": "err = errors.New(fmt.Sprintf(\"error at %s\", time.Now()))", + "file": "errors/src/newing/main.go", + "lang": "go", + "name": "new", + "start": 18, + "end": 20 + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" src=\"errors/src/newing/main.go#new\"\u003e", + "type": "hype.SourceCode" + } + ] + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + }, + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.5:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "Creating errors with ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "errors#New", + "href": "https://pkg.go.dev/errors#New", + "target": "_blank" + }, + "filename": "errors", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "for", + "Val": "errors#New" + }, + { + "Namespace": "", + "Key": "href", + "Val": "https://pkg.go.dev/errors#New" + }, + { + "Namespace": "", + "Key": "target", + "Val": "_blank" + } + ], + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "errors.New", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ] + ], + "tag": "\u003ca for=\"errors#New\" href=\"https://pkg.go.dev/errors#New\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/errors#New" + } + ], + { + "text": " and ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "fmt#Sprintf", + "href": "https://pkg.go.dev/fmt#Sprintf", + "target": "_blank" + }, + "filename": "errors", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "for", + "Val": "fmt#Sprintf" + }, + { + "Namespace": "", + "Key": "href", + "Val": "https://pkg.go.dev/fmt#Sprintf" + }, + { + "Namespace": "", + "Key": "target", + "Val": "_blank" + } + ], + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "fmt.Sprintf", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ] + ], + "tag": "\u003ca for=\"fmt#Sprintf\" href=\"https://pkg.go.dev/fmt#Sprintf\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/fmt#Sprintf" + } + ], + { + "text": ".", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 5, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-5\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "errors/basics.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "To clean up the pattern seen in ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-5" + }, + "filename": "errors/basics.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "newing" + } + ], + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-5" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.5", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-5\"\u003e", + "type": "hype.Link", + "url": "#listing-1-5" + } + ], + "tag": "\u003cref id=\"listing-1-5\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ", the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "fmt#Errorf", + "href": "https://pkg.go.dev/fmt#Errorf", + "target": "_blank" + }, + "filename": "errors/basics.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/basics.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "fmt.Errorf", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"fmt#Errorf\" href=\"https://pkg.go.dev/fmt#Errorf\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/fmt#Errorf" + } + ], + { + "text": " method, ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-6" + }, + "filename": "errors/basics.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "errorf.doc" + } + ], + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-6" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.6", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-6\"\u003e", + "type": "hype.Link", + "url": "#listing-1-6" + } + ], + "tag": "\u003cref id=\"listing-1-6\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ", can be used.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-6", + "type": "listing" + }, + "filename": "errors/basics.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "errorf.doc" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "args": [ + "go", + "doc", + "fmt.Errorf" + ], + "atom": "cmd", + "attributes": { + "data-go-version": "go1.22.0", + "doc": "fmt.Errorf", + "exec": "go doc fmt.Errorf" + }, + "expected_exit": 0, + "filename": "errors", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "data-go-version", + "Val": "go1.22.0" + }, + { + "Namespace": "", + "Key": "doc", + "Val": "fmt.Errorf" + }, + { + "Namespace": "", + "Key": "exec", + "Val": "go doc fmt.Errorf" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "doc", + "fmt.Errorf" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypejs", + "duration": "2.054655542s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go doc fmt.Errorf\n\npackage fmt // import \u0026#34;fmt\u0026#34;\n\nfunc Errorf(format string, a ...any) error\n Errorf formats according to a format specifier and returns the string as a\n value that satisfies error.\n\n If the format specifier includes a %w verb with an error operand,\n the returned error will implement an Unwrap method returning the operand.\n If there is more than one %w verb, the returned error will implement an\n Unwrap method returning a []error containing all the %w operands in the\n order they appear in the arguments. It is invalid to supply the %w verb\n with an operand that does not implement the error interface. The %w verb is\n otherwise a synonym for %v.", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "package fmt // import \"fmt\"\n\nfunc Errorf(format string, a ...any) error\n Errorf formats according to a format specifier and returns the string as a\n value that satisfies error.\n\n If the format specifier includes a %w verb with an error operand,\n the returned error will implement an Unwrap method returning the operand.\n If there is more than one %w verb, the returned error will implement an\n Unwrap method returning a []error containing all the %w operands in the\n order they appear in the arguments. It is invalid to supply the %w verb\n with an operand that does not implement the error interface. The %w verb is\n otherwise a synonym for %v.", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "doc", + "fmt.Errorf" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypejs", + "duration": "2.054655542s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go doc fmt.Errorf\n\npackage fmt // import \u0026#34;fmt\u0026#34;\n\nfunc Errorf(format string, a ...any) error\n Errorf formats according to a format specifier and returns the string as a\n value that satisfies error.\n\n If the format specifier includes a %w verb with an error operand,\n the returned error will implement an Unwrap method returning the operand.\n If there is more than one %w verb, the returned error will implement an\n Unwrap method returning a []error containing all the %w operands in the\n order they appear in the arguments. It is invalid to supply the %w verb\n with an operand that does not implement the error interface. The %w verb is\n otherwise a synonym for %v.", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "package fmt // import \"fmt\"\n\nfunc Errorf(format string, a ...any) error\n Errorf formats according to a format specifier and returns the string as a\n value that satisfies error.\n\n If the format specifier includes a %w verb with an error operand,\n the returned error will implement an Unwrap method returning the operand.\n If there is more than one %w verb, the returned error will implement an\n Unwrap method returning a []error containing all the %w operands in the\n order they appear in the arguments. It is invalid to supply the %w verb\n with an operand that does not implement the error interface. The %w verb is\n otherwise a synonym for %v.", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd data-go-version=\"go1.22.0\" doc=\"fmt.Errorf\" exec=\"go doc fmt.Errorf\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.6:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "The ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "fmt#Errorf", + "href": "https://pkg.go.dev/fmt#Errorf", + "target": "_blank" + }, + "filename": "errors", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "for", + "Val": "fmt#Errorf" + }, + { + "Namespace": "", + "Key": "href", + "Val": "https://pkg.go.dev/fmt#Errorf" + }, + { + "Namespace": "", + "Key": "target", + "Val": "_blank" + } + ], + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "fmt.Errorf", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ] + ], + "tag": "\u003ca for=\"fmt#Errorf\" href=\"https://pkg.go.dev/fmt#Errorf\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/fmt#Errorf" + } + ], + { + "text": " method.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 6, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-6\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "errors/basics.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "In ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-7" + }, + "filename": "errors/basics.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "errorf.example" + } + ], + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-7" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.7", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-7\"\u003e", + "type": "hype.Link", + "url": "#listing-1-7" + } + ], + "tag": "\u003cref id=\"listing-1-7\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": " the code is now cleaner and more readable than in ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-5" + }, + "filename": "errors/basics.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "newing" + } + ], + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-5" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.5", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-5\"\u003e", + "type": "hype.Link", + "url": "#listing-1-5" + } + ], + "tag": "\u003cref id=\"listing-1-5\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ".", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-7", + "type": "listing" + }, + "filename": "errors/basics.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "errorf.example" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + { + "atom": "pre", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "src": "errors/src/newing/main.go#errorf" + }, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/newing/main.go#errorf" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "content": "err = fmt.Errorf(\"error at %s\", time.Now())", + "file": "errors/src/newing/main.go", + "lang": "go", + "name": "errorf", + "start": 12, + "end": 14 + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" src=\"errors/src/newing/main.go#errorf\"\u003e", + "type": "hype.SourceCode" + } + ] + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + }, + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.7:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "Creating errors with ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "fmt#Errorf", + "href": "https://pkg.go.dev/fmt#Errorf", + "target": "_blank" + }, + "filename": "errors", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "for", + "Val": "fmt#Errorf" + }, + { + "Namespace": "", + "Key": "href", + "Val": "https://pkg.go.dev/fmt#Errorf" + }, + { + "Namespace": "", + "Key": "target", + "Val": "_blank" + } + ], + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "fmt.Errorf", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ] + ], + "tag": "\u003ca for=\"fmt#Errorf\" href=\"https://pkg.go.dev/fmt#Errorf\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/fmt#Errorf" + } + ], + { + "text": ".", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 7, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-7\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + { + "atom": "blockquote", + "attributes": {}, + "filename": "errors/basics.md", + "html_node": { + "data": "blockquote", + "data_atom": "blockquote", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "errors/basics.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Using ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "fmt#Errorf", + "href": "https://pkg.go.dev/fmt#Errorf", + "target": "_blank" + }, + "filename": "errors/basics.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/basics.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "fmt.Errorf", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"fmt#Errorf\" href=\"https://pkg.go.dev/fmt#Errorf\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/fmt#Errorf" + } + ], + { + "text": " will handle ", + "type": "hype.Text" + }, + { + "atom": "strong", + "attributes": {}, + "filename": "errors/basics.md", + "html_node": { + "data": "strong", + "data_atom": "strong", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "most", + "type": "hype.Text" + } + ], + "tag": "\u003cstrong\u003e", + "type": "hype.Element" + }, + { + "text": " use cases for creating errors.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "tag": "\u003cblockquote\u003e", + "type": "hype.Element" + }, + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "h2", + "attributes": {}, + "filename": "errors/basics.md", + "html_node": { + "data": "h2", + "data_atom": "h2", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "level": 2, + "nodes": [ + { + "text": "Handling Errors", + "type": "hype.Text" + } + ], + "tag": "\u003ch2\u003e", + "type": "hype.Heading" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "errors/basics.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "With errors being a type in the Go type system, in this case an ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/basics.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "interface", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " type, errors can be returned from, and accepted as, function arguments.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "errors/basics.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "In Go, if an error is returned from the function, it should ", + "type": "hype.Text" + }, + { + "atom": "strong", + "attributes": {}, + "filename": "errors/basics.md", + "html_node": { + "data": "strong", + "data_atom": "strong", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "always", + "type": "hype.Text" + } + ], + "tag": "\u003cstrong\u003e", + "type": "hype.Element" + }, + { + "text": " be returned as the last argument. While the Go compiler won't enforce this, it is the expected idiom in the Go ecosystem.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-8", + "type": "listing" + }, + "filename": "errors/basics.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "error.return" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + { + "atom": "pre", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go" + }, + "filename": "errors", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "class", + "Val": "language-go" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "text": "// good\nfunc one() error {}\nfunc two() (int, error) {}\n\n// bad\nfunc bad() (error, int) {}\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\"\u003e", + "type": "hype.FencedCode" + } + ] + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + }, + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.8:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "Good and bad examples of return an ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "builtin#error", + "href": "https://pkg.go.dev/builtin#error", + "target": "_blank" + }, + "filename": "errors", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "for", + "Val": "builtin#error" + }, + { + "Namespace": "", + "Key": "href", + "Val": "https://pkg.go.dev/builtin#error" + }, + { + "Namespace": "", + "Key": "target", + "Val": "_blank" + } + ], + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "error", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ] + ], + "tag": "\u003ca for=\"builtin#error\" href=\"https://pkg.go.dev/builtin#error\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/builtin#error" + } + ], + { + "text": ".", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 8, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-8\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "errors/basics.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "As with all interfaces in Go, the zero value of the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "builtin#error", + "href": "https://pkg.go.dev/builtin#error", + "target": "_blank" + }, + "filename": "errors/basics.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/basics.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "error", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"builtin#error\" href=\"https://pkg.go.dev/builtin#error\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/builtin#error" + } + ], + { + "text": " interface is ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/basics.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "nil", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": ". Error checking in Go is done by checking if the returned error is ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/basics.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "nil", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " or not.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-9", + "type": "listing" + }, + "filename": "errors/basics.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "error.nil" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + { + "atom": "pre", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go" + }, + "filename": "errors", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "class", + "Val": "language-go" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "text": "err := boom()\nif err != nil {\n // the error was not nil\n // do something with the error\n}\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\"\u003e", + "type": "hype.FencedCode" + } + ] + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + }, + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.9:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "Checking for errors by assert against ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "nil", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": ".", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 9, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-9\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "h2", + "attributes": {}, + "filename": "errors/basics.md", + "html_node": { + "data": "h2", + "data_atom": "h2", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "level": 2, + "nodes": [ + { + "text": "Using Errors", + "type": "hype.Text" + } + ], + "tag": "\u003ch2\u003e", + "type": "hype.Heading" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "errors/basics.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "In ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-10" + }, + "filename": "errors/basics.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "using.example" + } + ], + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-10" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.10", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-10\"\u003e", + "type": "hype.Link", + "url": "#listing-1-10" + } + ], + "tag": "\u003cref id=\"listing-1-10\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": " if the key being requested in the map is found, its value will be returned and a ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/basics.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "nil", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " will be returned instead of an argument. If the key is not found in the map an empty string and an error, created with ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "fmt#Errorf", + "href": "https://pkg.go.dev/fmt#Errorf", + "target": "_blank" + }, + "filename": "errors/basics.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/basics.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "fmt.Errorf", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"fmt#Errorf\" href=\"https://pkg.go.dev/fmt#Errorf\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/fmt#Errorf" + } + ], + { + "text": ", are returned.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-10", + "type": "listing" + }, + "filename": "errors/basics.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "using.example" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + { + "atom": "pre", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "src": "errors/src/using/using.go#example" + }, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/using/using.go#example" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "content": "func Get(key string) (string, error) {\n\tm := map[string]string{\n\t\t\"a\": \"A\",\n\t\t\"b\": \"B\",\n\t}\n\n\tif v, ok := m[key]; ok {\n\t\treturn v, nil\n\t}\n\n\treturn \"\", fmt.Errorf(\"no key found %s\", key)\n}", + "file": "errors/src/using/using.go", + "lang": "go", + "name": "example", + "start": 5, + "end": 19 + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" src=\"errors/src/using/using.go#example\"\u003e", + "type": "hype.SourceCode" + } + ] + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + }, + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.10:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "A function that might return an ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "builtin#error", + "href": "https://pkg.go.dev/builtin#error", + "target": "_blank" + }, + "filename": "errors", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "for", + "Val": "builtin#error" + }, + { + "Namespace": "", + "Key": "href", + "Val": "https://pkg.go.dev/builtin#error" + }, + { + "Namespace": "", + "Key": "target", + "Val": "_blank" + } + ], + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "error", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ] + ], + "tag": "\u003ca for=\"builtin#error\" href=\"https://pkg.go.dev/builtin#error\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/builtin#error" + } + ], + { + "text": ".", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 10, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-10\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "errors/basics.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "A test for the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/basics.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Get", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " function, ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-11" + }, + "filename": "errors/basics.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "using.test" + } + ], + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-11" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.11", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-11\"\u003e", + "type": "hype.Link", + "url": "#listing-1-11" + } + ], + "tag": "\u003cref id=\"listing-1-11\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ", demonstrates the error checking pattern in action.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-11", + "type": "listing" + }, + "filename": "errors/basics.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "using.test" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + { + "atom": "pre", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "src": "errors/src/using/using_test.go#test" + }, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/using/using_test.go#test" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "content": "func Test_Get(t *testing.T) {\n\tt.Parallel()\n\n\tact, err := Get(\"a\")\n\tif err != nil {\n\t\tt.Fatalf(\"expect no error, got %s\", err)\n\t}\n\n\texp := \"A\"\n\tif act != exp {\n\t\tt.Fatalf(\"expected %s, got %s\", exp, act)\n\t}\n\n\t_, err = Get(\"?\")\n\tif err == nil {\n\t\tt.Fatalf(\"expected an error, got nil\")\n\t}\n}", + "file": "errors/src/using/using_test.go", + "lang": "go", + "name": "test", + "start": 5, + "end": 25 + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" src=\"errors/src/using/using_test.go#test\"\u003e", + "type": "hype.SourceCode" + } + ] + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + }, + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.11:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "A test for the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Get", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " function.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 11, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-11\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "tag": "\u003cpage\u003e", + "title": "Errors", + "type": "hype.Page" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "tag": "\u003cinclude src=\"errors/basics.md\"\u003e", + "type": "hype.Include" + } + ], + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "atom": "include", + "attributes": { + "src": "panic/panic.md" + }, + "dir": "panic", + "filename": "module.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "panic/panic.md" + } + ], + "data": "include", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "page", + "attributes": {}, + "filename": "panic.md", + "html_node": { + "data": "page", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "atom": "h1", + "attributes": {}, + "filename": "panic.md", + "html_node": { + "data": "h1", + "data_atom": "h1", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "level": 1, + "nodes": [ + { + "text": "Panic", + "type": "hype.Text" + } + ], + "tag": "\u003ch1\u003e", + "type": "hype.Heading" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + { + "atom": "blockquote", + "attributes": {}, + "filename": "panic.md", + "html_node": { + "data": "blockquote", + "data_atom": "blockquote", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "panic.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\"", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "href": "https://bit.ly/3jqqUk3", + "target": "_blank" + }, + "filename": "panic.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "href", + "Val": "https://bit.ly/3jqqUk3" + } + ], + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "The Hitchhiker's Guide to the Galaxy", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"https://bit.ly/3jqqUk3\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://bit.ly/3jqqUk3" + } + ], + { + "text": " itself has outsold the Encyclopedia Galactica because it is slightly cheaper, and because it has the words ‘DON'T PANIC' in large, friendly letters on the cover.\"", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "panic.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Arthur C. Clarke said Douglas Adams' use of ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "href": "https://en.wikipedia.org/wiki/Phrases_from_The_Hitchhiker%27s_Guide_to_the_Galaxy#Don't_Panic", + "target": "_blank" + }, + "filename": "panic.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "href", + "Val": "https://en.wikipedia.org/wiki/Phrases_from_The_Hitchhiker%27s_Guide_to_the_Galaxy#Don't_Panic" + } + ], + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\"don't panic\"", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"https://en.wikipedia.org/wiki/Phrases_from_The_Hitchhiker%27s_Guide_to_the_Galaxy#Don't_Panic\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://en.wikipedia.org/wiki/Phrases_from_The_Hitchhiker%27s_Guide_to_the_Galaxy#Don't_Panic" + } + ], + { + "text": " was perhaps the best advice that could be given to humanity.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "tag": "\u003cblockquote\u003e", + "type": "hype.Element" + }, + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "h2", + "attributes": {}, + "filename": "panic.md", + "html_node": { + "data": "h2", + "data_atom": "h2", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "level": 2, + "nodes": [ + { + "text": "What is a Panic?", + "type": "hype.Text" + } + ], + "tag": "\u003ch2\u003e", + "type": "hype.Heading" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "panic.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Occasionally, your code you will do something that the Go runtime does not like. For example, in ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-12" + }, + "filename": "panic.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "basics" + } + ], + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-12" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.12", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-12\"\u003e", + "type": "hype.Link", + "url": "#listing-1-12" + } + ], + "tag": "\u003cref id=\"listing-1-12\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ", if we try to insert a value into an array or slice that is beyond the bounds of the array or slice, the runtime will panic.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-12", + "type": "listing" + }, + "filename": "panic.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "basics" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + { + "atom": "pre", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "src": "panic/src/basics/main.go#example" + }, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/basics/main.go#example" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "content": "func main() {\n\ta := []string{}\n\ta[42] = \"Bring a towel\"\n}", + "file": "panic/src/basics/main.go", + "lang": "go", + "name": "example", + "start": 3, + "end": 9 + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" src=\"panic/src/basics/main.go#example\"\u003e", + "type": "hype.SourceCode" + } + ] + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + }, + { + "atom": "hr", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "hr", + "data_atom": "hr", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [], + "tag": "\u003chr\u003e", + "type": "hype.Element" + }, + [ + { + "args": [ + "go", + "run", + "." + ], + "atom": "cmd", + "attributes": { + "data-go-version": "go1.22.0", + "exec": "go run .", + "exit": "-1", + "run": ".", + "src": "panic/src/basics" + }, + "expected_exit": -1, + "filename": "panic", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "data-go-version", + "Val": "go1.22.0" + }, + { + "Namespace": "", + "Key": "exec", + "Val": "go run ." + }, + { + "Namespace": "", + "Key": "exit", + "Val": "-1" + }, + { + "Namespace": "", + "Key": "run", + "Val": "." + }, + { + "Namespace": "", + "Key": "src", + "Val": "src/basics" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "run", + "." + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/basics", + "duration": "3.40625375s", + "err": "exit status 1", + "exit": 1, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go run .\n\npanic: runtime error: index out of range [42] with length 0\n\ngoroutine 1 [running]:\nmain.main()\n\t/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/basics/main.go:6 +0x24\nexit status 2", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "panic: runtime error: index out of range [42] with length 0\n\ngoroutine 1 [running]:\nmain.main()\n\t/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/basics/main.go:6 +0x24\nexit status 2", + "stdout": "", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "run", + "." + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/basics", + "duration": "3.40625375s", + "err": "exit status 1", + "exit": 1, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go run .\n\npanic: runtime error: index out of range [42] with length 0\n\ngoroutine 1 [running]:\nmain.main()\n\t/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/basics/main.go:6 +0x24\nexit status 2", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "panic: runtime error: index out of range [42] with length 0\n\ngoroutine 1 [running]:\nmain.main()\n\t/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/basics/main.go:6 +0x24\nexit status 2", + "stdout": "", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd data-go-version=\"go1.22.0\" exec=\"go run .\" exit=\"-1\" run=\".\" src=\"panic/src/basics\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.12:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "A panic caused by an out of bounds index.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 12, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-12\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "h2", + "attributes": {}, + "filename": "panic.md", + "html_node": { + "data": "h2", + "data_atom": "h2", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "level": 2, + "nodes": [ + { + "text": "Raising a Panic", + "type": "hype.Text" + } + ], + "tag": "\u003ch2\u003e", + "type": "hype.Heading" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "panic.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "A panic in Go can be raised using the built-in ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "builtin#panic", + "href": "https://pkg.go.dev/builtin#panic", + "target": "_blank" + }, + "filename": "panic.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "panic.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "panic", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"builtin#panic\" href=\"https://pkg.go.dev/builtin#panic\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/builtin#panic" + } + ], + { + "text": " function, ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-13" + }, + "filename": "panic.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "panic.doc" + } + ], + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-13" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.13", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-13\"\u003e", + "type": "hype.Link", + "url": "#listing-1-13" + } + ], + "tag": "\u003cref id=\"listing-1-13\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ". The ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "builtin#panic", + "href": "https://pkg.go.dev/builtin#panic", + "target": "_blank" + }, + "filename": "panic.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "panic.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "panic", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"builtin#panic\" href=\"https://pkg.go.dev/builtin#panic\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/builtin#panic" + } + ], + { + "text": " function takes ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "panic.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "any", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " value as an argument.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-13", + "type": "listing" + }, + "filename": "panic.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "panic.doc" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "args": [ + "go", + "doc", + "builtin.panic" + ], + "atom": "cmd", + "attributes": { + "data-go-version": "go1.22.0", + "doc": "builtin.panic", + "exec": "go doc builtin.panic" + }, + "expected_exit": 0, + "filename": "panic", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "data-go-version", + "Val": "go1.22.0" + }, + { + "Namespace": "", + "Key": "doc", + "Val": "builtin.panic" + }, + { + "Namespace": "", + "Key": "exec", + "Val": "go doc builtin.panic" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "doc", + "builtin.panic" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypejs", + "duration": "1.701609292s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go doc builtin.panic\n\npackage builtin // import \u0026#34;builtin\u0026#34;\n\nfunc panic(v any)\n The panic built-in function stops normal execution of the current goroutine.\n When a function F calls panic, normal execution of F stops immediately.\n Any functions whose execution was deferred by F are run in the usual way,\n and then F returns to its caller. To the caller G, the invocation of F then\n behaves like a call to panic, terminating G\u0026#39;s execution and running any\n deferred functions. This continues until all functions in the executing\n goroutine have stopped, in reverse order. At that point, the program is\n terminated with a non-zero exit code. This termination sequence is called\n panicking and can be controlled by the built-in function recover.\n\n Starting in Go 1.21, calling panic with a nil interface value or an untyped\n nil causes a run-time error (a different panic). The GODEBUG setting\n panicnil=1 disables the run-time error.", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "package builtin // import \"builtin\"\n\nfunc panic(v any)\n The panic built-in function stops normal execution of the current goroutine.\n When a function F calls panic, normal execution of F stops immediately.\n Any functions whose execution was deferred by F are run in the usual way,\n and then F returns to its caller. To the caller G, the invocation of F then\n behaves like a call to panic, terminating G's execution and running any\n deferred functions. This continues until all functions in the executing\n goroutine have stopped, in reverse order. At that point, the program is\n terminated with a non-zero exit code. This termination sequence is called\n panicking and can be controlled by the built-in function recover.\n\n Starting in Go 1.21, calling panic with a nil interface value or an untyped\n nil causes a run-time error (a different panic). The GODEBUG setting\n panicnil=1 disables the run-time error.", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "doc", + "builtin.panic" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypejs", + "duration": "1.701609292s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go doc builtin.panic\n\npackage builtin // import \u0026#34;builtin\u0026#34;\n\nfunc panic(v any)\n The panic built-in function stops normal execution of the current goroutine.\n When a function F calls panic, normal execution of F stops immediately.\n Any functions whose execution was deferred by F are run in the usual way,\n and then F returns to its caller. To the caller G, the invocation of F then\n behaves like a call to panic, terminating G\u0026#39;s execution and running any\n deferred functions. This continues until all functions in the executing\n goroutine have stopped, in reverse order. At that point, the program is\n terminated with a non-zero exit code. This termination sequence is called\n panicking and can be controlled by the built-in function recover.\n\n Starting in Go 1.21, calling panic with a nil interface value or an untyped\n nil causes a run-time error (a different panic). The GODEBUG setting\n panicnil=1 disables the run-time error.", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "package builtin // import \"builtin\"\n\nfunc panic(v any)\n The panic built-in function stops normal execution of the current goroutine.\n When a function F calls panic, normal execution of F stops immediately.\n Any functions whose execution was deferred by F are run in the usual way,\n and then F returns to its caller. To the caller G, the invocation of F then\n behaves like a call to panic, terminating G's execution and running any\n deferred functions. This continues until all functions in the executing\n goroutine have stopped, in reverse order. At that point, the program is\n terminated with a non-zero exit code. This termination sequence is called\n panicking and can be controlled by the built-in function recover.\n\n Starting in Go 1.21, calling panic with a nil interface value or an untyped\n nil causes a run-time error (a different panic). The GODEBUG setting\n panicnil=1 disables the run-time error.", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd data-go-version=\"go1.22.0\" doc=\"builtin.panic\" exec=\"go doc builtin.panic\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.13:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "The ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "builtin#panic", + "href": "https://pkg.go.dev/builtin#panic", + "target": "_blank" + }, + "filename": "panic", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "for", + "Val": "builtin#panic" + }, + { + "Namespace": "", + "Key": "href", + "Val": "https://pkg.go.dev/builtin#panic" + }, + { + "Namespace": "", + "Key": "target", + "Val": "_blank" + } + ], + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "panic", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ] + ], + "tag": "\u003ca for=\"builtin#panic\" href=\"https://pkg.go.dev/builtin#panic\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/builtin#panic" + } + ], + { + "text": " function.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 13, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-13\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "h2", + "attributes": {}, + "filename": "panic.md", + "html_node": { + "data": "h2", + "data_atom": "h2", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "level": 2, + "nodes": [ + { + "text": "Recovering From A Panic", + "type": "hype.Text" + } + ], + "tag": "\u003ch2\u003e", + "type": "hype.Heading" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "panic.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "With a combination of the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "panic.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "defer", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " keyword and the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "builtin#recover", + "href": "https://pkg.go.dev/builtin#recover", + "target": "_blank" + }, + "filename": "panic.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "panic.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "recover", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"builtin#recover\" href=\"https://pkg.go.dev/builtin#recover\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/builtin#recover" + } + ], + { + "text": " function we can recover from panics in our applications and gracefully handle them.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-14", + "type": "listing" + }, + "filename": "panic.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "recover.doc" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "args": [ + "go", + "doc", + "builtin.recover" + ], + "atom": "cmd", + "attributes": { + "data-go-version": "go1.22.0", + "doc": "builtin.recover", + "exec": "go doc builtin.recover" + }, + "expected_exit": 0, + "filename": "panic", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "data-go-version", + "Val": "go1.22.0" + }, + { + "Namespace": "", + "Key": "doc", + "Val": "builtin.recover" + }, + { + "Namespace": "", + "Key": "exec", + "Val": "go doc builtin.recover" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "doc", + "builtin.recover" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypejs", + "duration": "1.873189916s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go doc builtin.recover\n\npackage builtin // import \u0026#34;builtin\u0026#34;\n\nfunc recover() any\n The recover built-in function allows a program to manage behavior of\n a panicking goroutine. Executing a call to recover inside a deferred\n function (but not any function called by it) stops the panicking sequence\n by restoring normal execution and retrieves the error value passed to the\n call of panic. If recover is called outside the deferred function it will\n not stop a panicking sequence. In this case, or when the goroutine is not\n panicking, recover returns nil.\n\n Prior to Go 1.21, recover would also return nil if panic is called with a\n nil argument. See [panic] for details.", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "package builtin // import \"builtin\"\n\nfunc recover() any\n The recover built-in function allows a program to manage behavior of\n a panicking goroutine. Executing a call to recover inside a deferred\n function (but not any function called by it) stops the panicking sequence\n by restoring normal execution and retrieves the error value passed to the\n call of panic. If recover is called outside the deferred function it will\n not stop a panicking sequence. In this case, or when the goroutine is not\n panicking, recover returns nil.\n\n Prior to Go 1.21, recover would also return nil if panic is called with a\n nil argument. See [panic] for details.", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "doc", + "builtin.recover" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypejs", + "duration": "1.873189916s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go doc builtin.recover\n\npackage builtin // import \u0026#34;builtin\u0026#34;\n\nfunc recover() any\n The recover built-in function allows a program to manage behavior of\n a panicking goroutine. Executing a call to recover inside a deferred\n function (but not any function called by it) stops the panicking sequence\n by restoring normal execution and retrieves the error value passed to the\n call of panic. If recover is called outside the deferred function it will\n not stop a panicking sequence. In this case, or when the goroutine is not\n panicking, recover returns nil.\n\n Prior to Go 1.21, recover would also return nil if panic is called with a\n nil argument. See [panic] for details.", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "package builtin // import \"builtin\"\n\nfunc recover() any\n The recover built-in function allows a program to manage behavior of\n a panicking goroutine. Executing a call to recover inside a deferred\n function (but not any function called by it) stops the panicking sequence\n by restoring normal execution and retrieves the error value passed to the\n call of panic. If recover is called outside the deferred function it will\n not stop a panicking sequence. In this case, or when the goroutine is not\n panicking, recover returns nil.\n\n Prior to Go 1.21, recover would also return nil if panic is called with a\n nil argument. See [panic] for details.", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd data-go-version=\"go1.22.0\" doc=\"builtin.recover\" exec=\"go doc builtin.recover\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.14:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "The ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "builtin#recover", + "href": "https://pkg.go.dev/builtin#recover", + "target": "_blank" + }, + "filename": "panic", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "for", + "Val": "builtin#recover" + }, + { + "Namespace": "", + "Key": "href", + "Val": "https://pkg.go.dev/builtin#recover" + }, + { + "Namespace": "", + "Key": "target", + "Val": "_blank" + } + ], + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "recover", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ] + ], + "tag": "\u003ca for=\"builtin#recover\" href=\"https://pkg.go.dev/builtin#recover\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/builtin#recover" + } + ], + { + "text": " function.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 14, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-14\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "panic.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "In ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-15" + }, + "filename": "panic.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "recover" + } + ], + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-15" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.15", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-15\"\u003e", + "type": "hype.Link", + "url": "#listing-1-15" + } + ], + "tag": "\u003cref id=\"listing-1-15\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ", before we run the code that will panic, we use the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "panic.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "defer", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " keyword to execute an anonymous function that will run before the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "panic.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "main", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " function exits. Inside of the deferred function we can call the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "builtin#recover", + "href": "https://pkg.go.dev/builtin#recover", + "target": "_blank" + }, + "filename": "panic.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "panic.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "recover", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"builtin#recover\" href=\"https://pkg.go.dev/builtin#recover\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/builtin#recover" + } + ], + { + "text": " function and check its return value for ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "panic.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "nil", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": ". A non-", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "panic.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "nil", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " value will be returned from the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "builtin#recover", + "href": "https://pkg.go.dev/builtin#recover", + "target": "_blank" + }, + "filename": "panic.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "panic.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "recover", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"builtin#recover\" href=\"https://pkg.go.dev/builtin#recover\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/builtin#recover" + } + ], + { + "text": " function if a panic occurred.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "panic.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Now, when the panic occurs, it is caught by the deferred ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "builtin#recover", + "href": "https://pkg.go.dev/builtin#recover", + "target": "_blank" + }, + "filename": "panic.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "panic.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "recover", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"builtin#recover\" href=\"https://pkg.go.dev/builtin#recover\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/builtin#recover" + } + ], + { + "text": " and can be handled gracefully.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-15", + "type": "listing" + }, + "filename": "panic.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "recover" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + { + "atom": "pre", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "src": "panic/src/recover/main.go#example" + }, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/recover/main.go#example" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "content": "func main() {\n\tdefer func() {\n\t\tif i := recover(); i != nil {\n\t\t\tfmt.Println(\"oh no, a panic occurred:\", i)\n\t\t}\n\t}()\n\n\ta := []string{}\n\ta[42] = \"Bring a towel\"\n}", + "file": "panic/src/recover/main.go", + "lang": "go", + "name": "example", + "start": 5, + "end": 17 + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" src=\"panic/src/recover/main.go#example\"\u003e", + "type": "hype.SourceCode" + } + ] + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + }, + { + "atom": "hr", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "hr", + "data_atom": "hr", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [], + "tag": "\u003chr\u003e", + "type": "hype.Element" + }, + [ + { + "args": [ + "go", + "run", + "." + ], + "atom": "cmd", + "attributes": { + "data-go-version": "go1.22.0", + "exec": "go run .", + "run": ".", + "src": "panic/src/recover" + }, + "expected_exit": 0, + "filename": "panic", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "data-go-version", + "Val": "go1.22.0" + }, + { + "Namespace": "", + "Key": "exec", + "Val": "go run ." + }, + { + "Namespace": "", + "Key": "run", + "Val": "." + }, + { + "Namespace": "", + "Key": "src", + "Val": "src/recover" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "run", + "." + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/recover", + "duration": "2.544934792s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go run .\n\noh no, a panic occurred: runtime error: index out of range [42] with length 0", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "oh no, a panic occurred: runtime error: index out of range [42] with length 0", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "run", + "." + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/recover", + "duration": "2.544934792s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go run .\n\noh no, a panic occurred: runtime error: index out of range [42] with length 0", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "oh no, a panic occurred: runtime error: index out of range [42] with length 0", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd data-go-version=\"go1.22.0\" exec=\"go run .\" run=\".\" src=\"panic/src/recover\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.15:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "Recovering from a panic.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 15, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-15\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "panic.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "While this is not the common use case for using ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "builtin#recover", + "href": "https://pkg.go.dev/builtin#recover", + "target": "_blank" + }, + "filename": "panic.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "panic.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "recover", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"builtin#recover\" href=\"https://pkg.go.dev/builtin#recover\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/builtin#recover" + } + ], + { + "text": ", it does show the mechanics of how it works. It is more common to use recover when your application calls a user defined function that is passed in as an argument.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "panic.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-16" + }, + "filename": "panic.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "sanitize" + } + ], + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-16" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.16", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-16\"\u003e", + "type": "hype.Link", + "url": "#listing-1-16" + } + ], + "tag": "\u003cref id=\"listing-1-16\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": " is an example of a function that takes a user defined function to match a specific string. If the function passed in panics, it will result in the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "panic.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "sanitize", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " function panicking as well.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-16", + "type": "listing" + }, + "filename": "panic.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "sanitize" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + { + "atom": "pre", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "src": "panic/src/matcher/bad/main.go#matcher" + }, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/matcher/bad/main.go#matcher" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "content": "type matcher func(rune) bool\n\nfunc sanitize(m matcher, s string) (string, error) {\n\tvar val string\n\n\t// iterate over the runes in the string\n\tfor _, c := range s {\n\n\t\t// call the matcher function\n\t\t// with the rune as the argument\n\t\tif m(c) {\n\t\t\t// append `*` to the result\n\t\t\tval = val + \"*\"\n\t\t\t// continue to the next rune\n\t\t\tcontinue\n\t\t}\n\n\t\t// append the rune to the result\n\t\tval = val + string(c)\n\t}\n\n\t// return the sanitized string\n\treturn val, nil\n}", + "file": "panic/src/matcher/bad/main.go", + "lang": "go", + "name": "matcher", + "start": 33, + "end": 59 + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" src=\"panic/src/matcher/bad/main.go#matcher\"\u003e", + "type": "hype.SourceCode" + } + ] + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + }, + { + "text": "\n\n", + "type": "hype.Text" + }, + { + "atom": "pre", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "src": "panic/src/matcher/bad/main.go#bad" + }, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/matcher/bad/main.go#bad" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "content": "func main() {\n\n\t// create a matcher function\n\tm := func(r rune) bool {\n\t\t// simulate doing something bad...\n\t\tpanic(\"hahaha\")\n\n\t\t// unreachable code\n\t\treturn false\n\t}\n\n\t// sanitize the string\n\ts, err := sanitize(m, \"go is awesome\")\n\tif err != nil {\n\t\t// handle the error\n\t\tlog.Fatal(err)\n\t}\n\n\t// print the sanitized string\n\tfmt.Println(s)\n}", + "file": "panic/src/matcher/bad/main.go", + "lang": "go", + "name": "bad", + "start": 8, + "end": 31 + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" src=\"panic/src/matcher/bad/main.go#bad\"\u003e", + "type": "hype.SourceCode" + } + ] + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + }, + { + "atom": "hr", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "hr", + "data_atom": "hr", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [], + "tag": "\u003chr\u003e", + "type": "hype.Element" + }, + [ + { + "args": [ + "go", + "run", + "." + ], + "atom": "cmd", + "attributes": { + "data-go-version": "go1.22.0", + "exec": "go run .", + "exit": "-1", + "run": ".", + "src": "panic/src/matcher/bad" + }, + "expected_exit": -1, + "filename": "panic", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "data-go-version", + "Val": "go1.22.0" + }, + { + "Namespace": "", + "Key": "exec", + "Val": "go run ." + }, + { + "Namespace": "", + "Key": "exit", + "Val": "-1" + }, + { + "Namespace": "", + "Key": "run", + "Val": "." + }, + { + "Namespace": "", + "Key": "src", + "Val": "src/matcher/bad" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "run", + "." + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/matcher/bad", + "duration": "5.045854708s", + "err": "exit status 1", + "exit": 1, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go run .\n\npanic: hahaha\n\ngoroutine 1 [running]:\nmain.main.func1(0x188ed8?)\n\t/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/matcher/bad/main.go:14 +0x2c\nmain.sanitize(0x102544880, {0x102504a2b, 0xd})\n\t/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/matcher/bad/main.go:44 +0xa4\nmain.main()\n\t/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/matcher/bad/main.go:21 +0x30\nexit status 2", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "panic: hahaha\n\ngoroutine 1 [running]:\nmain.main.func1(0x188ed8?)\n\t/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/matcher/bad/main.go:14 +0x2c\nmain.sanitize(0x102544880, {0x102504a2b, 0xd})\n\t/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/matcher/bad/main.go:44 +0xa4\nmain.main()\n\t/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/matcher/bad/main.go:21 +0x30\nexit status 2", + "stdout": "", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "run", + "." + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/matcher/bad", + "duration": "5.045854708s", + "err": "exit status 1", + "exit": 1, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go run .\n\npanic: hahaha\n\ngoroutine 1 [running]:\nmain.main.func1(0x188ed8?)\n\t/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/matcher/bad/main.go:14 +0x2c\nmain.sanitize(0x102544880, {0x102504a2b, 0xd})\n\t/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/matcher/bad/main.go:44 +0xa4\nmain.main()\n\t/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/matcher/bad/main.go:21 +0x30\nexit status 2", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "panic: hahaha\n\ngoroutine 1 [running]:\nmain.main.func1(0x188ed8?)\n\t/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/matcher/bad/main.go:14 +0x2c\nmain.sanitize(0x102544880, {0x102504a2b, 0xd})\n\t/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/matcher/bad/main.go:44 +0xa4\nmain.main()\n\t/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/matcher/bad/main.go:21 +0x30\nexit status 2", + "stdout": "", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd data-go-version=\"go1.22.0\" exec=\"go run .\" exit=\"-1\" run=\".\" src=\"panic/src/matcher/bad\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.16:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "A function that sanitizes a given string.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 16, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-16\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "panic.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "However, if we use a ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "builtin#recover", + "href": "https://pkg.go.dev/builtin#recover", + "target": "_blank" + }, + "filename": "panic.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "panic.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "recover", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"builtin#recover\" href=\"https://pkg.go.dev/builtin#recover\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/builtin#recover" + } + ], + { + "text": " in the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "panic.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "sanitize", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " function, we can gracefully handle any potential panic that the user provided function may create. In ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-17" + }, + "filename": "panic.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "good.matcher" + } + ], + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-17" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.17", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-17\"\u003e", + "type": "hype.Link", + "url": "#listing-1-17" + } + ], + "tag": "\u003cref id=\"listing-1-17\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ", we use the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "builtin#recover", + "href": "https://pkg.go.dev/builtin#recover", + "target": "_blank" + }, + "filename": "panic.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "panic.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "recover", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"builtin#recover\" href=\"https://pkg.go.dev/builtin#recover\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/builtin#recover" + } + ], + { + "text": " to handle panics in the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "panic.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "sanitize", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " function.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-17", + "type": "listing" + }, + "filename": "panic.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "good.matcher" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + { + "atom": "pre", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "src": "panic/src/matcher/good/main.go#matcher" + }, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/matcher/good/main.go#matcher" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "content": "func sanitize(m matcher, s string) (val string, err error) {\n\t// guard against an invalid matcher that could panic\n\tdefer func() {\n\t\tif e := recover(); e != nil {\n\t\t\terr = fmt.Errorf(\"invalid matcher. panic occurred: %v\", e)\n\t\t}\n\t}()\n\n\tfor _, c := range s {\n\t\tif m(c) {\n\t\t\tval = val + \"*\"\n\t\t\tcontinue\n\t\t}\n\t\tval = val + string(c)\n\t}\n\treturn\n}", + "file": "panic/src/matcher/good/main.go", + "lang": "go", + "name": "matcher", + "start": 25, + "end": 44 + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" src=\"panic/src/matcher/good/main.go#matcher\"\u003e", + "type": "hype.SourceCode" + } + ] + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + }, + { + "atom": "hr", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "hr", + "data_atom": "hr", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [], + "tag": "\u003chr\u003e", + "type": "hype.Element" + }, + [ + { + "args": [ + "go", + "run", + "." + ], + "atom": "cmd", + "attributes": { + "data-go-version": "go1.22.0", + "exec": "go run .", + "run": ".", + "src": "panic/src/matcher/good" + }, + "expected_exit": 0, + "filename": "panic", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "data-go-version", + "Val": "go1.22.0" + }, + { + "Namespace": "", + "Key": "exec", + "Val": "go run ." + }, + { + "Namespace": "", + "Key": "run", + "Val": "." + }, + { + "Namespace": "", + "Key": "src", + "Val": "src/matcher/good" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "run", + "." + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/matcher/good", + "duration": "3.966207375s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go run .\n\ninvalid matcher. panic occurred: hahaha", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "invalid matcher. panic occurred: hahaha", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "run", + "." + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/matcher/good", + "duration": "3.966207375s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go run .\n\ninvalid matcher. panic occurred: hahaha", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "invalid matcher. panic occurred: hahaha", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd data-go-version=\"go1.22.0\" exec=\"go run .\" run=\".\" src=\"panic/src/matcher/good\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.17:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "A function that sanitizes a given string.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 17, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-17\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "panic.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Now, if a user inadvertently raises a panic in the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "panic.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "matcher", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " function provided, the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "panic.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "sanitize", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " function will handle it gracefully and return an error, instead of panicking as well.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "h2", + "attributes": {}, + "filename": "panic.md", + "html_node": { + "data": "h2", + "data_atom": "h2", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "level": 2, + "nodes": [ + { + "text": "Capturing and Returning Panic Values", + "type": "hype.Text" + } + ], + "tag": "\u003ch2\u003e", + "type": "hype.Heading" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "panic.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "When something panics in Go you have three options for how to handle the panic. ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-18" + }, + "filename": "panic.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "options" + } + ], + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-18" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.18", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-18\"\u003e", + "type": "hype.Link", + "url": "#listing-1-18" + } + ], + "tag": "\u003cref id=\"listing-1-18\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": " lists the three options.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-18", + "type": "listing" + }, + "filename": "panic.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "options" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "atom": "ol", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "ol", + "data_atom": "ol", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "atom": "li", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "li", + "data_atom": "li", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "list-type": "ol", + "nodes": [ + { + "text": "You can let the panic crash the application and deal with the fall out.", + "type": "hype.Text" + } + ], + "tag": "\u003cli\u003e", + "type": "hype.LI" + } + ], + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "atom": "li", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "li", + "data_atom": "li", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "list-type": "ol", + "nodes": [ + { + "text": "You can recover from the panic, log it, and move on.", + "type": "hype.Text" + } + ], + "tag": "\u003cli\u003e", + "type": "hype.LI" + } + ], + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "atom": "li", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "li", + "data_atom": "li", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "list-type": "ol", + "nodes": [ + { + "text": "You can properly capture the panicked value and return it as an error.", + "type": "hype.Text" + } + ], + "tag": "\u003cli\u003e", + "type": "hype.LI" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "tag": "\u003col\u003e", + "type": "hype.OL" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.18:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "Three options for handling panics.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 18, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-18\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "panic.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "This last option, in ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-18" + }, + "filename": "panic.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "options" + } + ], + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-18" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.18", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-18\"\u003e", + "type": "hype.Link", + "url": "#listing-1-18" + } + ], + "tag": "\u003cref id=\"listing-1-18\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ", gives you the most control over recovering from panics. However, it requires a number of steps, and functions, to make this happen.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "panic.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Consider the function, ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "panic.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "DoSomething(int)", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": ", in ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-19" + }, + "filename": "panic.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "dosomething" + } + ], + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-19" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.19", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-19\"\u003e", + "type": "hype.Link", + "url": "#listing-1-19" + } + ], + "tag": "\u003cref id=\"listing-1-19\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": " that takes an integer and either returns ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "panic.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "nil", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " or panics.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-19", + "type": "listing" + }, + "filename": "panic.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "dosomething" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + { + "atom": "pre", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "src": "panic/src/recover-broken/recover.go#example" + }, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/recover-broken/recover.go#example" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "content": "func DoSomething(input int) error {\n\tswitch input {\n\tcase 0:\n\t\t// input was 0, return no error (nil)\n\t\treturn nil\n\tcase 1:\n\t\t// input was 1, panic with the string \"one\"\n\t\tpanic(\"one\")\n\t}\n\n\t// no case was matched\n\treturn nil\n}", + "file": "panic/src/recover-broken/recover.go", + "lang": "go", + "name": "example", + "start": 3, + "end": 18 + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" src=\"panic/src/recover-broken/recover.go#example\"\u003e", + "type": "hype.SourceCode" + } + ] + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + }, + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.19:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "A function that returns ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "nil", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " or panics.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 19, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-19\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "panic.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "In ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-20" + }, + "filename": "panic.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "broken" + } + ], + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-20" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.20", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-20\"\u003e", + "type": "hype.Link", + "url": "#listing-1-20" + } + ], + "tag": "\u003cref id=\"listing-1-20\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": " we have a test for the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "panic.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "DoSomething(int)", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " function. When we call the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "panic.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "DoSomething(int)", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " function with the value ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "panic.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "1", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": ", the test panics.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-20", + "type": "listing" + }, + "filename": "panic.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "broken" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + { + "atom": "pre", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "src": "panic/src/recover-broken/recover_test.go#test" + }, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/recover-broken/recover_test.go#test" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "content": "func Test_DoSomething(t *testing.T) {\n\tt.Parallel()\n\n\terr := DoSomething(0)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\terr = DoSomething(1)\n\n\tif err != nil {\n\t\tt.Fatal(\"expected nil, got\", err)\n\t}\n}", + "file": "panic/src/recover-broken/recover_test.go", + "lang": "go", + "name": "test", + "start": 7, + "end": 23 + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" src=\"panic/src/recover-broken/recover_test.go#test\"\u003e", + "type": "hype.SourceCode" + } + ] + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + }, + { + "atom": "hr", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "hr", + "data_atom": "hr", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [], + "tag": "\u003chr\u003e", + "type": "hype.Element" + }, + [ + { + "args": [ + "go", + "test", + "-v" + ], + "atom": "cmd", + "attributes": { + "data-go-version": "go1.22.0", + "exec": "go test -v", + "exit": "-1", + "src": "panic/src/recover-broken", + "test": "-v" + }, + "expected_exit": -1, + "filename": "panic", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "data-go-version", + "Val": "go1.22.0" + }, + { + "Namespace": "", + "Key": "exec", + "Val": "go test -v" + }, + { + "Namespace": "", + "Key": "exit", + "Val": "-1" + }, + { + "Namespace": "", + "Key": "src", + "Val": "src/recover-broken" + }, + { + "Namespace": "", + "Key": "test", + "Val": "-v" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "test", + "-v" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/recover-broken", + "duration": "5.28288725s", + "err": "exit status 1", + "exit": 1, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go test -v\n\n=== RUN Test_DoSomething\n=== PAUSE Test_DoSomething\n=== CONT Test_DoSomething\n--- FAIL: Test_DoSomething (0.00s)\npanic: one [recovered]\n\tpanic: one\n\ngoroutine 4 [running]:\ntesting.tRunner.func1.2({0x100f51540, 0x100f79600})\n\t/usr/local/go/src/testing/testing.go:1631 +0x1c4\ntesting.tRunner.func1()\n\t/usr/local/go/src/testing/testing.go:1634 +0x33c\npanic({0x100f51540?, 0x100f79600?})\n\t/usr/local/go/src/runtime/panic.go:770 +0x124\ndemo.DoSomething(...)\n\t/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/recover-broken/recover.go:11\ndemo.Test_DoSomething(0x1400010e680?)\n\t/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/recover-broken/recover_test.go:16 +0x34\ntesting.tRunner(0x1400010e680, 0x100f78dc0)\n\t/usr/local/go/src/testing/testing.go:1689 +0xec\ncreated by testing.(*T).Run in goroutine 1\n\t/usr/local/go/src/testing/testing.go:1742 +0x318\nexit status 2\nFAIL\tdemo\t3.167s", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "=== RUN Test_DoSomething\n=== PAUSE Test_DoSomething\n=== CONT Test_DoSomething\n--- FAIL: Test_DoSomething (0.00s)\npanic: one [recovered]\n\tpanic: one\n\ngoroutine 4 [running]:\ntesting.tRunner.func1.2({0x100f51540, 0x100f79600})\n\t/usr/local/go/src/testing/testing.go:1631 +0x1c4\ntesting.tRunner.func1()\n\t/usr/local/go/src/testing/testing.go:1634 +0x33c\npanic({0x100f51540?, 0x100f79600?})\n\t/usr/local/go/src/runtime/panic.go:770 +0x124\ndemo.DoSomething(...)\n\t/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/recover-broken/recover.go:11\ndemo.Test_DoSomething(0x1400010e680?)\n\t/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/recover-broken/recover_test.go:16 +0x34\ntesting.tRunner(0x1400010e680, 0x100f78dc0)\n\t/usr/local/go/src/testing/testing.go:1689 +0xec\ncreated by testing.(*T).Run in goroutine 1\n\t/usr/local/go/src/testing/testing.go:1742 +0x318\nexit status 2\nFAIL\tdemo\t3.167s", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "test", + "-v" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/recover-broken", + "duration": "5.28288725s", + "err": "exit status 1", + "exit": 1, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go test -v\n\n=== RUN Test_DoSomething\n=== PAUSE Test_DoSomething\n=== CONT Test_DoSomething\n--- FAIL: Test_DoSomething (0.00s)\npanic: one [recovered]\n\tpanic: one\n\ngoroutine 4 [running]:\ntesting.tRunner.func1.2({0x100f51540, 0x100f79600})\n\t/usr/local/go/src/testing/testing.go:1631 +0x1c4\ntesting.tRunner.func1()\n\t/usr/local/go/src/testing/testing.go:1634 +0x33c\npanic({0x100f51540?, 0x100f79600?})\n\t/usr/local/go/src/runtime/panic.go:770 +0x124\ndemo.DoSomething(...)\n\t/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/recover-broken/recover.go:11\ndemo.Test_DoSomething(0x1400010e680?)\n\t/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/recover-broken/recover_test.go:16 +0x34\ntesting.tRunner(0x1400010e680, 0x100f78dc0)\n\t/usr/local/go/src/testing/testing.go:1689 +0xec\ncreated by testing.(*T).Run in goroutine 1\n\t/usr/local/go/src/testing/testing.go:1742 +0x318\nexit status 2\nFAIL\tdemo\t3.167s", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "=== RUN Test_DoSomething\n=== PAUSE Test_DoSomething\n=== CONT Test_DoSomething\n--- FAIL: Test_DoSomething (0.00s)\npanic: one [recovered]\n\tpanic: one\n\ngoroutine 4 [running]:\ntesting.tRunner.func1.2({0x100f51540, 0x100f79600})\n\t/usr/local/go/src/testing/testing.go:1631 +0x1c4\ntesting.tRunner.func1()\n\t/usr/local/go/src/testing/testing.go:1634 +0x33c\npanic({0x100f51540?, 0x100f79600?})\n\t/usr/local/go/src/runtime/panic.go:770 +0x124\ndemo.DoSomething(...)\n\t/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/recover-broken/recover.go:11\ndemo.Test_DoSomething(0x1400010e680?)\n\t/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/recover-broken/recover_test.go:16 +0x34\ntesting.tRunner(0x1400010e680, 0x100f78dc0)\n\t/usr/local/go/src/testing/testing.go:1689 +0xec\ncreated by testing.(*T).Run in goroutine 1\n\t/usr/local/go/src/testing/testing.go:1742 +0x318\nexit status 2\nFAIL\tdemo\t3.167s", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd data-go-version=\"go1.22.0\" exec=\"go test -v\" exit=\"-1\" src=\"panic/src/recover-broken\" test=\"-v\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.20:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "A test for the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "DoSomething(1)", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " function in ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-19" + }, + "filename": "panic", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "dosomething" + } + ], + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-19" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.19", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-19\"\u003e", + "type": "hype.Link", + "url": "#listing-1-19" + } + ], + "tag": "\u003cref id=\"listing-1-19\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ".", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 20, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-20\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "panic.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "To fix this problem we need to properly recover from the panic being raised in the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "panic.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "DoSomething(int)", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " function. ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-21" + }, + "filename": "panic.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "recover.steps" + } + ], + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-21" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.21", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-21\"\u003e", + "type": "hype.Link", + "url": "#listing-1-21" + } + ], + "tag": "\u003cref id=\"listing-1-21\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": " outlines the steps required to properly recover from a panic.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-21", + "type": "listing" + }, + "filename": "panic.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "recover.steps" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "atom": "ol", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "ol", + "data_atom": "ol", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "atom": "li", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "li", + "data_atom": "li", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "list-type": "ol", + "nodes": [ + { + "text": "Use a ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "defer", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " with a ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "builtin#recover", + "href": "https://pkg.go.dev/builtin#recover", + "target": "_blank" + }, + "filename": "panic", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "for", + "Val": "builtin#recover" + }, + { + "Namespace": "", + "Key": "href", + "Val": "https://pkg.go.dev/builtin#recover" + }, + { + "Namespace": "", + "Key": "target", + "Val": "_blank" + } + ], + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "recover", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ] + ], + "tag": "\u003ca for=\"builtin#recover\" href=\"https://pkg.go.dev/builtin#recover\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/builtin#recover" + } + ], + { + "text": " to catch the panic.", + "type": "hype.Text" + } + ], + "tag": "\u003cli\u003e", + "type": "hype.LI" + } + ], + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "atom": "li", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "li", + "data_atom": "li", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "list-type": "ol", + "nodes": [ + { + "text": "Use type assertion on the value returned from the panic to see if it was an ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "builtin#error", + "href": "https://pkg.go.dev/builtin#error", + "target": "_blank" + }, + "filename": "panic", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "for", + "Val": "builtin#error" + }, + { + "Namespace": "", + "Key": "href", + "Val": "https://pkg.go.dev/builtin#error" + }, + { + "Namespace": "", + "Key": "target", + "Val": "_blank" + } + ], + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "error", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ] + ], + "tag": "\u003ca for=\"builtin#error\" href=\"https://pkg.go.dev/builtin#error\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/builtin#error" + } + ], + { + "text": ".", + "type": "hype.Text" + } + ], + "tag": "\u003cli\u003e", + "type": "hype.LI" + } + ], + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "atom": "li", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "li", + "data_atom": "li", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "list-type": "ol", + "nodes": [ + { + "text": "Use a ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "named", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " return to allow sending back of the error from the deferred recover.", + "type": "hype.Text" + } + ], + "tag": "\u003cli\u003e", + "type": "hype.LI" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "tag": "\u003col\u003e", + "type": "hype.OL" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.21:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "Steps for recovering from a panic.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 21, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-21\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "panic.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "In ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-22" + }, + "filename": "panic.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "named" + } + ], + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-22" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.22", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-22\"\u003e", + "type": "hype.Link", + "url": "#listing-1-22" + } + ], + "tag": "\u003cref id=\"listing-1-22\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ", we implement the steps outlined in ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-21" + }, + "filename": "panic.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "recover.steps" + } + ], + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-21" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.21", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-21\"\u003e", + "type": "hype.Link", + "url": "#listing-1-21" + } + ], + "tag": "\u003cref id=\"listing-1-21\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": " to properly recover from the panic. As we see in ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-22" + }, + "filename": "panic.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "named" + } + ], + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-22" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.22", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-22\"\u003e", + "type": "hype.Link", + "url": "#listing-1-22" + } + ], + "tag": "\u003cref id=\"listing-1-22\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ", we implemented the fix in the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "panic.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "DoSomething(int)", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " function, and not in the test. This is because it is the responsibility of the function that panics to properly recover from it.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-22", + "type": "listing" + }, + "filename": "panic.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "named" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + { + "atom": "pre", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "src": "panic/src/recover-named/recover.go#example" + }, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/recover-named/recover.go#example" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "content": "func DoSomething(input int) (err error) {\n\t// defer a function to recover from the panic\n\tdefer func() {\n\t\tp := recover()\n\t\tif p == nil {\n\t\t\t// a nil was return, no panic was raised\n\t\t\t// return from the deferred function.\n\t\t\treturn\n\t\t}\n\n\t\t// check if the recovered value is already an error\n\t\tif e, ok := p.(error); ok {\n\t\t\t// assign the recovered error to the perr variable\n\t\t\t// outside of the anonymous function scope\n\t\t\terr = e\n\t\t\treturn\n\t\t}\n\n\t\t// a non-error value was recovered\n\t\t// create a new error, `ErrNonErrCaught`, with\n\t\t// information about the recovered value\n\t\tmsg := fmt.Sprintf(\"non-error panic type %T %s\", p, p)\n\t\terr = ErrNonErrCaught(msg)\n\t}()\n\n\tswitch input {\n\tcase 0:\n\t\t// input was 0, return no error (nil)\n\t\treturn nil\n\tcase 1:\n\t\t// input was 1, panic with the string \"one\"\n\t\tpanic(\"one\")\n\t}\n\n\t// no case was matched\n\treturn nil\n}\n\ntype ErrNonErrCaught string\n\nfunc (e ErrNonErrCaught) Error() string {\n\treturn string(e)\n}", + "file": "panic/src/recover-named/recover.go", + "lang": "go", + "name": "example", + "start": 7, + "end": 52 + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" src=\"panic/src/recover-named/recover.go#example\"\u003e", + "type": "hype.SourceCode" + } + ] + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + }, + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.22:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "Properly returning from a panic.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 22, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-22\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "panic.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "First, we have changed our function signature to use a named return for the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "builtin#error", + "href": "https://pkg.go.dev/builtin#error", + "target": "_blank" + }, + "filename": "panic.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "panic.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "error", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"builtin#error\" href=\"https://pkg.go.dev/builtin#error\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/builtin#error" + } + ], + { + "text": ", ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "panic.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "(err error)", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": ". This will allow us to set the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "builtin#error", + "href": "https://pkg.go.dev/builtin#error", + "target": "_blank" + }, + "filename": "panic.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "panic.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "error", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"builtin#error\" href=\"https://pkg.go.dev/builtin#error\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/builtin#error" + } + ], + { + "text": " value inside the deferred function. Once inside the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "panic.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "DoSomething(int)", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " function, we use the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "panic.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "defer", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " keyword and an anonymous function to catch the panic. Inside of the anonymous function, we use the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "builtin#recover", + "href": "https://pkg.go.dev/builtin#recover", + "target": "_blank" + }, + "filename": "panic.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "panic.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "recover", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"builtin#recover\" href=\"https://pkg.go.dev/builtin#recover\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/builtin#recover" + } + ], + { + "text": " function to recover from the panic, and assign the value returned to the variable ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "panic.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "p", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": ".", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "panic.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "As we see in ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-14" + }, + "filename": "panic.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "recover.doc" + } + ], + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-14" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.14", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-14\"\u003e", + "type": "hype.Link", + "url": "#listing-1-14" + } + ], + "tag": "\u003cref id=\"listing-1-14\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ", the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "builtin#recover", + "href": "https://pkg.go.dev/builtin#recover", + "target": "_blank" + }, + "filename": "panic.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "panic.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "recover", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"builtin#recover\" href=\"https://pkg.go.dev/builtin#recover\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/builtin#recover" + } + ], + { + "text": " function returns ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "panic.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "any", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": ". This means that the value can be of any type, a ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "panic.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "string", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": ", ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "panic.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "int", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": ", an ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "builtin#error", + "href": "https://pkg.go.dev/builtin#error", + "target": "_blank" + }, + "filename": "panic.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "panic.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "error", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"builtin#error\" href=\"https://pkg.go.dev/builtin#error\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/builtin#error" + } + ], + { + "text": ", or ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "panic.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "nil", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": ". As result, we must use type assertions to check the type of the value returned from the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "builtin#recover", + "href": "https://pkg.go.dev/builtin#recover", + "target": "_blank" + }, + "filename": "panic.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "panic.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "recover", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"builtin#recover\" href=\"https://pkg.go.dev/builtin#recover\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/builtin#recover" + } + ], + { + "text": " function. If the value is an ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "builtin#error", + "href": "https://pkg.go.dev/builtin#error", + "target": "_blank" + }, + "filename": "panic.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "panic.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "error", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"builtin#error\" href=\"https://pkg.go.dev/builtin#error\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/builtin#error" + } + ], + { + "text": ", we can use the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "panic.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "named", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " return to send the value back to the caller. If not, we create a new ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "builtin#error", + "href": "https://pkg.go.dev/builtin#error", + "target": "_blank" + }, + "filename": "panic.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "panic.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "error", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"builtin#error\" href=\"https://pkg.go.dev/builtin#error\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/builtin#error" + } + ], + { + "text": " with the value returned from the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "builtin#recover", + "href": "https://pkg.go.dev/builtin#recover", + "target": "_blank" + }, + "filename": "panic.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "panic.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "recover", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"builtin#recover\" href=\"https://pkg.go.dev/builtin#recover\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/builtin#recover" + } + ], + { + "text": " function.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "panic.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "As we see in ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-23" + }, + "filename": "panic.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "recover.test" + } + ], + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-23" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.23", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-23\"\u003e", + "type": "hype.Link", + "url": "#listing-1-23" + } + ], + "tag": "\u003cref id=\"listing-1-23\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ", when run the tests now are no longer panicking, and the test passes.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-23", + "type": "listing" + }, + "filename": "panic.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "recover.test" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + { + "atom": "pre", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "src": "panic/src/recover-named/recover_test.go#test" + }, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/recover-named/recover_test.go#test" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "content": "func Test_DoSomething(t *testing.T) {\n\tt.Parallel()\n\n\terr := DoSomething(0)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\terr = DoSomething(1)\n\n\tif err != ErrNonErrCaught(\"non-error panic type string one\") {\n\t\tt.Fatal(\"expected ErrNonErrCaught, got\", err)\n\t}\n}", + "file": "panic/src/recover-named/recover_test.go", + "lang": "go", + "name": "test", + "start": 7, + "end": 23 + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" src=\"panic/src/recover-named/recover_test.go#test\"\u003e", + "type": "hype.SourceCode" + } + ] + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + }, + { + "atom": "hr", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "hr", + "data_atom": "hr", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [], + "tag": "\u003chr\u003e", + "type": "hype.Element" + }, + [ + { + "args": [ + "go", + "test", + "-v" + ], + "atom": "cmd", + "attributes": { + "data-go-version": "go1.22.0", + "exec": "go test -v", + "src": "panic/src/recover-named", + "test": "-v" + }, + "expected_exit": 0, + "filename": "panic", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "data-go-version", + "Val": "go1.22.0" + }, + { + "Namespace": "", + "Key": "exec", + "Val": "go test -v" + }, + { + "Namespace": "", + "Key": "src", + "Val": "src/recover-named" + }, + { + "Namespace": "", + "Key": "test", + "Val": "-v" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "test", + "-v" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/recover-named", + "duration": "3.892094792s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go test -v\n\n=== RUN Test_DoSomething\n=== PAUSE Test_DoSomething\n=== CONT Test_DoSomething\n--- PASS: Test_DoSomething (0.00s)\nPASS\nok \tdemo\t1.864s", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "=== RUN Test_DoSomething\n=== PAUSE Test_DoSomething\n=== CONT Test_DoSomething\n--- PASS: Test_DoSomething (0.00s)\nPASS\nok \tdemo\t1.864s", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "test", + "-v" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/recover-named", + "duration": "3.892094792s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go test -v\n\n=== RUN Test_DoSomething\n=== PAUSE Test_DoSomething\n=== CONT Test_DoSomething\n--- PASS: Test_DoSomething (0.00s)\nPASS\nok \tdemo\t1.864s", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "=== RUN Test_DoSomething\n=== PAUSE Test_DoSomething\n=== CONT Test_DoSomething\n--- PASS: Test_DoSomething (0.00s)\nPASS\nok \tdemo\t1.864s", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd data-go-version=\"go1.22.0\" exec=\"go test -v\" src=\"panic/src/recover-named\" test=\"-v\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.23:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "Tests now pass after proper panic recovery.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 23, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-23\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "tag": "\u003cpage\u003e", + "title": "Panic", + "type": "hype.Page" + } + ], + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "atom": "include", + "attributes": { + "src": "panic/_dont.md" + }, + "dir": ".", + "filename": "panic.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "_dont.md" + } + ], + "data": "include", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "page", + "attributes": {}, + "filename": "panic/_dont.md", + "html_node": { + "data": "page", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "atom": "h1", + "attributes": {}, + "filename": "panic/_dont.md", + "html_node": { + "data": "h1", + "data_atom": "h1", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "level": 1, + "nodes": [ + { + "text": "Don't Panic", + "type": "hype.Text" + } + ], + "tag": "\u003ch1\u003e", + "type": "hype.Heading" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + { + "atom": "blockquote", + "attributes": {}, + "filename": "panic/_dont.md", + "html_node": { + "data": "blockquote", + "data_atom": "blockquote", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + { + "atom": "strong", + "attributes": {}, + "filename": "panic/_dont.md", + "html_node": { + "data": "strong", + "data_atom": "strong", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "NEVER RAISE A PANIC IN YOUR CODE", + "type": "hype.Text" + } + ], + "tag": "\u003cstrong\u003e", + "type": "hype.Element" + }, + { + "text": "\n", + "type": "hype.Text" + } + ], + "tag": "\u003cblockquote\u003e", + "type": "hype.Element" + }, + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "panic/_dont.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Ok, maybe ", + "type": "hype.Text" + }, + { + "atom": "strong", + "attributes": {}, + "filename": "panic/_dont.md", + "html_node": { + "data": "strong", + "data_atom": "strong", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "never", + "type": "hype.Text" + } + ], + "tag": "\u003cstrong\u003e", + "type": "hype.Element" + }, + { + "text": " is too strong of a stance. However, in general, it's considered non-idiomatic to panic instead of returning an error outside of specific conditions.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "panic/_dont.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "When a panic occurs, unless there is a recover in place, the program will shut down (usually not gracefully). It is usually a much better practice to return an error, and let the code upstream handle the error.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "panic/_dont.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "The general rule is that if you are writing a package, you should not panic. The reason for this is that the caller should always have control of the program, and a package should not dictate control flow of a program.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "panic/_dont.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "On the other hand, if you are the caller (maybe you are in control of the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "panic/_dont.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "main", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " function in the program), then you already have total control of the program flow, and if needed, a panic may be appropriate. Many times this is manifested in the form of a ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "log#Fatal", + "href": "https://pkg.go.dev/log#Fatal", + "target": "_blank" + }, + "filename": "panic/_dont.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "panic/_dont.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "log.Fatal", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"log#Fatal\" href=\"https://pkg.go.dev/log#Fatal\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/log#Fatal" + } + ], + { + "text": ", ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-24" + }, + "filename": "panic/_dont.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "fatal.doc" + } + ], + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-24" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.24", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-24\"\u003e", + "type": "hype.Link", + "url": "#listing-1-24" + } + ], + "tag": "\u003cref id=\"listing-1-24\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ", which will exit the program with a non-zero exit code.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-24", + "type": "listing" + }, + "filename": "panic/_dont.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "fatal.doc" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "args": [ + "go", + "doc", + "log.Fatal" + ], + "atom": "cmd", + "attributes": { + "data-go-version": "go1.22.0", + "doc": "log.Fatal", + "exec": "go doc log.Fatal" + }, + "expected_exit": 0, + "filename": "panic", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "data-go-version", + "Val": "go1.22.0" + }, + { + "Namespace": "", + "Key": "doc", + "Val": "log.Fatal" + }, + { + "Namespace": "", + "Key": "exec", + "Val": "go doc log.Fatal" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "doc", + "log.Fatal" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypejs", + "duration": "1.932561667s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go doc log.Fatal\n\npackage log // import \u0026#34;log\u0026#34;\n\nfunc Fatal(v ...any)\n Fatal is equivalent to Print followed by a call to os.Exit(1).", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "package log // import \"log\"\n\nfunc Fatal(v ...any)\n Fatal is equivalent to Print followed by a call to os.Exit(1).", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "doc", + "log.Fatal" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypejs", + "duration": "1.932561667s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go doc log.Fatal\n\npackage log // import \u0026#34;log\u0026#34;\n\nfunc Fatal(v ...any)\n Fatal is equivalent to Print followed by a call to os.Exit(1).", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "package log // import \"log\"\n\nfunc Fatal(v ...any)\n Fatal is equivalent to Print followed by a call to os.Exit(1).", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd data-go-version=\"go1.22.0\" doc=\"log.Fatal\" exec=\"go doc log.Fatal\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.24:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "The ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "log#Fatal", + "href": "https://pkg.go.dev/log#Fatal", + "target": "_blank" + }, + "filename": "panic", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "for", + "Val": "log#Fatal" + }, + { + "Namespace": "", + "Key": "href", + "Val": "https://pkg.go.dev/log#Fatal" + }, + { + "Namespace": "", + "Key": "target", + "Val": "_blank" + } + ], + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "log.Fatal", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ] + ], + "tag": "\u003ca for=\"log#Fatal\" href=\"https://pkg.go.dev/log#Fatal\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/log#Fatal" + } + ], + { + "text": " function.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 24, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-24\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "panic/_dont.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Lastly, any code that panics may be more difficult to test. For all of these reasons, it is best to consider alternatives to a panicking. After all, most panics can be prevented by sensible code and well designed tests.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "h2", + "attributes": {}, + "filename": "panic/_dont.md", + "html_node": { + "data": "h2", + "data_atom": "h2", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "level": 2, + "nodes": [ + { + "text": "Checking for Nil", + "type": "hype.Text" + } + ], + "tag": "\u003ch2\u003e", + "type": "hype.Heading" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "panic/_dont.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "The most common source of panics in Go are calls being made on ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "panic/_dont.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "nil", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " values. Any type in go that has a zero value of ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "panic/_dont.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "nil", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " can be a source of these panics. Types such as interfaces, maps, pointers, channels, and functions all fall into this category. Checking whether these types are ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "panic/_dont.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "nil", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " before using them can easily avoid these panics.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "panic/_dont.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "A common example of this is when a type has an embedded type that is a pointer. In ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-25" + }, + "filename": "panic/_dont.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "nil" + } + ], + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-25" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.25", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-25\"\u003e", + "type": "hype.Link", + "url": "#listing-1-25" + } + ], + "tag": "\u003cref id=\"listing-1-25\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ", ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "panic/_dont.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "User", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " is embedded in ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "panic/_dont.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Admin", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " as a pointer. Because it's embedded, the methods are promoted. This means that the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "panic/_dont.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Admin", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " type now has a ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "panic/_dont.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "String", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " method. However, on the last line of code where ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "panic/_dont.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "a.String()", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " is being called, the receiver to the method is actually the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "panic/_dont.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "User", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": ". Because ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "panic/_dont.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "User", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " is ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "panic/_dont.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "nil", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": ", it was never set, the code will panic when it tries to access the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "panic/_dont.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "String", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " method.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-25", + "type": "listing" + }, + "filename": "panic/_dont.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "nil" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + { + "atom": "pre", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "src": "panic/src/nil/main.go" + }, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/nil/main.go" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "text": "package main\n\nimport \u0026#34;fmt\u0026#34;\n\ntype User struct {\n\tname string\n}\n\nfunc (u User) String() string {\n\treturn u.name\n}\n\ntype Admin struct {\n\t*User\n\tPerms map[string]bool\n}\n\nfunc main() {\n\ta := \u0026amp;Admin{}\n\tfmt.Println(a.String())\n}\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" src=\"panic/src/nil/main.go\"\u003e", + "type": "hype.SourceCode" + } + ] + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + }, + { + "atom": "hr", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "hr", + "data_atom": "hr", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [], + "tag": "\u003chr\u003e", + "type": "hype.Element" + }, + [ + { + "args": [ + "go", + "run", + "." + ], + "atom": "cmd", + "attributes": { + "data-go-version": "go1.22.0", + "exec": "go run .", + "exit": "-1", + "run": ".", + "src": "panic/src/nil" + }, + "expected_exit": -1, + "filename": "panic", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "data-go-version", + "Val": "go1.22.0" + }, + { + "Namespace": "", + "Key": "exec", + "Val": "go run ." + }, + { + "Namespace": "", + "Key": "exit", + "Val": "-1" + }, + { + "Namespace": "", + "Key": "run", + "Val": "." + }, + { + "Namespace": "", + "Key": "src", + "Val": "src/nil" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "run", + "." + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/nil", + "duration": "3.221337792s", + "err": "exit status 1", + "exit": 1, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go run .\n\npanic: runtime error: invalid memory address or nil pointer dereference\n[signal SIGSEGV: segmentation violation code=0x2 addr=0x8 pc=0x102978a9c]\n\ngoroutine 1 [running]:\nmain.main()\n\t/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/nil/main.go:20 +0x1c\nexit status 2", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "panic: runtime error: invalid memory address or nil pointer dereference\n[signal SIGSEGV: segmentation violation code=0x2 addr=0x8 pc=0x102978a9c]\n\ngoroutine 1 [running]:\nmain.main()\n\t/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/nil/main.go:20 +0x1c\nexit status 2", + "stdout": "", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "run", + "." + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/nil", + "duration": "3.221337792s", + "err": "exit status 1", + "exit": 1, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go run .\n\npanic: runtime error: invalid memory address or nil pointer dereference\n[signal SIGSEGV: segmentation violation code=0x2 addr=0x8 pc=0x102978a9c]\n\ngoroutine 1 [running]:\nmain.main()\n\t/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/nil/main.go:20 +0x1c\nexit status 2", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "panic: runtime error: invalid memory address or nil pointer dereference\n[signal SIGSEGV: segmentation violation code=0x2 addr=0x8 pc=0x102978a9c]\n\ngoroutine 1 [running]:\nmain.main()\n\t/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/nil/main.go:20 +0x1c\nexit status 2", + "stdout": "", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd data-go-version=\"go1.22.0\" exec=\"go run .\" exit=\"-1\" run=\".\" src=\"panic/src/nil\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.25:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "A panic when calling a method on a ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "nil", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " value.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 25, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-25\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "panic/_dont.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "In ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-26" + }, + "filename": "panic/_dont.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "non-nil" + } + ], + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-26" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.26", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-26\"\u003e", + "type": "hype.Link", + "url": "#listing-1-26" + } + ], + "tag": "\u003cref id=\"listing-1-26\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ", the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "panic/_dont.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Admin", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " type is properly initialized with a ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "panic/_dont.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "User", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": ". Now, when the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "panic/_dont.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "String", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " method is called, the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "panic/_dont.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "User", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " is not ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "panic/_dont.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "nil", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": ", and the method properly executes.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-26", + "type": "listing" + }, + "filename": "panic/_dont.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "non-nil" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + { + "atom": "pre", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "src": "panic/src/non-nil/main.go" + }, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/non-nil/main.go" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "text": "package main\n\nimport \u0026#34;fmt\u0026#34;\n\ntype User struct {\n\tname string\n}\n\nfunc (u User) String() string {\n\treturn u.name\n}\n\ntype Admin struct {\n\t*User\n\tPerms map[string]bool\n}\n\nfunc main() {\n\ta := \u0026amp;Admin{\n\t\tUser: \u0026amp;User{name: \u0026#34;Kurt\u0026#34;},\n\t}\n\tfmt.Println(a.String())\n}\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" src=\"panic/src/non-nil/main.go\"\u003e", + "type": "hype.SourceCode" + } + ] + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + }, + { + "atom": "hr", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "hr", + "data_atom": "hr", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [], + "tag": "\u003chr\u003e", + "type": "hype.Element" + }, + [ + { + "args": [ + "go", + "run", + "." + ], + "atom": "cmd", + "attributes": { + "data-go-version": "go1.22.0", + "exec": "go run .", + "run": ".", + "src": "panic/src/non-nil" + }, + "expected_exit": 0, + "filename": "panic", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "data-go-version", + "Val": "go1.22.0" + }, + { + "Namespace": "", + "Key": "exec", + "Val": "go run ." + }, + { + "Namespace": "", + "Key": "run", + "Val": "." + }, + { + "Namespace": "", + "Key": "src", + "Val": "src/non-nil" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "run", + "." + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/non-nil", + "duration": "2.142392583s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go run .\n\nKurt", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "Kurt", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "run", + "." + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/non-nil", + "duration": "2.142392583s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go run .\n\nKurt", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "Kurt", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd data-go-version=\"go1.22.0\" exec=\"go run .\" run=\".\" src=\"panic/src/non-nil\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.26:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "Proper initialization to prevent panicking.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 26, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-26\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "h2", + "attributes": {}, + "filename": "panic/_dont.md", + "html_node": { + "data": "h2", + "data_atom": "h2", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "level": 2, + "nodes": [ + { + "text": "Maps", + "type": "hype.Text" + } + ], + "tag": "\u003ch2\u003e", + "type": "hype.Heading" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "panic/_dont.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "When creating maps, it is required to ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "panic/_dont.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "initialize", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " the memory space behind them. Consider ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-27" + }, + "filename": "panic/_dont.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "map-broken" + } + ], + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-27" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.27", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-27\"\u003e", + "type": "hype.Link", + "url": "#listing-1-27" + } + ], + "tag": "\u003cref id=\"listing-1-27\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": " as an example. We have created a map variable, but we have not initialized it. This causes a panic when we try to access the map.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-27", + "type": "listing" + }, + "filename": "panic/_dont.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "map-broken" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + { + "atom": "pre", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "src": "panic/src/maps/broken/main.go" + }, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/maps/broken/main.go" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "text": "package main\n\nimport \u0026#34;fmt\u0026#34;\n\nfunc main() {\n\n\t// create a new map variable\n\tvar m map[string]int\n\n\t// insert a key-value pair\n\tm[\u0026#34;Amy\u0026#34;] = 27\n\n\t// print the map\n\tfmt.Printf(\u0026#34;%+v\\n\u0026#34;, m)\n}\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" src=\"panic/src/maps/broken/main.go\"\u003e", + "type": "hype.SourceCode" + } + ] + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + }, + { + "atom": "hr", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "hr", + "data_atom": "hr", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [], + "tag": "\u003chr\u003e", + "type": "hype.Element" + }, + [ + { + "args": [ + "go", + "run", + "." + ], + "atom": "cmd", + "attributes": { + "data-go-version": "go1.22.0", + "exec": "go run .", + "exit": "-1", + "run": ".", + "src": "panic/src/maps/broken" + }, + "expected_exit": -1, + "filename": "panic", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "data-go-version", + "Val": "go1.22.0" + }, + { + "Namespace": "", + "Key": "exec", + "Val": "go run ." + }, + { + "Namespace": "", + "Key": "exit", + "Val": "-1" + }, + { + "Namespace": "", + "Key": "run", + "Val": "." + }, + { + "Namespace": "", + "Key": "src", + "Val": "src/maps/broken" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "run", + "." + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/maps/broken", + "duration": "4.542353916s", + "err": "exit status 1", + "exit": 1, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go run .\n\npanic: assignment to entry in nil map\n\ngoroutine 1 [running]:\nmain.main()\n\t/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/maps/broken/main.go:11 +0x34\nexit status 2", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "panic: assignment to entry in nil map\n\ngoroutine 1 [running]:\nmain.main()\n\t/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/maps/broken/main.go:11 +0x34\nexit status 2", + "stdout": "", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "run", + "." + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/maps/broken", + "duration": "4.542353916s", + "err": "exit status 1", + "exit": 1, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go run .\n\npanic: assignment to entry in nil map\n\ngoroutine 1 [running]:\nmain.main()\n\t/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/maps/broken/main.go:11 +0x34\nexit status 2", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "panic: assignment to entry in nil map\n\ngoroutine 1 [running]:\nmain.main()\n\t/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/maps/broken/main.go:11 +0x34\nexit status 2", + "stdout": "", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd data-go-version=\"go1.22.0\" exec=\"go run .\" exit=\"-1\" run=\".\" src=\"panic/src/maps/broken\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.27:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "A panic when creating a map with a nil value.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 27, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-27\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "panic/_dont.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "The easiest solution is to use the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "panic/_dont.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": ":=", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " operator to initialize the map when the variable is declared. In ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-28" + }, + "filename": "panic/_dont.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "map-init" + } + ], + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-28" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.28", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-28\"\u003e", + "type": "hype.Link", + "url": "#listing-1-28" + } + ], + "tag": "\u003cref id=\"listing-1-28\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ", we have initialized the map and the code runs successfully.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-28", + "type": "listing" + }, + "filename": "panic/_dont.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "map-init" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + { + "atom": "pre", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "src": "panic/src/maps/init/main.go" + }, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/maps/init/main.go" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "text": "package main\n\nimport \u0026#34;fmt\u0026#34;\n\nfunc main() {\n\n\t// initialize a new map\n\tm := map[string]int{}\n\n\t// insert a key-value pair\n\tm[\u0026#34;Amy\u0026#34;] = 27\n\n\t// print the map\n\tfmt.Printf(\u0026#34;%+v\\n\u0026#34;, m)\n}\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" src=\"panic/src/maps/init/main.go\"\u003e", + "type": "hype.SourceCode" + } + ] + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + }, + { + "atom": "hr", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "hr", + "data_atom": "hr", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [], + "tag": "\u003chr\u003e", + "type": "hype.Element" + }, + [ + { + "args": [ + "go", + "run", + "." + ], + "atom": "cmd", + "attributes": { + "data-go-version": "go1.22.0", + "exec": "go run .", + "run": ".", + "src": "panic/src/maps/init" + }, + "expected_exit": 0, + "filename": "panic", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "data-go-version", + "Val": "go1.22.0" + }, + { + "Namespace": "", + "Key": "exec", + "Val": "go run ." + }, + { + "Namespace": "", + "Key": "run", + "Val": "." + }, + { + "Namespace": "", + "Key": "src", + "Val": "src/maps/init" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "run", + "." + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/maps/init", + "duration": "2.837135125s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go run .\n\nmap[Amy:27]", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "map[Amy:27]", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "run", + "." + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/maps/init", + "duration": "2.837135125s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go run .\n\nmap[Amy:27]", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "map[Amy:27]", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd data-go-version=\"go1.22.0\" exec=\"go run .\" run=\".\" src=\"panic/src/maps/init\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.28:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "Avoiding panics when creating maps.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 28, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-28\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "panic/_dont.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "However, if a map is declared with long variable declaration, and not initialized, later in the code the map will need to be initialized or it will panic when used.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-29", + "type": "listing" + }, + "filename": "panic/_dont.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "map-check" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + { + "atom": "pre", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "src": "panic/src/maps/check/main.go" + }, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/maps/check/main.go" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "text": "package main\n\nimport \u0026#34;fmt\u0026#34;\n\nfunc main() {\n\n\t// create a new map variable\n\tvar m map[string]int\n\n\tif m == nil {\n\t\t// initialize the map\n\t\tm = map[string]int{}\n\t}\n\n\t// insert a key-value pair\n\tm[\u0026#34;Amy\u0026#34;] = 27\n\n\t// print the map\n\tfmt.Printf(\u0026#34;%+v\\n\u0026#34;, m)\n}\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" src=\"panic/src/maps/check/main.go\"\u003e", + "type": "hype.SourceCode" + } + ] + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + }, + { + "atom": "hr", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "hr", + "data_atom": "hr", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [], + "tag": "\u003chr\u003e", + "type": "hype.Element" + }, + [ + { + "args": [ + "go", + "run", + "." + ], + "atom": "cmd", + "attributes": { + "data-go-version": "go1.22.0", + "exec": "go run .", + "run": ".", + "src": "panic/src/maps/check" + }, + "expected_exit": 0, + "filename": "panic", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "data-go-version", + "Val": "go1.22.0" + }, + { + "Namespace": "", + "Key": "exec", + "Val": "go run ." + }, + { + "Namespace": "", + "Key": "run", + "Val": "." + }, + { + "Namespace": "", + "Key": "src", + "Val": "src/maps/check" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "run", + "." + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/maps/check", + "duration": "4.191048s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go run .\n\nmap[Amy:27]", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "map[Amy:27]", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "run", + "." + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/maps/check", + "duration": "4.191048s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go run .\n\nmap[Amy:27]", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "map[Amy:27]", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd data-go-version=\"go1.22.0\" exec=\"go run .\" run=\".\" src=\"panic/src/maps/check\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.29:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "Checking a map for ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "nil", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " before accessing.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 29, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-29\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "panic/_dont.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Finally, as in ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-30" + }, + "filename": "panic/_dont.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "map-make" + } + ], + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-30" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.30", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-30\"\u003e", + "type": "hype.Link", + "url": "#listing-1-30" + } + ], + "tag": "\u003cref id=\"listing-1-30\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ", we can use the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "builtin#make", + "href": "https://pkg.go.dev/builtin#make", + "target": "_blank" + }, + "filename": "panic/_dont.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "panic/_dont.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "make", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"builtin#make\" href=\"https://pkg.go.dev/builtin#make\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/builtin#make" + } + ], + { + "text": " function to initialize the map. While this works, it is consider non-idiomatic to use ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "builtin#make", + "href": "https://pkg.go.dev/builtin#make", + "target": "_blank" + }, + "filename": "panic/_dont.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "panic/_dont.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "make", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"builtin#make\" href=\"https://pkg.go.dev/builtin#make\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/builtin#make" + } + ], + { + "text": " to initialize a map.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-30", + "type": "listing" + }, + "filename": "panic/_dont.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "map-make" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + { + "atom": "pre", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "src": "panic/src/maps/make/main.go" + }, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/maps/make/main.go" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "text": "package main\n\nimport \u0026#34;fmt\u0026#34;\n\nfunc main() {\n\n\t// initialize a new map\n\tm := make(map[string]int)\n\n\t// insert a key-value pair\n\tm[\u0026#34;Amy\u0026#34;] = 27\n\n\t// print the map\n\tfmt.Printf(\u0026#34;%+v\\n\u0026#34;, m)\n}\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" src=\"panic/src/maps/make/main.go\"\u003e", + "type": "hype.SourceCode" + } + ] + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + }, + { + "atom": "hr", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "hr", + "data_atom": "hr", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [], + "tag": "\u003chr\u003e", + "type": "hype.Element" + }, + [ + { + "args": [ + "go", + "run", + "." + ], + "atom": "cmd", + "attributes": { + "data-go-version": "go1.22.0", + "exec": "go run .", + "run": ".", + "src": "panic/src/maps/make" + }, + "expected_exit": 0, + "filename": "panic", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "data-go-version", + "Val": "go1.22.0" + }, + { + "Namespace": "", + "Key": "exec", + "Val": "go run ." + }, + { + "Namespace": "", + "Key": "run", + "Val": "." + }, + { + "Namespace": "", + "Key": "src", + "Val": "src/maps/make" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "run", + "." + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/maps/make", + "duration": "3.680575042s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go run .\n\nmap[Amy:27]", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "map[Amy:27]", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "run", + "." + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/maps/make", + "duration": "3.680575042s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go run .\n\nmap[Amy:27]", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "map[Amy:27]", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd data-go-version=\"go1.22.0\" exec=\"go run .\" run=\".\" src=\"panic/src/maps/make\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.30:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "Using ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "builtin#make", + "href": "https://pkg.go.dev/builtin#make", + "target": "_blank" + }, + "filename": "panic", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "for", + "Val": "builtin#make" + }, + { + "Namespace": "", + "Key": "href", + "Val": "https://pkg.go.dev/builtin#make" + }, + { + "Namespace": "", + "Key": "target", + "Val": "_blank" + } + ], + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "make", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ] + ], + "tag": "\u003ca for=\"builtin#make\" href=\"https://pkg.go.dev/builtin#make\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/builtin#make" + } + ], + { + "text": " to initialize a map.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 30, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-30\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "h2", + "attributes": {}, + "filename": "panic/_dont.md", + "html_node": { + "data": "h2", + "data_atom": "h2", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "level": 2, + "nodes": [ + { + "text": "Pointers", + "type": "hype.Text" + } + ], + "tag": "\u003ch2\u003e", + "type": "hype.Heading" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "panic/_dont.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Before a pointer can be used, it has to be initialized. The following code checks to see if a pointer is ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "panic/_dont.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "nil", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": ", not initialized, and then properly initializes it.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-31", + "type": "listing" + }, + "filename": "panic/_dont.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "ptr-broken" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + { + "atom": "pre", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "src": "panic/src/pointers/broken/main.go" + }, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/pointers/broken/main.go" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "text": "package main\n\nimport (\n\t\u0026#34;bytes\u0026#34;\n\t\u0026#34;fmt\u0026#34;\n)\n\nfunc main() {\n\n\t// create a new pointer\n\t// to a bytes.Buffer\n\tvar bb *bytes.Buffer\n\n\t// use the pointer to\n\t// write data to the buffer\n\tbb.WriteString(\u0026#34;Hello, world!\u0026#34;)\n\n\t// print the buffer\n\tfmt.Println(bb.String())\n}\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" src=\"panic/src/pointers/broken/main.go\"\u003e", + "type": "hype.SourceCode" + } + ] + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + }, + { + "atom": "hr", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "hr", + "data_atom": "hr", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [], + "tag": "\u003chr\u003e", + "type": "hype.Element" + }, + [ + { + "args": [ + "go", + "run", + "." + ], + "atom": "cmd", + "attributes": { + "data-go-version": "go1.22.0", + "exec": "go run .", + "exit": "-1", + "run": ".", + "src": "panic/src/pointers/broken" + }, + "expected_exit": -1, + "filename": "panic", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "data-go-version", + "Val": "go1.22.0" + }, + { + "Namespace": "", + "Key": "exec", + "Val": "go run ." + }, + { + "Namespace": "", + "Key": "exit", + "Val": "-1" + }, + { + "Namespace": "", + "Key": "run", + "Val": "." + }, + { + "Namespace": "", + "Key": "src", + "Val": "src/pointers/broken" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "run", + "." + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/pointers/broken", + "duration": "1.819582458s", + "err": "exit status 1", + "exit": 1, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go run .\n\npanic: runtime error: invalid memory address or nil pointer dereference\n[signal SIGSEGV: segmentation violation code=0x2 addr=0x20 pc=0x1030621cc]\n\ngoroutine 1 [running]:\nbytes.(*Buffer).WriteString(0x14000070738?, {0x103086364?, 0x60?})\n\t/usr/local/go/src/bytes/buffer.go:188 +0x1c\nmain.main()\n\t/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/pointers/broken/main.go:16 +0x2c\nexit status 2", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "panic: runtime error: invalid memory address or nil pointer dereference\n[signal SIGSEGV: segmentation violation code=0x2 addr=0x20 pc=0x1030621cc]\n\ngoroutine 1 [running]:\nbytes.(*Buffer).WriteString(0x14000070738?, {0x103086364?, 0x60?})\n\t/usr/local/go/src/bytes/buffer.go:188 +0x1c\nmain.main()\n\t/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/pointers/broken/main.go:16 +0x2c\nexit status 2", + "stdout": "", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "run", + "." + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/pointers/broken", + "duration": "1.819582458s", + "err": "exit status 1", + "exit": 1, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go run .\n\npanic: runtime error: invalid memory address or nil pointer dereference\n[signal SIGSEGV: segmentation violation code=0x2 addr=0x20 pc=0x1030621cc]\n\ngoroutine 1 [running]:\nbytes.(*Buffer).WriteString(0x14000070738?, {0x103086364?, 0x60?})\n\t/usr/local/go/src/bytes/buffer.go:188 +0x1c\nmain.main()\n\t/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/pointers/broken/main.go:16 +0x2c\nexit status 2", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "panic: runtime error: invalid memory address or nil pointer dereference\n[signal SIGSEGV: segmentation violation code=0x2 addr=0x20 pc=0x1030621cc]\n\ngoroutine 1 [running]:\nbytes.(*Buffer).WriteString(0x14000070738?, {0x103086364?, 0x60?})\n\t/usr/local/go/src/bytes/buffer.go:188 +0x1c\nmain.main()\n\t/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/pointers/broken/main.go:16 +0x2c\nexit status 2", + "stdout": "", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd data-go-version=\"go1.22.0\" exec=\"go run .\" exit=\"-1\" run=\".\" src=\"panic/src/pointers/broken\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.31:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "A panic caused by a ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "nil", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " pointer.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 31, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-31\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-32", + "type": "listing" + }, + "filename": "panic/_dont.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "ptr-fixed" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + { + "atom": "pre", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "src": "panic/src/pointers/fixed/main.go" + }, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/pointers/fixed/main.go" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "text": "package main\n\nimport (\n\t\u0026#34;bytes\u0026#34;\n\t\u0026#34;fmt\u0026#34;\n)\n\nfunc main() {\n\n\t// create and initialize\n\t// a new pointer\n\t// to a bytes.Buffer\n\tbb := \u0026amp;bytes.Buffer{}\n\n\t// use the pointer to\n\t// write data to the buffer\n\tbb.WriteString(\u0026#34;Hello, world!\u0026#34;)\n\n\t// print the buffer\n\tfmt.Println(bb.String())\n}\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" src=\"panic/src/pointers/fixed/main.go\"\u003e", + "type": "hype.SourceCode" + } + ] + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + }, + { + "atom": "hr", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "hr", + "data_atom": "hr", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [], + "tag": "\u003chr\u003e", + "type": "hype.Element" + }, + [ + { + "args": [ + "go", + "run", + "." + ], + "atom": "cmd", + "attributes": { + "data-go-version": "go1.22.0", + "exec": "go run .", + "run": ".", + "src": "panic/src/pointers/fixed" + }, + "expected_exit": 0, + "filename": "panic", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "data-go-version", + "Val": "go1.22.0" + }, + { + "Namespace": "", + "Key": "exec", + "Val": "go run ." + }, + { + "Namespace": "", + "Key": "run", + "Val": "." + }, + { + "Namespace": "", + "Key": "src", + "Val": "src/pointers/fixed" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "run", + "." + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/pointers/fixed", + "duration": "3.153478709s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go run .\n\nHello, world!", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "Hello, world!", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "run", + "." + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/pointers/fixed", + "duration": "3.153478709s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go run .\n\nHello, world!", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "Hello, world!", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd data-go-version=\"go1.22.0\" exec=\"go run .\" run=\".\" src=\"panic/src/pointers/fixed\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.32:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "Properly initializing a pointer before use.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 32, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-32\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "h2", + "attributes": {}, + "filename": "panic/_dont.md", + "html_node": { + "data": "h2", + "data_atom": "h2", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "level": 2, + "nodes": [ + { + "text": "Interfaces", + "type": "hype.Text" + } + ], + "tag": "\u003ch2\u003e", + "type": "hype.Heading" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "panic/_dont.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "In ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-33" + }, + "filename": "panic/_dont.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "interface.broken" + } + ], + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-33" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.33", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-33\"\u003e", + "type": "hype.Link", + "url": "#listing-1-33" + } + ], + "tag": "\u003cref id=\"listing-1-33\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ", we have create a new variable, ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "panic/_dont.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "w", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": ", of type ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "io#Writer", + "href": "https://pkg.go.dev/io#Writer", + "target": "_blank" + }, + "filename": "panic/_dont.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "panic/_dont.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "io.Writer", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"io#Writer\" href=\"https://pkg.go.dev/io#Writer\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/io#Writer" + } + ], + { + "text": ". This variable has not be initialized with an implementation of the interface. This causes a panic when we try to use the variable.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-33", + "type": "listing" + }, + "filename": "panic/_dont.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "interface.broken" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + { + "atom": "pre", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "src": "panic/src/interface/broken/main.go" + }, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/interface/broken/main.go" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "text": "package main\n\nimport (\n\t\u0026#34;fmt\u0026#34;\n\t\u0026#34;io\u0026#34;\n)\n\nfunc main() {\n\n\t// create a new writer variable\n\tvar w io.Writer\n\n\t// print to the writer\n\tfmt.Fprintln(w, \u0026#34;Hello, world!\u0026#34;)\n}\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" src=\"panic/src/interface/broken/main.go\"\u003e", + "type": "hype.SourceCode" + } + ] + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + }, + { + "atom": "hr", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "hr", + "data_atom": "hr", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [], + "tag": "\u003chr\u003e", + "type": "hype.Element" + }, + [ + { + "args": [ + "go", + "run", + "." + ], + "atom": "cmd", + "attributes": { + "data-go-version": "go1.22.0", + "exec": "go run .", + "exit": "-1", + "run": ".", + "src": "panic/src/interface/broken" + }, + "expected_exit": -1, + "filename": "panic", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "data-go-version", + "Val": "go1.22.0" + }, + { + "Namespace": "", + "Key": "exec", + "Val": "go run ." + }, + { + "Namespace": "", + "Key": "exit", + "Val": "-1" + }, + { + "Namespace": "", + "Key": "run", + "Val": "." + }, + { + "Namespace": "", + "Key": "src", + "Val": "src/interface/broken" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "run", + "." + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/interface/broken", + "duration": "2.276858041s", + "err": "exit status 1", + "exit": 1, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go run .\n\npanic: runtime error: invalid memory address or nil pointer dereference\n[signal SIGSEGV: segmentation violation code=0x2 addr=0x18 pc=0x104bead38]\n\ngoroutine 1 [running]:\nfmt.Fprintln({0x0, 0x0}, {0x14000108f28, 0x1, 0x1})\n\t/usr/local/go/src/fmt/print.go:305 +0x48\nmain.main()\n\t/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/interface/broken/main.go:14 +0x4c\nexit status 2", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "panic: runtime error: invalid memory address or nil pointer dereference\n[signal SIGSEGV: segmentation violation code=0x2 addr=0x18 pc=0x104bead38]\n\ngoroutine 1 [running]:\nfmt.Fprintln({0x0, 0x0}, {0x14000108f28, 0x1, 0x1})\n\t/usr/local/go/src/fmt/print.go:305 +0x48\nmain.main()\n\t/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/interface/broken/main.go:14 +0x4c\nexit status 2", + "stdout": "", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "run", + "." + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/interface/broken", + "duration": "2.276858041s", + "err": "exit status 1", + "exit": 1, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go run .\n\npanic: runtime error: invalid memory address or nil pointer dereference\n[signal SIGSEGV: segmentation violation code=0x2 addr=0x18 pc=0x104bead38]\n\ngoroutine 1 [running]:\nfmt.Fprintln({0x0, 0x0}, {0x14000108f28, 0x1, 0x1})\n\t/usr/local/go/src/fmt/print.go:305 +0x48\nmain.main()\n\t/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/interface/broken/main.go:14 +0x4c\nexit status 2", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "panic: runtime error: invalid memory address or nil pointer dereference\n[signal SIGSEGV: segmentation violation code=0x2 addr=0x18 pc=0x104bead38]\n\ngoroutine 1 [running]:\nfmt.Fprintln({0x0, 0x0}, {0x14000108f28, 0x1, 0x1})\n\t/usr/local/go/src/fmt/print.go:305 +0x48\nmain.main()\n\t/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/interface/broken/main.go:14 +0x4c\nexit status 2", + "stdout": "", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd data-go-version=\"go1.22.0\" exec=\"go run .\" exit=\"-1\" run=\".\" src=\"panic/src/interface/broken\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.33:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "A panic caused by a ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "nil", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " interface.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 33, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-33\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "panic/_dont.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "In ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-34" + }, + "filename": "panic/_dont.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "interface.fixed" + } + ], + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-34" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.34", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-34\"\u003e", + "type": "hype.Link", + "url": "#listing-1-34" + } + ], + "tag": "\u003cref id=\"listing-1-34\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ", we have initialized the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "panic/_dont.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "w", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " variable with an implementation of the interface, in this case ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "io#Stdout", + "href": "https://pkg.go.dev/io#Stdout", + "target": "_blank" + }, + "filename": "panic/_dont.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "panic/_dont.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "io.Stdout", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"io#Stdout\" href=\"https://pkg.go.dev/io#Stdout\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/io#Stdout" + } + ], + { + "text": ".", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-34", + "type": "listing" + }, + "filename": "panic/_dont.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "interface.fixed" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + { + "atom": "pre", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "src": "panic/src/interface/fixed/main.go" + }, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/interface/fixed/main.go" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "text": "package main\n\nimport (\n\t\u0026#34;fmt\u0026#34;\n\t\u0026#34;os\u0026#34;\n)\n\nfunc main() {\n\n\t// create a new writer variable\n\t// with STDOUT as the\n\t// writer implementation\n\tw := os.Stdout\n\n\t// print to the writer\n\tfmt.Fprintln(w, \u0026#34;Hello, world!\u0026#34;)\n}\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" src=\"panic/src/interface/fixed/main.go\"\u003e", + "type": "hype.SourceCode" + } + ] + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + }, + { + "atom": "hr", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "hr", + "data_atom": "hr", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [], + "tag": "\u003chr\u003e", + "type": "hype.Element" + }, + [ + { + "args": [ + "go", + "run", + "." + ], + "atom": "cmd", + "attributes": { + "data-go-version": "go1.22.0", + "exec": "go run .", + "run": ".", + "src": "panic/src/interface/fixed" + }, + "expected_exit": 0, + "filename": "panic", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "data-go-version", + "Val": "go1.22.0" + }, + { + "Namespace": "", + "Key": "exec", + "Val": "go run ." + }, + { + "Namespace": "", + "Key": "run", + "Val": "." + }, + { + "Namespace": "", + "Key": "src", + "Val": "src/interface/fixed" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "run", + "." + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/interface/fixed", + "duration": "2.689265084s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go run .\n\nHello, world!", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "Hello, world!", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "run", + "." + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/interface/fixed", + "duration": "2.689265084s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go run .\n\nHello, world!", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "Hello, world!", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd data-go-version=\"go1.22.0\" exec=\"go run .\" run=\".\" src=\"panic/src/interface/fixed\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.34:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "Initializing an interface before use.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 34, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-34\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "panic/_dont.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "More commonly, a panic will occur when an interface is embedded into a type, and that interface was not backed by an instance.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "panic/_dont.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "In ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-35" + }, + "filename": "panic/_dont.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "stream" + } + ], + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-35" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.35", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-35\"\u003e", + "type": "hype.Link", + "url": "#listing-1-35" + } + ], + "tag": "\u003cref id=\"listing-1-35\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": " we are defining a ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "panic/_dont.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Stream", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " struct that embeds the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "io#Writer", + "href": "https://pkg.go.dev/io#Writer", + "target": "_blank" + }, + "filename": "panic/_dont.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "panic/_dont.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "io.Writer", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"io#Writer\" href=\"https://pkg.go.dev/io#Writer\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/io#Writer" + } + ], + { + "text": " interface. By embedding the interface, the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "panic/_dont.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Stream", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " type is now also an implementation ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "io#Writer", + "href": "https://pkg.go.dev/io#Writer", + "target": "_blank" + }, + "filename": "panic/_dont.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "panic/_dont.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "io.Writer", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"io#Writer\" href=\"https://pkg.go.dev/io#Writer\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/io#Writer" + } + ], + { + "text": " as the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "io#Writer.Write", + "href": "https://pkg.go.dev/io#Writer.Write", + "target": "_blank" + }, + "filename": "panic/_dont.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "panic/_dont.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "io.Writer.Write", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"io#Writer.Write\" href=\"https://pkg.go.dev/io#Writer.Write\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/io#Writer.Write" + } + ], + { + "text": " method is promoted to the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "panic/_dont.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Stream", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " type.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-35", + "type": "listing" + }, + "filename": "panic/_dont.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "stream" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + { + "atom": "pre", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "src": "panic/src/interface/empty/main.go#type" + }, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/interface/empty/main.go#type" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "content": "type Stream struct {\n\tio.Writer\n}", + "file": "panic/src/interface/empty/main.go", + "lang": "go", + "name": "type", + "start": 8, + "end": 13 + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" src=\"panic/src/interface/empty/main.go#type\"\u003e", + "type": "hype.SourceCode" + } + ] + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + }, + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.35:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "A custom type that embeds an interface.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 35, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-35\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "panic/_dont.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "However, if an instance of a writer is never assigned to the embedded ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "io#Writer", + "href": "https://pkg.go.dev/io#Writer", + "target": "_blank" + }, + "filename": "panic/_dont.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "panic/_dont.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "io.Writer", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"io#Writer\" href=\"https://pkg.go.dev/io#Writer\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/io#Writer" + } + ], + { + "text": ", as in ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-36" + }, + "filename": "panic/_dont.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "stream-broken" + } + ], + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-36" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.36", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-36\"\u003e", + "type": "hype.Link", + "url": "#listing-1-36" + } + ], + "tag": "\u003cref id=\"listing-1-36\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ", the code will panic when it tries to call the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "io#Writer.Write", + "href": "https://pkg.go.dev/io#Writer.Write", + "target": "_blank" + }, + "filename": "panic/_dont.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "panic/_dont.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "io.Writer.Write", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"io#Writer.Write\" href=\"https://pkg.go.dev/io#Writer.Write\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/io#Writer.Write" + } + ], + { + "text": " method, as the receiver is ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "panic/_dont.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "nil", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": ".", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-36", + "type": "listing" + }, + "filename": "panic/_dont.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "stream-broken" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + { + "atom": "pre", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "src": "panic/src/interface/empty/main.go#example" + }, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/interface/empty/main.go#example" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "content": "func main() {\n\n\t// initialize a stream\n\t// without a writer\n\ts := Stream{}\n\n\tfmt.Fprintf(s, \"Hello Gophers!\")\n}", + "file": "panic/src/interface/empty/main.go", + "lang": "go", + "name": "example", + "start": 15, + "end": 25 + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" src=\"panic/src/interface/empty/main.go#example\"\u003e", + "type": "hype.SourceCode" + } + ] + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + }, + { + "atom": "hr", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "hr", + "data_atom": "hr", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [], + "tag": "\u003chr\u003e", + "type": "hype.Element" + }, + [ + { + "args": [ + "go", + "run", + "." + ], + "atom": "cmd", + "attributes": { + "data-go-version": "go1.22.0", + "exec": "go run .", + "exit": "-1", + "run": ".", + "src": "panic/src/interface/empty" + }, + "expected_exit": -1, + "filename": "panic", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "data-go-version", + "Val": "go1.22.0" + }, + { + "Namespace": "", + "Key": "exec", + "Val": "go run ." + }, + { + "Namespace": "", + "Key": "exit", + "Val": "-1" + }, + { + "Namespace": "", + "Key": "run", + "Val": "." + }, + { + "Namespace": "", + "Key": "src", + "Val": "src/interface/empty" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "run", + "." + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/interface/empty", + "duration": "2.012651667s", + "err": "exit status 1", + "exit": 1, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go run .\n\npanic: runtime error: invalid memory address or nil pointer dereference\n[signal SIGSEGV: segmentation violation code=0x2 addr=0x18 pc=0x102d0116c]\n\ngoroutine 1 [running]:\nmain.(*Stream).Write(0x140000a45b0?, {0x1400000e160?, 0xe?, 0x0?})\n\t\u0026lt;autogenerated\u0026gt;:1 +0x2c\nfmt.Fprintf({0x102d442f8, 0x14000010070}, {0x102d02798, 0xe}, {0x0, 0x0, 0x0})\n\t/usr/local/go/src/fmt/print.go:225 +0x84\nmain.main()\n\t/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/interface/empty/main.go:22 +0x54\nexit status 2", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "panic: runtime error: invalid memory address or nil pointer dereference\n[signal SIGSEGV: segmentation violation code=0x2 addr=0x18 pc=0x102d0116c]\n\ngoroutine 1 [running]:\nmain.(*Stream).Write(0x140000a45b0?, {0x1400000e160?, 0xe?, 0x0?})\n\t\u003cautogenerated\u003e:1 +0x2c\nfmt.Fprintf({0x102d442f8, 0x14000010070}, {0x102d02798, 0xe}, {0x0, 0x0, 0x0})\n\t/usr/local/go/src/fmt/print.go:225 +0x84\nmain.main()\n\t/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/interface/empty/main.go:22 +0x54\nexit status 2", + "stdout": "", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "run", + "." + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/interface/empty", + "duration": "2.012651667s", + "err": "exit status 1", + "exit": 1, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go run .\n\npanic: runtime error: invalid memory address or nil pointer dereference\n[signal SIGSEGV: segmentation violation code=0x2 addr=0x18 pc=0x102d0116c]\n\ngoroutine 1 [running]:\nmain.(*Stream).Write(0x140000a45b0?, {0x1400000e160?, 0xe?, 0x0?})\n\t\u0026lt;autogenerated\u0026gt;:1 +0x2c\nfmt.Fprintf({0x102d442f8, 0x14000010070}, {0x102d02798, 0xe}, {0x0, 0x0, 0x0})\n\t/usr/local/go/src/fmt/print.go:225 +0x84\nmain.main()\n\t/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/interface/empty/main.go:22 +0x54\nexit status 2", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "panic: runtime error: invalid memory address or nil pointer dereference\n[signal SIGSEGV: segmentation violation code=0x2 addr=0x18 pc=0x102d0116c]\n\ngoroutine 1 [running]:\nmain.(*Stream).Write(0x140000a45b0?, {0x1400000e160?, 0xe?, 0x0?})\n\t\u003cautogenerated\u003e:1 +0x2c\nfmt.Fprintf({0x102d442f8, 0x14000010070}, {0x102d02798, 0xe}, {0x0, 0x0, 0x0})\n\t/usr/local/go/src/fmt/print.go:225 +0x84\nmain.main()\n\t/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/interface/empty/main.go:22 +0x54\nexit status 2", + "stdout": "", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd data-go-version=\"go1.22.0\" exec=\"go run .\" exit=\"-1\" run=\".\" src=\"panic/src/interface/empty\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.36:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "A panic caused by a ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "nil", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " interface.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 36, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-36\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "panic/_dont.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "In ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-37" + }, + "filename": "panic/_dont.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "stream-fixed" + } + ], + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-37" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.37", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-37\"\u003e", + "type": "hype.Link", + "url": "#listing-1-37" + } + ], + "tag": "\u003cref id=\"listing-1-37\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ", we fix the code by properly assigning an implementation of an ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "io#Writer", + "href": "https://pkg.go.dev/io#Writer", + "target": "_blank" + }, + "filename": "panic/_dont.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "panic/_dont.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "io.Writer", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"io#Writer\" href=\"https://pkg.go.dev/io#Writer\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/io#Writer" + } + ], + { + "text": " interface, in this case ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "os#Stdout", + "href": "https://pkg.go.dev/os#Stdout", + "target": "_blank" + }, + "filename": "panic/_dont.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "panic/_dont.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "os.Stdout", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"os#Stdout\" href=\"https://pkg.go.dev/os#Stdout\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/os#Stdout" + } + ], + { + "text": " to the embedded ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "io#Writer", + "href": "https://pkg.go.dev/io#Writer", + "target": "_blank" + }, + "filename": "panic/_dont.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "panic/_dont.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "io.Writer", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"io#Writer\" href=\"https://pkg.go.dev/io#Writer\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/io#Writer" + } + ], + { + "text": " in the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "panic/_dont.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Stream", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " type.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-37", + "type": "listing" + }, + "filename": "panic/_dont.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "stream-fixed" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + { + "atom": "pre", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "src": "panic/src/interface/backed/main.go#example" + }, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/interface/backed/main.go#example" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "content": "func main() {\n\n\t// initialize a stream\n\t// with STDOUT as the writer\n\ts := Stream{\n\t\tWriter: os.Stdout,\n\t}\n\n\tfmt.Fprintf(s, \"Hello Gophers!\")\n}", + "file": "panic/src/interface/backed/main.go", + "lang": "go", + "name": "example", + "start": 13, + "end": 25 + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" src=\"panic/src/interface/backed/main.go#example\"\u003e", + "type": "hype.SourceCode" + } + ] + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + }, + { + "atom": "hr", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "hr", + "data_atom": "hr", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [], + "tag": "\u003chr\u003e", + "type": "hype.Element" + }, + [ + { + "args": [ + "go", + "run", + "." + ], + "atom": "cmd", + "attributes": { + "data-go-version": "go1.22.0", + "exec": "go run .", + "run": ".", + "src": "panic/src/interface/backed" + }, + "expected_exit": 0, + "filename": "panic", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "data-go-version", + "Val": "go1.22.0" + }, + { + "Namespace": "", + "Key": "exec", + "Val": "go run ." + }, + { + "Namespace": "", + "Key": "run", + "Val": "." + }, + { + "Namespace": "", + "Key": "src", + "Val": "src/interface/backed" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "run", + "." + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/interface/backed", + "duration": "1.882431042s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go run .\n\nHello Gophers!", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "Hello Gophers!", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "run", + "." + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/interface/backed", + "duration": "1.882431042s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go run .\n\nHello Gophers!", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "Hello Gophers!", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd data-go-version=\"go1.22.0\" exec=\"go run .\" run=\".\" src=\"panic/src/interface/backed\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.37:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "Properly assigning an implementation of an embedded ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "io#Writer", + "href": "https://pkg.go.dev/io#Writer", + "target": "_blank" + }, + "filename": "panic", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "for", + "Val": "io#Writer" + }, + { + "Namespace": "", + "Key": "href", + "Val": "https://pkg.go.dev/io#Writer" + }, + { + "Namespace": "", + "Key": "target", + "Val": "_blank" + } + ], + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "io.Writer", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ] + ], + "tag": "\u003ca for=\"io#Writer\" href=\"https://pkg.go.dev/io#Writer\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/io#Writer" + } + ], + { + "text": ".", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 37, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-37\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "h2", + "attributes": {}, + "filename": "panic/_dont.md", + "html_node": { + "data": "h2", + "data_atom": "h2", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "level": 2, + "nodes": [ + { + "text": "Functions", + "type": "hype.Text" + } + ], + "tag": "\u003ch2\u003e", + "type": "hype.Heading" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "panic/_dont.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "A function's zero value is ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "panic/_dont.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "nil", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": ". As such, a function needs to be assigned before using it. In ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-38" + }, + "filename": "panic/_dont.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "func/broken" + } + ], + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-38" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.38", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-38\"\u003e", + "type": "hype.Link", + "url": "#listing-1-38" + } + ], + "tag": "\u003cref id=\"listing-1-38\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ", we have created a function variable, ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "panic/_dont.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "fn", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": ", that is not backed by an actual function. This causes a panic when we try to call the function.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-38", + "type": "listing" + }, + "filename": "panic/_dont.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "func/broken" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + { + "atom": "pre", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "src": "panic/src/func/broken/main.go#example" + }, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/func/broken/main.go#example" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "content": "func main() {\n\n\t// create a new function\n\t// type variable\n\tvar fn func() string\n\n\t// print the results\n\t// of the function\n\tfmt.Println(fn())\n}", + "file": "panic/src/func/broken/main.go", + "lang": "go", + "name": "example", + "start": 7, + "end": 19 + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" src=\"panic/src/func/broken/main.go#example\"\u003e", + "type": "hype.SourceCode" + } + ] + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + }, + { + "atom": "hr", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "hr", + "data_atom": "hr", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [], + "tag": "\u003chr\u003e", + "type": "hype.Element" + }, + [ + { + "args": [ + "go", + "run", + "." + ], + "atom": "cmd", + "attributes": { + "data-go-version": "go1.22.0", + "exec": "go run .", + "exit": "-1", + "run": ".", + "src": "panic/src/func/broken" + }, + "expected_exit": -1, + "filename": "panic", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "data-go-version", + "Val": "go1.22.0" + }, + { + "Namespace": "", + "Key": "exec", + "Val": "go run ." + }, + { + "Namespace": "", + "Key": "exit", + "Val": "-1" + }, + { + "Namespace": "", + "Key": "run", + "Val": "." + }, + { + "Namespace": "", + "Key": "src", + "Val": "src/func/broken" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "run", + "." + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/func/broken", + "duration": "4.483027541s", + "err": "exit status 1", + "exit": 1, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go run .\n\npanic: runtime error: invalid memory address or nil pointer dereference\n[signal SIGSEGV: segmentation violation code=0x2 addr=0x0 pc=0x102754a9c]\n\ngoroutine 1 [running]:\nmain.main()\n\t/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/func/broken/main.go:16 +0x1c\nexit status 2", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "panic: runtime error: invalid memory address or nil pointer dereference\n[signal SIGSEGV: segmentation violation code=0x2 addr=0x0 pc=0x102754a9c]\n\ngoroutine 1 [running]:\nmain.main()\n\t/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/func/broken/main.go:16 +0x1c\nexit status 2", + "stdout": "", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "run", + "." + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/func/broken", + "duration": "4.483027541s", + "err": "exit status 1", + "exit": 1, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go run .\n\npanic: runtime error: invalid memory address or nil pointer dereference\n[signal SIGSEGV: segmentation violation code=0x2 addr=0x0 pc=0x102754a9c]\n\ngoroutine 1 [running]:\nmain.main()\n\t/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/func/broken/main.go:16 +0x1c\nexit status 2", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "panic: runtime error: invalid memory address or nil pointer dereference\n[signal SIGSEGV: segmentation violation code=0x2 addr=0x0 pc=0x102754a9c]\n\ngoroutine 1 [running]:\nmain.main()\n\t/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/func/broken/main.go:16 +0x1c\nexit status 2", + "stdout": "", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd data-go-version=\"go1.22.0\" exec=\"go run .\" exit=\"-1\" run=\".\" src=\"panic/src/func/broken\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.38:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "Using an uninitialized function variable.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 38, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-38\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "panic/_dont.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "In ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-39" + }, + "filename": "panic/_dont.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "func/fixed" + } + ], + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-39" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.39", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-39\"\u003e", + "type": "hype.Link", + "url": "#listing-1-39" + } + ], + "tag": "\u003cref id=\"listing-1-39\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ", we have assigned a function to the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "panic/_dont.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "fn", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " variable and the application runs successfully.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-39", + "type": "listing" + }, + "filename": "panic/_dont.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "func/fixed" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + { + "atom": "pre", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "src": "panic/src/func/fixed/main.go#example" + }, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/func/fixed/main.go#example" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "content": "func main() {\n\n\t// create a new function\n\t// type variable\n\tvar fn func() string\n\n\t// back the fn variable\n\t// with a function\n\tfn = func() string {\n\t\treturn \"Hello, World!\"\n\t}\n\n\t// print the results\n\t// of the function\n\tfmt.Println(fn())\n}", + "file": "panic/src/func/fixed/main.go", + "lang": "go", + "name": "example", + "start": 7, + "end": 25 + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" src=\"panic/src/func/fixed/main.go#example\"\u003e", + "type": "hype.SourceCode" + } + ] + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + }, + { + "atom": "hr", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "hr", + "data_atom": "hr", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [], + "tag": "\u003chr\u003e", + "type": "hype.Element" + }, + [ + { + "args": [ + "go", + "run", + "." + ], + "atom": "cmd", + "attributes": { + "data-go-version": "go1.22.0", + "exec": "go run .", + "run": ".", + "src": "panic/src/func/fixed" + }, + "expected_exit": 0, + "filename": "panic", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "data-go-version", + "Val": "go1.22.0" + }, + { + "Namespace": "", + "Key": "exec", + "Val": "go run ." + }, + { + "Namespace": "", + "Key": "run", + "Val": "." + }, + { + "Namespace": "", + "Key": "src", + "Val": "src/func/fixed" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "run", + "." + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/func/fixed", + "duration": "3.291095792s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go run .\n\nHello, World!", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "Hello, World!", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "run", + "." + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/func/fixed", + "duration": "3.291095792s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go run .\n\nHello, World!", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "Hello, World!", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd data-go-version=\"go1.22.0\" exec=\"go run .\" run=\".\" src=\"panic/src/func/fixed\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.39:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "Assigning a function definition to the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "fn", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " variable.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 39, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-39\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "h2", + "attributes": {}, + "filename": "panic/_dont.md", + "html_node": { + "data": "h2", + "data_atom": "h2", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "level": 2, + "nodes": [ + { + "text": "Type Assertions", + "type": "hype.Text" + } + ], + "tag": "\u003ch2\u003e", + "type": "hype.Heading" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "panic/_dont.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "When type asserting in Go, if the interface being asserted against fails, Go will panic as a result.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-40", + "type": "listing" + }, + "filename": "panic/_dont.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "assert/write" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + { + "atom": "pre", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "src": "panic/src/assert/broken/main.go#write" + }, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/assert/broken/main.go#write" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "content": "func WriteToFile(w io.Writer, data []byte) error {\n\n\t// assert that w is a file\n\tf := w.(*os.File)\n\n\t// defer closing the file\n\tdefer f.Close()\n\n\t// log the file name\n\tfmt.Printf(\"writing to file %s\\n\", f.Name())\n\n\t// write the data\n\t_, err := f.Write(data)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}", + "file": "panic/src/assert/broken/main.go", + "lang": "go", + "name": "write", + "start": 34, + "end": 55 + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" src=\"panic/src/assert/broken/main.go#write\"\u003e", + "type": "hype.SourceCode" + } + ] + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + }, + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.40:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "Panic caused by a failed type assertion.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 40, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-40\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "panic/_dont.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Consider the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "panic/_dont.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "WriteToFile(io.Writer, []byte)", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " function defined in ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-40" + }, + "filename": "panic/_dont.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "assert/write" + } + ], + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-40" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.40", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-40\"\u003e", + "type": "hype.Link", + "url": "#listing-1-40" + } + ], + "tag": "\u003cref id=\"listing-1-40\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ". This function takes an ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "io#Writer", + "href": "https://pkg.go.dev/io#Writer", + "target": "_blank" + }, + "filename": "panic/_dont.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "panic/_dont.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "io.Writer", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"io#Writer\" href=\"https://pkg.go.dev/io#Writer\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/io#Writer" + } + ], + { + "text": " as an argument, along with a ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "panic/_dont.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "[]byte", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " slice of data to write. Inside of the function, the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "io#Writer", + "href": "https://pkg.go.dev/io#Writer", + "target": "_blank" + }, + "filename": "panic/_dont.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "panic/_dont.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "io.Writer", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"io#Writer\" href=\"https://pkg.go.dev/io#Writer\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/io#Writer" + } + ], + { + "text": " argument, ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "panic/_dont.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "w", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": ", is being type asserted to the concrete type ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "os#File", + "href": "https://pkg.go.dev/os#File", + "target": "_blank" + }, + "filename": "panic/_dont.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "panic/_dont.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "os.File", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"os#File\" href=\"https://pkg.go.dev/os#File\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/os#File" + } + ], + { + "text": ". In ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-41" + }, + "filename": "panic/_dont.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "assert/broken" + } + ], + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-41" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.41", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-41\"\u003e", + "type": "hype.Link", + "url": "#listing-1-41" + } + ], + "tag": "\u003cref id=\"listing-1-41\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ", we are calling this function with a ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "bytes#Buffer", + "href": "https://pkg.go.dev/bytes#Buffer", + "target": "_blank" + }, + "filename": "panic/_dont.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "panic/_dont.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "bytes.Buffer", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"bytes#Buffer\" href=\"https://pkg.go.dev/bytes#Buffer\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/bytes#Buffer" + } + ], + { + "text": " as the first argument, which is not an instance of ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "os#File", + "href": "https://pkg.go.dev/os#File", + "target": "_blank" + }, + "filename": "panic/_dont.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "panic/_dont.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "os.File", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"os#File\" href=\"https://pkg.go.dev/os#File\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/os#File" + } + ], + { + "text": ". This causes a panic.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-41", + "type": "listing" + }, + "filename": "panic/_dont.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "assert/broken" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + { + "atom": "pre", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "src": "panic/src/assert/broken/main.go#example" + }, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/assert/broken/main.go#example" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "content": "func main() {\n\n\t// create a buffer\n\t// to write to\n\tbb := \u0026bytes.Buffer{}\n\n\t// data to be written\n\tdata := []byte(\"Hello, world!\")\n\n\t// call WriteToFile\n\t// passing the buffer\n\t// and the data\n\terr := WriteToFile(bb, data)\n\n\t// check for errors\n\tif err != nil {\n\t\tfmt.Println(err)\n\t\tos.Exit(1)\n\t}\n}", + "file": "panic/src/assert/broken/main.go", + "lang": "go", + "name": "example", + "start": 10, + "end": 32 + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" src=\"panic/src/assert/broken/main.go#example\"\u003e", + "type": "hype.SourceCode" + } + ] + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + }, + { + "atom": "hr", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "hr", + "data_atom": "hr", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [], + "tag": "\u003chr\u003e", + "type": "hype.Element" + }, + [ + { + "args": [ + "go", + "run", + "." + ], + "atom": "cmd", + "attributes": { + "data-go-version": "go1.22.0", + "exec": "go run .", + "exit": "-1", + "run": ".", + "src": "panic/src/assert/broken" + }, + "expected_exit": -1, + "filename": "panic", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "data-go-version", + "Val": "go1.22.0" + }, + { + "Namespace": "", + "Key": "exec", + "Val": "go run ." + }, + { + "Namespace": "", + "Key": "exit", + "Val": "-1" + }, + { + "Namespace": "", + "Key": "run", + "Val": "." + }, + { + "Namespace": "", + "Key": "src", + "Val": "src/assert/broken" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "run", + "." + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/assert/broken", + "duration": "1.495222s", + "err": "exit status 1", + "exit": 1, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go run .\n\npanic: interface conversion: io.Writer is *bytes.Buffer, not *os.File\n\ngoroutine 1 [running]:\nmain.WriteToFile({0x102aec8f8?, 0x14000104f10?}, {0x14000104ef3?, 0x102a50a48?, 0x0?})\n\t/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/assert/broken/main.go:38 +0x150\nmain.main()\n\t/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/assert/broken/main.go:23 +0x68\nexit status 2", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "panic: interface conversion: io.Writer is *bytes.Buffer, not *os.File\n\ngoroutine 1 [running]:\nmain.WriteToFile({0x102aec8f8?, 0x14000104f10?}, {0x14000104ef3?, 0x102a50a48?, 0x0?})\n\t/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/assert/broken/main.go:38 +0x150\nmain.main()\n\t/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/assert/broken/main.go:23 +0x68\nexit status 2", + "stdout": "", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "run", + "." + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/assert/broken", + "duration": "1.495222s", + "err": "exit status 1", + "exit": 1, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go run .\n\npanic: interface conversion: io.Writer is *bytes.Buffer, not *os.File\n\ngoroutine 1 [running]:\nmain.WriteToFile({0x102aec8f8?, 0x14000104f10?}, {0x14000104ef3?, 0x102a50a48?, 0x0?})\n\t/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/assert/broken/main.go:38 +0x150\nmain.main()\n\t/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/assert/broken/main.go:23 +0x68\nexit status 2", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "panic: interface conversion: io.Writer is *bytes.Buffer, not *os.File\n\ngoroutine 1 [running]:\nmain.WriteToFile({0x102aec8f8?, 0x14000104f10?}, {0x14000104ef3?, 0x102a50a48?, 0x0?})\n\t/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/assert/broken/main.go:38 +0x150\nmain.main()\n\t/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/assert/broken/main.go:23 +0x68\nexit status 2", + "stdout": "", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd data-go-version=\"go1.22.0\" exec=\"go run .\" exit=\"-1\" run=\".\" src=\"panic/src/assert/broken\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.41:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "Panic caused by a failed type assertion.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 41, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-41\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "panic/_dont.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "If asked, Go, will return a second argument, a boolean, during the assertion. That boolean will be ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "panic/_dont.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "true", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " if the assertion was successful and ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "panic/_dont.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "false", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " if it wasn't. Checking this second argument will prevent panics on type assertion failures and keep your application up and running.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-42", + "type": "listing" + }, + "filename": "panic/_dont.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "assert/fixed" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + { + "atom": "pre", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "src": "panic/src/assert/fixed/main.go#write" + }, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/assert/fixed/main.go#write" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "content": "func WriteToFile(w io.Writer, data []byte) error {\n\n\t// assert that w is a file\n\tf, ok := w.(*os.File)\n\n\t// check the assertion was successful\n\tif !ok {\n\t\treturn fmt.Errorf(\"expected *os.File, got %T\", w)\n\t}\n\n\t// defer closing the file\n\tdefer f.Close()\n\n\t// log the file name\n\tfmt.Printf(\"writing to file %s\\n\", f.Name())\n\n\t// write the data\n\t_, err := f.Write(data)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}", + "file": "panic/src/assert/fixed/main.go", + "lang": "go", + "name": "write", + "start": 34, + "end": 60 + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" src=\"panic/src/assert/fixed/main.go#write\"\u003e", + "type": "hype.SourceCode" + } + ] + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + }, + { + "atom": "hr", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "hr", + "data_atom": "hr", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [], + "tag": "\u003chr\u003e", + "type": "hype.Element" + }, + [ + { + "args": [ + "go", + "run", + "." + ], + "atom": "cmd", + "attributes": { + "data-go-version": "go1.22.0", + "exec": "go run .", + "exit": "-1", + "run": ".", + "src": "panic/src/assert/fixed" + }, + "expected_exit": -1, + "filename": "panic", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "data-go-version", + "Val": "go1.22.0" + }, + { + "Namespace": "", + "Key": "exec", + "Val": "go run ." + }, + { + "Namespace": "", + "Key": "exit", + "Val": "-1" + }, + { + "Namespace": "", + "Key": "run", + "Val": "." + }, + { + "Namespace": "", + "Key": "src", + "Val": "src/assert/fixed" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "run", + "." + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/assert/fixed", + "duration": "2.48187425s", + "err": "exit status 1", + "exit": 1, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go run .\n\nexpected *os.File, got *bytes.Buffer\n\nexit status 1", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "exit status 1", + "stdout": "expected *os.File, got *bytes.Buffer", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "run", + "." + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/assert/fixed", + "duration": "2.48187425s", + "err": "exit status 1", + "exit": 1, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go run .\n\nexpected *os.File, got *bytes.Buffer\n\nexit status 1", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "exit status 1", + "stdout": "expected *os.File, got *bytes.Buffer", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd data-go-version=\"go1.22.0\" exec=\"go run .\" exit=\"-1\" run=\".\" src=\"panic/src/assert/fixed\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.42:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "Proper type assertion checking prevents panics.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 42, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-42\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + { + "atom": "blockquote", + "attributes": {}, + "filename": "panic/_dont.md", + "html_node": { + "data": "blockquote", + "data_atom": "blockquote", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "panic/_dont.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Note: It is very important that a type check is not avoided. In virtually all cases, avoiding a type check will lead to a future bug in your code.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "tag": "\u003cblockquote\u003e", + "type": "hype.Element" + }, + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "h2", + "attributes": {}, + "filename": "panic/_dont.md", + "html_node": { + "data": "h2", + "data_atom": "h2", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "level": 2, + "nodes": [ + { + "text": "Array/Slice Indexes", + "type": "hype.Text" + } + ], + "tag": "\u003ch2\u003e", + "type": "hype.Heading" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "panic/_dont.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "When accessing indexes on slices and arrays if the index is greater than the length of the slice/array Go will panic.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-43", + "type": "listing" + }, + "filename": "panic/_dont.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "slices/find" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + { + "atom": "pre", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "src": "panic/src/slices/broken/main.go#find" + }, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/slices/broken/main.go#find" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "content": "func find(names []string, index int) (string, error) {\n\n\t// find the name at the index\n\ts := names[index]\n\n\t// return an error if the value is empty\n\tif len(s) == 0 {\n\t\treturn s, fmt.Errorf(\"index %d empty\", index)\n\t}\n\n\t// return the name\n\treturn s, nil\n}", + "file": "panic/src/slices/broken/main.go", + "lang": "go", + "name": "find", + "start": 29, + "end": 44 + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" src=\"panic/src/slices/broken/main.go#find\"\u003e", + "type": "hype.SourceCode" + } + ] + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + }, + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.43:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "A function for retrieving the index of a slice.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 43, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-43\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "panic/_dont.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Consider the function defined in ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-43" + }, + "filename": "panic/_dont.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "slices/find" + } + ], + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-43" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.43", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-43\"\u003e", + "type": "hype.Link", + "url": "#listing-1-43" + } + ], + "tag": "\u003cref id=\"listing-1-43\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ". This function attempts to access the given index of the given slice. If the index is greater than the length of the slice, Go will panic, ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-44" + }, + "filename": "panic/_dont.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "slices/broken" + } + ], + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-44" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.44", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-44\"\u003e", + "type": "hype.Link", + "url": "#listing-1-44" + } + ], + "tag": "\u003cref id=\"listing-1-44\"\u003e", + "type": "hype.Ref" + } + ] + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-44", + "type": "listing" + }, + "filename": "panic/_dont.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "slices/broken" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + { + "atom": "pre", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "src": "panic/src/slices/broken/main.go#example" + }, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/slices/broken/main.go#example" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "content": "func main() {\n\n\t// create a slice\n\tnames := []string{\"Kurt\", \"Janis\", \"Jimi\", \"Amy\"}\n\n\t// find index 42\n\ts, err := find(names, 42)\n\n\t// check for errors\n\tif err != nil {\n\t\tfmt.Println(err)\n\t\tos.Exit(1)\n\t}\n\n\t// print the result\n\tfmt.Println(\"found: \", s)\n}", + "file": "panic/src/slices/broken/main.go", + "lang": "go", + "name": "example", + "start": 8, + "end": 27 + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" src=\"panic/src/slices/broken/main.go#example\"\u003e", + "type": "hype.SourceCode" + } + ] + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + }, + { + "atom": "hr", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "hr", + "data_atom": "hr", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [], + "tag": "\u003chr\u003e", + "type": "hype.Element" + }, + [ + { + "args": [ + "go", + "run", + "." + ], + "atom": "cmd", + "attributes": { + "data-go-version": "go1.22.0", + "exec": "go run .", + "exit": "-1", + "run": ".", + "src": "panic/src/slices/broken" + }, + "expected_exit": -1, + "filename": "panic", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "data-go-version", + "Val": "go1.22.0" + }, + { + "Namespace": "", + "Key": "exec", + "Val": "go run ." + }, + { + "Namespace": "", + "Key": "exit", + "Val": "-1" + }, + { + "Namespace": "", + "Key": "run", + "Val": "." + }, + { + "Namespace": "", + "Key": "src", + "Val": "src/slices/broken" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "run", + "." + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/slices/broken", + "duration": "2.209293667s", + "err": "exit status 1", + "exit": 1, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go run .\n\npanic: runtime error: index out of range [42] with length 4\n\ngoroutine 1 [running]:\nmain.find({0x14000112ef8?, 0x1020b2834?, 0x100000000000010?}, 0x0?)\n\t/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/slices/broken/main.go:33 +0xb0\nmain.main()\n\t/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/slices/broken/main.go:15 +0x88\nexit status 2", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "panic: runtime error: index out of range [42] with length 4\n\ngoroutine 1 [running]:\nmain.find({0x14000112ef8?, 0x1020b2834?, 0x100000000000010?}, 0x0?)\n\t/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/slices/broken/main.go:33 +0xb0\nmain.main()\n\t/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/slices/broken/main.go:15 +0x88\nexit status 2", + "stdout": "", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "run", + "." + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/slices/broken", + "duration": "2.209293667s", + "err": "exit status 1", + "exit": 1, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go run .\n\npanic: runtime error: index out of range [42] with length 4\n\ngoroutine 1 [running]:\nmain.find({0x14000112ef8?, 0x1020b2834?, 0x100000000000010?}, 0x0?)\n\t/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/slices/broken/main.go:33 +0xb0\nmain.main()\n\t/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/slices/broken/main.go:15 +0x88\nexit status 2", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "panic: runtime error: index out of range [42] with length 4\n\ngoroutine 1 [running]:\nmain.find({0x14000112ef8?, 0x1020b2834?, 0x100000000000010?}, 0x0?)\n\t/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/slices/broken/main.go:33 +0xb0\nmain.main()\n\t/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/slices/broken/main.go:15 +0x88\nexit status 2", + "stdout": "", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd data-go-version=\"go1.22.0\" exec=\"go run .\" exit=\"-1\" run=\".\" src=\"panic/src/slices/broken\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.44:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "An out of bounds panic.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 44, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-44\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "panic/_dont.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "To avoid this panic, check the length of slice/array to ensure the requested index can safely be retrieved. In ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-45" + }, + "filename": "panic/_dont.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "slices/fixed" + } + ], + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-45" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.45", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-45\"\u003e", + "type": "hype.Link", + "url": "#listing-1-45" + } + ], + "tag": "\u003cref id=\"listing-1-45\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ", the index is checked against the length of the slice/array before being accessed. If the index is greater than the length of the slice/array, the function will return an ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "builtin#error", + "href": "https://pkg.go.dev/builtin#error", + "target": "_blank" + }, + "filename": "panic/_dont.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "panic/_dont.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "error", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"builtin#error\" href=\"https://pkg.go.dev/builtin#error\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/builtin#error" + } + ], + { + "text": " instead of panicking.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-45", + "type": "listing" + }, + "filename": "panic/_dont.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "slices/fixed" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + { + "atom": "pre", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "src": "panic/src/slices/fixed/main.go#find" + }, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/slices/fixed/main.go#find" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "content": "func find(names []string, index int) (string, error) {\n\n\t// check for out of bounds index\n\tif index \u003e= len(names) {\n\t\treturn \"\", fmt.Errorf(\"out of bounds index %d [%d]\", index, len(names))\n\t}\n\n\t// find the name at the index\n\ts := names[index]\n\n\t// return an error if the value is empty\n\tif len(s) == 0 {\n\t\treturn s, fmt.Errorf(\"index %d empty\", index)\n\t}\n\n\t// return the name\n\treturn s, nil\n}", + "file": "panic/src/slices/fixed/main.go", + "lang": "go", + "name": "find", + "start": 29, + "end": 49 + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" src=\"panic/src/slices/fixed/main.go#find\"\u003e", + "type": "hype.SourceCode" + } + ] + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + }, + { + "atom": "hr", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "hr", + "data_atom": "hr", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [], + "tag": "\u003chr\u003e", + "type": "hype.Element" + }, + [ + { + "args": [ + "go", + "run", + "." + ], + "atom": "cmd", + "attributes": { + "data-go-version": "go1.22.0", + "exec": "go run .", + "exit": "-1", + "run": ".", + "src": "panic/src/slices/fixed" + }, + "expected_exit": -1, + "filename": "panic", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "data-go-version", + "Val": "go1.22.0" + }, + { + "Namespace": "", + "Key": "exec", + "Val": "go run ." + }, + { + "Namespace": "", + "Key": "exit", + "Val": "-1" + }, + { + "Namespace": "", + "Key": "run", + "Val": "." + }, + { + "Namespace": "", + "Key": "src", + "Val": "src/slices/fixed" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "run", + "." + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/slices/fixed", + "duration": "3.344031666s", + "err": "exit status 1", + "exit": 1, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go run .\n\nout of bounds index 42 [4]\n\nexit status 1", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "exit status 1", + "stdout": "out of bounds index 42 [4]", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "run", + "." + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/slices/fixed", + "duration": "3.344031666s", + "err": "exit status 1", + "exit": 1, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go run .\n\nout of bounds index 42 [4]\n\nexit status 1", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "exit status 1", + "stdout": "out of bounds index 42 [4]", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd data-go-version=\"go1.22.0\" exec=\"go run .\" exit=\"-1\" run=\".\" src=\"panic/src/slices/fixed\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "panic", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.45:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "Proper type assertion checking prevents panics.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 45, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-45\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "tag": "\u003cpage\u003e", + "title": "Don't Panic", + "type": "hype.Page" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "tag": "\u003cinclude src=\"panic/_dont.md\"\u003e", + "type": "hype.Include" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "tag": "\u003cinclude src=\"panic/panic.md\"\u003e", + "type": "hype.Include" + } + ], + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "atom": "include", + "attributes": { + "src": "errors/custom.md" + }, + "dir": "errors", + "filename": "module.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "errors/custom.md" + } + ], + "data": "include", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "page", + "attributes": {}, + "filename": "errors/custom.md", + "html_node": { + "data": "page", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "atom": "h1", + "attributes": {}, + "filename": "errors/custom.md", + "html_node": { + "data": "h1", + "data_atom": "h1", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "level": 1, + "nodes": [ + { + "text": "Custom Errors", + "type": "hype.Text" + } + ], + "tag": "\u003ch1\u003e", + "type": "hype.Heading" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "errors/custom.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "As we have seen, errors in Go are implemented via the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "builtin#error", + "href": "https://pkg.go.dev/builtin#error", + "target": "_blank" + }, + "filename": "errors/custom.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/custom.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "error", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"builtin#error\" href=\"https://pkg.go.dev/builtin#error\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/builtin#error" + } + ], + { + "text": " interface, ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-46" + }, + "filename": "errors/custom.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "error.doc" + } + ], + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-46" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.46", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-46\"\u003e", + "type": "hype.Link", + "url": "#listing-1-46" + } + ], + "tag": "\u003cref id=\"listing-1-46\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ". This means we can create our own custom error implementations. Custom errors allow us to manage workflow and provide detailed information about an error beyond the scope of the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "builtin#error", + "href": "https://pkg.go.dev/builtin#error", + "target": "_blank" + }, + "filename": "errors/custom.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/custom.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "error", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"builtin#error\" href=\"https://pkg.go.dev/builtin#error\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/builtin#error" + } + ], + { + "text": " interface.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-46", + "type": "listing" + }, + "filename": "errors/custom.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "error.doc" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "args": [ + "go", + "doc", + "builtin.error" + ], + "atom": "cmd", + "attributes": { + "data-go-version": "go1.22.0", + "doc": "builtin.error", + "exec": "go doc builtin.error" + }, + "expected_exit": 0, + "filename": "errors", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "data-go-version", + "Val": "go1.22.0" + }, + { + "Namespace": "", + "Key": "doc", + "Val": "builtin.error" + }, + { + "Namespace": "", + "Key": "exec", + "Val": "go doc builtin.error" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "doc", + "builtin.error" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypejs", + "duration": "2.039163667s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go doc builtin.error\n\npackage builtin // import \u0026#34;builtin\u0026#34;\n\ntype error interface {\n\tError() string\n}\n The error built-in interface type is the conventional interface for\n representing an error condition, with the nil value representing no error.", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "package builtin // import \"builtin\"\n\ntype error interface {\n\tError() string\n}\n The error built-in interface type is the conventional interface for\n representing an error condition, with the nil value representing no error.", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "doc", + "builtin.error" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypejs", + "duration": "2.039163667s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go doc builtin.error\n\npackage builtin // import \u0026#34;builtin\u0026#34;\n\ntype error interface {\n\tError() string\n}\n The error built-in interface type is the conventional interface for\n representing an error condition, with the nil value representing no error.", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "package builtin // import \"builtin\"\n\ntype error interface {\n\tError() string\n}\n The error built-in interface type is the conventional interface for\n representing an error condition, with the nil value representing no error.", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd data-go-version=\"go1.22.0\" doc=\"builtin.error\" exec=\"go doc builtin.error\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.46:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "The ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "builtin#error", + "href": "https://pkg.go.dev/builtin#error", + "target": "_blank" + }, + "filename": "errors", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "for", + "Val": "builtin#error" + }, + { + "Namespace": "", + "Key": "href", + "Val": "https://pkg.go.dev/builtin#error" + }, + { + "Namespace": "", + "Key": "target", + "Val": "_blank" + } + ], + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "error", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ] + ], + "tag": "\u003ca for=\"builtin#error\" href=\"https://pkg.go.dev/builtin#error\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/builtin#error" + } + ], + { + "text": " interface.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 46, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-46\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "h2", + "attributes": {}, + "filename": "errors/custom.md", + "html_node": { + "data": "h2", + "data_atom": "h2", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "level": 2, + "nodes": [ + { + "text": "Standard Errors", + "type": "hype.Text" + } + ], + "tag": "\u003ch2\u003e", + "type": "hype.Heading" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "errors/custom.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Let's consider ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-47" + }, + "filename": "errors/custom.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "store.type" + } + ], + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-47" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.47", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-47\"\u003e", + "type": "hype.Link", + "url": "#listing-1-47" + } + ], + "tag": "\u003cref id=\"listing-1-47\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ". A couple of types are being defined. The first, ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/custom.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Model", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": ", is based on ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/custom.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "map[string]any", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": ". For example, ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/custom.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "{\"age\": 27, \"name\": \"jimi\"}", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": ". Next, a ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/custom.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Store", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " struct type is defined with a ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/custom.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "data", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " field of type ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/custom.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "map[string][]Model", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": ". This ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/custom.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "data", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " field is a map of table names to their models.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-47", + "type": "listing" + }, + "filename": "errors/custom.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "store.type" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + { + "atom": "pre", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "src": "errors/src/custom/store.go#store" + }, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/custom/store.go#store" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "content": "// Model is a key/value pair representing a model in the store.\n// e.g. {\"id\": 1, \"name\": \"bob\"}\ntype Model map[string]any\n\n// Store is a table based key/value store.\ntype Store struct {\n\tdata map[string][]Model\n}", + "file": "errors/src/custom/store.go", + "lang": "go", + "name": "store", + "start": 5, + "end": 16 + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" src=\"errors/src/custom/store.go#store\"\u003e", + "type": "hype.SourceCode" + } + ] + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + }, + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.47:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "Type definitions.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 47, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-47\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "errors/custom.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "The ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/custom.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Store", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " has a method, ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/custom.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "All(string)", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": ", that will return all of the models in the store for the given table. If the table doesn't exist an error will be returned. This error is created using the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "fmt#Errorf", + "href": "https://pkg.go.dev/fmt#Errorf", + "target": "_blank" + }, + "filename": "errors/custom.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/custom.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "fmt.Errorf", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"fmt#Errorf\" href=\"https://pkg.go.dev/fmt#Errorf\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/fmt#Errorf" + } + ], + { + "text": " function.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-48", + "type": "listing" + }, + "filename": "errors/custom.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "store.all" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + { + "atom": "pre", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "src": "errors/src/custom/store.go#all" + }, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/custom/store.go#all" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "content": "// All returns all models in the store for the given table name.\n// If no models exist, an error is returned.\nfunc (s *Store) All(tn string) ([]Model, error) {\n\tdb := s.data\n\n\t// if the underlying data is nil, return an error\n\tif db == nil {\n\t\treturn nil, fmt.Errorf(\"no data\")\n\t}\n\n\t// check to make sure table exists\n\tmods, ok := db[tn]\n\n\t// if table doesn't exist, return an error\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"table %s not found\", tn)\n\t}\n\n\t// return the slice of models\n\treturn mods, nil\n}", + "file": "errors/src/custom/store.go", + "lang": "go", + "name": "all", + "start": 18, + "end": 41 + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" src=\"errors/src/custom/store.go#all\"\u003e", + "type": "hype.SourceCode" + } + ] + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + }, + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.48:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "The ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Store.All", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " method.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 48, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-48\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "errors/custom.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-49" + }, + "filename": "errors/custom.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "store.all.test" + } + ], + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-49" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.49", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-49\"\u003e", + "type": "hype.Link", + "url": "#listing-1-49" + } + ], + "tag": "\u003cref id=\"listing-1-49\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": " is a test that asserts that if a given table doesn't exist in the store. This test, however, is lacking. Yes it asserts that an error was returned, but we don't know which error was returned. Did the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/custom.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "All", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " method return an error because the table didn't exist or because the underlying ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/custom.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "data", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " map was ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/custom.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "nil", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": "?", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-49", + "type": "listing" + }, + "filename": "errors/custom.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "store.all.test" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + { + "atom": "pre", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "src": "errors/src/custom/store_test.go#test" + }, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/custom/store_test.go#test" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "content": "func Test_Store_All_NoTable(t *testing.T) {\n\tt.Parallel()\n\n\ts := \u0026Store{\n\t\tdata: map[string][]Model{},\n\t}\n\n\t_, err := s.All(\"users\")\n\tif err == nil {\n\t\tt.Fatal(\"expected error, got nil\")\n\t}\n\n\texp := \"table users not found\"\n\tact := err.Error()\n\tif act != exp {\n\t\tt.Fatalf(\"expected %q, got %q\", exp, act)\n\t}\n}", + "file": "errors/src/custom/store_test.go", + "lang": "go", + "name": "test", + "start": 5, + "end": 27 + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" src=\"errors/src/custom/store_test.go#test\"\u003e", + "type": "hype.SourceCode" + } + ] + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + }, + { + "atom": "hr", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "hr", + "data_atom": "hr", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [], + "tag": "\u003chr\u003e", + "type": "hype.Element" + }, + [ + { + "args": [ + "go", + "test", + "-v" + ], + "atom": "cmd", + "attributes": { + "data-go-version": "go1.22.0", + "exec": "go test -v", + "src": "errors/src/custom", + "test": "-v" + }, + "expected_exit": 0, + "filename": "errors", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "data-go-version", + "Val": "go1.22.0" + }, + { + "Namespace": "", + "Key": "exec", + "Val": "go test -v" + }, + { + "Namespace": "", + "Key": "src", + "Val": "src/custom" + }, + { + "Namespace": "", + "Key": "test", + "Val": "-v" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "test", + "-v" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/09-errors/errors/src/custom", + "duration": "4.918560042s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go test -v\n\n=== RUN Test_Store_All_NoTable\n=== PAUSE Test_Store_All_NoTable\n=== CONT Test_Store_All_NoTable\n--- PASS: Test_Store_All_NoTable (0.00s)\nPASS\nok \tdemo\t2.839s", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "=== RUN Test_Store_All_NoTable\n=== PAUSE Test_Store_All_NoTable\n=== CONT Test_Store_All_NoTable\n--- PASS: Test_Store_All_NoTable (0.00s)\nPASS\nok \tdemo\t2.839s", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "test", + "-v" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/09-errors/errors/src/custom", + "duration": "4.918560042s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go test -v\n\n=== RUN Test_Store_All_NoTable\n=== PAUSE Test_Store_All_NoTable\n=== CONT Test_Store_All_NoTable\n--- PASS: Test_Store_All_NoTable (0.00s)\nPASS\nok \tdemo\t2.839s", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "=== RUN Test_Store_All_NoTable\n=== PAUSE Test_Store_All_NoTable\n=== CONT Test_Store_All_NoTable\n--- PASS: Test_Store_All_NoTable (0.00s)\nPASS\nok \tdemo\t2.839s", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd data-go-version=\"go1.22.0\" exec=\"go test -v\" src=\"errors/src/custom\" test=\"-v\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.49:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "A test for the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Store.All", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " method.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 49, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-49\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "errors/custom.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Like in, ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-49" + }, + "filename": "errors/custom.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "store.all.test" + } + ], + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-49" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.49", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-49\"\u003e", + "type": "hype.Link", + "url": "#listing-1-49" + } + ], + "tag": "\u003cref id=\"listing-1-49\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ", it might be tempting to assert against an error's message, but that is considered non-idiomatic and should never be used. The reason for this is simple; error messages change. If the error message changes the following test will fail. We consider this to be a \"brittle\" test.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "h2", + "attributes": {}, + "filename": "errors/custom.md", + "html_node": { + "data": "h2", + "data_atom": "h2", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "level": 2, + "nodes": [ + { + "text": "Defining Custom Errors", + "type": "hype.Text" + } + ], + "tag": "\u003ch2\u003e", + "type": "hype.Heading" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "errors/custom.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "We can define custom errors that can help distinguish one error from another, as well as, add more context around the error.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "errors/custom.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "In ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-50" + }, + "filename": "errors/custom.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "error.type" + } + ], + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-50" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.50", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-50\"\u003e", + "type": "hype.Link", + "url": "#listing-1-50" + } + ], + "tag": "\u003cref id=\"listing-1-50\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": " we define a new ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/custom.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "struct", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " type, ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/custom.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "ErrTableNotFound", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": ", that will implement the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "builtin#error", + "href": "https://pkg.go.dev/builtin#error", + "target": "_blank" + }, + "filename": "errors/custom.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/custom.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "error", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"builtin#error\" href=\"https://pkg.go.dev/builtin#error\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/builtin#error" + } + ], + { + "text": " interface. This type will contain information such as what table was missing and what time the error occurred.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-50", + "type": "listing" + }, + "filename": "errors/custom.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "error.type" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + { + "atom": "pre", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "src": "errors/src/custom-table-err/errors.go#err-table-not-found" + }, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/custom-table-err/errors.go#err-table-not-found" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "content": "type ErrTableNotFound struct {\n\tTable string\n\tOccurredAt time.Time\n}\n\nfunc (e ErrTableNotFound) Error() string {\n\treturn fmt.Sprintf(\"[%s] table not found %s\", e.OccurredAt, e.Table)\n}", + "file": "errors/src/custom-table-err/errors.go", + "lang": "go", + "name": "err-table-not-found", + "start": 8, + "end": 18 + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" src=\"errors/src/custom-table-err/errors.go#err-table-not-found\"\u003e", + "type": "hype.SourceCode" + } + ] + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + }, + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.50:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "The ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "ErrTableNotFound", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " struct.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 50, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-50\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "errors/custom.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-51" + }, + "filename": "errors/custom.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "store.all.err" + } + ], + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-51" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.51", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-51\"\u003e", + "type": "hype.Link", + "url": "#listing-1-51" + } + ], + "tag": "\u003cref id=\"listing-1-51\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": " updates the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/custom.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Store.All(string)", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": ", method to now return an ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/custom.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "ErrTableNotFound", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " error if the table doesn't exist. We also set the table name and the time the error occurred.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-51", + "type": "listing" + }, + "filename": "errors/custom.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "store.all.err" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + { + "atom": "pre", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "src": "errors/src/custom-table-err/store.go#all" + }, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/custom-table-err/store.go#all" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "content": "// All returns all models in the store for the given table name.\n// If no models exist, an error is returned.\nfunc (s *Store) All(tn string) ([]Model, error) {\n\tdb := s.data\n\n\t// if the underlying data is nil, return an error\n\tif db == nil {\n\t\treturn nil, fmt.Errorf(\"no data\")\n\t}\n\n\t// check to make sure table exists\n\tmods, ok := db[tn]\n\n\t// if table doesn't exist, return an error\n\tif !ok {\n\t\treturn nil, ErrTableNotFound{\n\t\t\tTable: tn,\n\t\t\tOccurredAt: time.Now(),\n\t\t}\n\t}\n\n\t// return the slice of models\n\treturn mods, nil\n}", + "file": "errors/src/custom-table-err/store.go", + "lang": "go", + "name": "all", + "start": 21, + "end": 47 + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" src=\"errors/src/custom-table-err/store.go#all\"\u003e", + "type": "hype.SourceCode" + } + ] + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + }, + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.51:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "The ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Store.All", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " method with custom errors.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 51, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-51\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "errors/custom.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "The test can now be updated, ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-52" + }, + "filename": "errors/custom.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "store.all.err.test" + } + ], + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-52" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.52", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-52\"\u003e", + "type": "hype.Link", + "url": "#listing-1-52" + } + ], + "tag": "\u003cref id=\"listing-1-52\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ", to assert that the error is an ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/custom.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "ErrTableNotFound", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " error. The test passes and we can see the table name and the time the error occurred.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-52", + "type": "listing" + }, + "filename": "errors/custom.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "store.all.err.test" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + { + "atom": "pre", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "src": "errors/src/custom-table-err/store_test.go#test" + }, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/custom-table-err/store_test.go#test" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "content": "func Test_Store_All_NoTable(t *testing.T) {\n\tt.Parallel()\n\n\ts := \u0026Store{\n\t\tdata: map[string][]Model{},\n\t}\n\n\t_, err := s.All(\"users\")\n\tif err == nil {\n\t\tt.Fatal(\"expected error, got nil\")\n\t}\n\n\texp := \"users\"\n\te, ok := err.(ErrTableNotFound)\n\tif !ok {\n\t\tt.Fatalf(\"expected ErrTableNotFound, got %T\", err)\n\t}\n\n\tact := e.Table\n\tif act != exp {\n\t\tt.Fatalf(\"expected %q, got %q\", exp, act)\n\t}\n\n\tif e.OccurredAt.IsZero() {\n\t\tt.Fatal(\"expected non-zero time\")\n\t}\n}", + "file": "errors/src/custom-table-err/store_test.go", + "lang": "go", + "name": "test", + "start": 5, + "end": 36 + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" src=\"errors/src/custom-table-err/store_test.go#test\"\u003e", + "type": "hype.SourceCode" + } + ] + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + }, + { + "atom": "hr", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "hr", + "data_atom": "hr", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [], + "tag": "\u003chr\u003e", + "type": "hype.Element" + }, + [ + { + "args": [ + "go", + "test", + "-v" + ], + "atom": "cmd", + "attributes": { + "data-go-version": "go1.22.0", + "exec": "go test -v", + "src": "errors/src/custom-table-err", + "test": "-v" + }, + "expected_exit": 0, + "filename": "errors", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "data-go-version", + "Val": "go1.22.0" + }, + { + "Namespace": "", + "Key": "exec", + "Val": "go test -v" + }, + { + "Namespace": "", + "Key": "src", + "Val": "src/custom-table-err" + }, + { + "Namespace": "", + "Key": "test", + "Val": "-v" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "test", + "-v" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/09-errors/errors/src/custom-table-err", + "duration": "3.822462833s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go test -v\n\n=== RUN Test_Store_All_NoTable\n=== PAUSE Test_Store_All_NoTable\n=== CONT Test_Store_All_NoTable\n--- PASS: Test_Store_All_NoTable (0.00s)\nPASS\nok \tdemo\t1.784s", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "=== RUN Test_Store_All_NoTable\n=== PAUSE Test_Store_All_NoTable\n=== CONT Test_Store_All_NoTable\n--- PASS: Test_Store_All_NoTable (0.00s)\nPASS\nok \tdemo\t1.784s", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "test", + "-v" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/09-errors/errors/src/custom-table-err", + "duration": "3.822462833s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go test -v\n\n=== RUN Test_Store_All_NoTable\n=== PAUSE Test_Store_All_NoTable\n=== CONT Test_Store_All_NoTable\n--- PASS: Test_Store_All_NoTable (0.00s)\nPASS\nok \tdemo\t1.784s", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "=== RUN Test_Store_All_NoTable\n=== PAUSE Test_Store_All_NoTable\n=== CONT Test_Store_All_NoTable\n--- PASS: Test_Store_All_NoTable (0.00s)\nPASS\nok \tdemo\t1.784s", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd data-go-version=\"go1.22.0\" exec=\"go test -v\" src=\"errors/src/custom-table-err\" test=\"-v\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.52:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "A test for the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Store.All", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " method with custom errors.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 52, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-52\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "tag": "\u003cpage\u003e", + "title": "Custom Errors", + "type": "hype.Page" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "tag": "\u003cinclude src=\"errors/custom.md\"\u003e", + "type": "hype.Include" + } + ], + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "atom": "include", + "attributes": { + "src": "errors/wrapping.md" + }, + "dir": "errors", + "filename": "module.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "errors/wrapping.md" + } + ], + "data": "include", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "page", + "attributes": {}, + "filename": "errors/wrapping.md", + "html_node": { + "data": "page", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "atom": "h1", + "attributes": {}, + "filename": "errors/wrapping.md", + "html_node": { + "data": "h1", + "data_atom": "h1", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "level": 1, + "nodes": [ + { + "text": "Wrapping and Unwrapping Errors", + "type": "hype.Text" + } + ], + "tag": "\u003ch1\u003e", + "type": "hype.Heading" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "errors/wrapping.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Consider the method defined in ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-53" + }, + "filename": "errors/wrapping.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "store.all" + } + ], + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-53" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.53", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-53\"\u003e", + "type": "hype.Link", + "url": "#listing-1-53" + } + ], + "tag": "\u003cref id=\"listing-1-53\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ". If an error occurs a custom ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "builtin#error", + "href": "https://pkg.go.dev/builtin#error", + "target": "_blank" + }, + "filename": "errors/wrapping.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/wrapping.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "error", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"builtin#error\" href=\"https://pkg.go.dev/builtin#error\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/builtin#error" + } + ], + { + "text": " implementation, ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/wrapping.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "ErrTableNotFound", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": ", is initialized with the appropriate information. Before being returned, however, error is then wrapped with ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "fmt#Errorf", + "href": "https://pkg.go.dev/fmt#Errorf", + "target": "_blank" + }, + "filename": "errors/wrapping.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/wrapping.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "fmt.Errorf", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"fmt#Errorf\" href=\"https://pkg.go.dev/fmt#Errorf\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/fmt#Errorf" + } + ], + { + "text": " to a message that includes the type and method that caused the error. To wrap an error using ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "fmt#Errorf", + "href": "https://pkg.go.dev/fmt#Errorf", + "target": "_blank" + }, + "filename": "errors/wrapping.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/wrapping.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "fmt.Errorf", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"fmt#Errorf\" href=\"https://pkg.go.dev/fmt#Errorf\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/fmt#Errorf" + } + ], + { + "text": ", we can use the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/wrapping.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "%w", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " formatting verb, meant for errors.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-53", + "type": "listing" + }, + "filename": "errors/wrapping.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "store.all" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + { + "atom": "pre", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "src": "errors/src/wrapped-error/store.go#all" + }, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/wrapped-error/store.go#all" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "content": "// All returns all models in the store for the given table name.\n// If no models exist, an error is returned.\nfunc (s *Store) All(tn string) ([]Model, error) {\n\tdb := s.data\n\n\t// if the underlying data is nil, return an error\n\tif db == nil {\n\t\treturn nil, fmt.Errorf(\"no data\")\n\t}\n\n\t// check to make sure table exists\n\tmods, ok := db[tn]\n\n\t// if table doesn't exist, return an error\n\tif !ok {\n\t\terr := ErrTableNotFound{\n\t\t\tTable: tn,\n\t\t\tOccurredAt: time.Now(),\n\t\t}\n\t\treturn nil, fmt.Errorf(\"[Store.All] %w\", err)\n\t}\n\n\t// return the slice of models\n\treturn mods, nil\n}", + "file": "errors/src/wrapped-error/store.go", + "lang": "go", + "name": "all", + "start": 21, + "end": 48 + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" src=\"errors/src/wrapped-error/store.go#all\"\u003e", + "type": "hype.SourceCode" + } + ] + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + }, + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.53:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "The ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Store.All", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " method.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 53, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-53\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "errors/wrapping.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-54" + }, + "filename": "errors/wrapping.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "wrapped.error.bug" + } + ], + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-54" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.54", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-54\"\u003e", + "type": "hype.Link", + "url": "#listing-1-54" + } + ], + "tag": "\u003cref id=\"listing-1-54\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": " shows a test for the method in ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-53" + }, + "filename": "errors/wrapping.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "store.all" + } + ], + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-53" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.53", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-53\"\u003e", + "type": "hype.Link", + "url": "#listing-1-53" + } + ], + "tag": "\u003cref id=\"listing-1-53\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ". This test tries to assert the returned error is of type ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/wrapping.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "ErrTableNotFound", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": ". When an error is wrapped with ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "fmt#Errorf", + "href": "https://pkg.go.dev/fmt#Errorf", + "target": "_blank" + }, + "filename": "errors/wrapping.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/wrapping.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "fmt.Errorf", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"fmt#Errorf\" href=\"https://pkg.go.dev/fmt#Errorf\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/fmt#Errorf" + } + ], + { + "text": ", the resulting type is that of the general ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "builtin#error", + "href": "https://pkg.go.dev/builtin#error", + "target": "_blank" + }, + "filename": "errors/wrapping.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/wrapping.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "error", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"builtin#error\" href=\"https://pkg.go.dev/builtin#error\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/builtin#error" + } + ], + { + "text": " interface. As such, by wrapping the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/wrapping.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "ErrTableNotFound", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " error with ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "fmt#Errorf", + "href": "https://pkg.go.dev/fmt#Errorf", + "target": "_blank" + }, + "filename": "errors/wrapping.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/wrapping.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "fmt.Errorf", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"fmt#Errorf\" href=\"https://pkg.go.dev/fmt#Errorf\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/fmt#Errorf" + } + ], + { + "text": " we have changed the resulting type of the error. This also results in the tests failing as the error is no longer an ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/wrapping.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "ErrTableNotFound", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": ", but a different type.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-54", + "type": "listing" + }, + "filename": "errors/wrapping.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "wrapped.error.bug" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + { + "atom": "pre", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "src": "errors/src/wrapped-error/store_test.go#test" + }, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/wrapped-error/store_test.go#test" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "content": "func Test_Store_All_NoTable(t *testing.T) {\n\tt.Parallel()\n\n\ts := \u0026Store{\n\t\tdata: map[string][]Model{},\n\t}\n\n\t_, err := s.All(\"users\")\n\tif err == nil {\n\t\tt.Fatal(\"expected error, got nil\")\n\t}\n\n\texp := \"users\"\n\te, ok := err.(ErrTableNotFound)\n\tif !ok {\n\t\tt.Fatalf(\"expected ErrTableNotFound, got %T\", err)\n\t}\n\n\tact := e.Table\n\tif act != exp {\n\t\tt.Fatalf(\"expected %q, got %q\", exp, act)\n\t}\n\n\tif e.OccurredAt.IsZero() {\n\t\tt.Fatal(\"expected non-zero time\")\n\t}\n}", + "file": "errors/src/wrapped-error/store_test.go", + "lang": "go", + "name": "test", + "start": 5, + "end": 34 + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" src=\"errors/src/wrapped-error/store_test.go#test\"\u003e", + "type": "hype.SourceCode" + } + ] + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + }, + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "args": [ + "go", + "test", + "-v" + ], + "atom": "cmd", + "attributes": { + "data-go-version": "go1.22.0", + "exec": "go test -v", + "exit": "-1", + "src": "errors/src/wrapped-error", + "test": "-v" + }, + "expected_exit": -1, + "filename": "errors", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "data-go-version", + "Val": "go1.22.0" + }, + { + "Namespace": "", + "Key": "exec", + "Val": "go test -v" + }, + { + "Namespace": "", + "Key": "exit", + "Val": "-1" + }, + { + "Namespace": "", + "Key": "src", + "Val": "src/wrapped-error" + }, + { + "Namespace": "", + "Key": "test", + "Val": "-v" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "test", + "-v" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/09-errors/errors/src/wrapped-error", + "duration": "5.189109542s", + "err": "exit status 1", + "exit": 1, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go test -v\n\n=== RUN Test_Store_All_NoTable\n=== PAUSE Test_Store_All_NoTable\n=== CONT Test_Store_All_NoTable\n store_test.go:21: expected ErrTableNotFound, got *fmt.wrapError\n--- FAIL: Test_Store_All_NoTable (0.00s)\nFAIL\nexit status 1\nFAIL\tdemo\t3.085s", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "=== RUN Test_Store_All_NoTable\n=== PAUSE Test_Store_All_NoTable\n=== CONT Test_Store_All_NoTable\n store_test.go:21: expected ErrTableNotFound, got *fmt.wrapError\n--- FAIL: Test_Store_All_NoTable (0.00s)\nFAIL\nexit status 1\nFAIL\tdemo\t3.085s", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "test", + "-v" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/09-errors/errors/src/wrapped-error", + "duration": "5.189109542s", + "err": "exit status 1", + "exit": 1, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go test -v\n\n=== RUN Test_Store_All_NoTable\n=== PAUSE Test_Store_All_NoTable\n=== CONT Test_Store_All_NoTable\n store_test.go:21: expected ErrTableNotFound, got *fmt.wrapError\n--- FAIL: Test_Store_All_NoTable (0.00s)\nFAIL\nexit status 1\nFAIL\tdemo\t3.085s", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "=== RUN Test_Store_All_NoTable\n=== PAUSE Test_Store_All_NoTable\n=== CONT Test_Store_All_NoTable\n store_test.go:21: expected ErrTableNotFound, got *fmt.wrapError\n--- FAIL: Test_Store_All_NoTable (0.00s)\nFAIL\nexit status 1\nFAIL\tdemo\t3.085s", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd data-go-version=\"go1.22.0\" exec=\"go test -v\" exit=\"-1\" src=\"errors/src/wrapped-error\" test=\"-v\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.54:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "A wrapped error can no longer be asserted against correctly.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 54, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-54\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "h2", + "attributes": {}, + "filename": "errors/wrapping.md", + "html_node": { + "data": "h2", + "data_atom": "h2", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "level": 2, + "nodes": [ + { + "text": "Wrapping Errors", + "type": "hype.Text" + } + ], + "tag": "\u003ch2\u003e", + "type": "hype.Heading" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "errors/wrapping.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "In order to get to the original error we need to unwrap the errors until we reach the original error. This is similar to peeling an onion, where each error is a layer of wrapping.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "errors/wrapping.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Let's take a simplified look at how wrapping and unwrapping errors works in Go. Consider the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "builtin#error", + "href": "https://pkg.go.dev/builtin#error", + "target": "_blank" + }, + "filename": "errors/wrapping.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/wrapping.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "error", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"builtin#error\" href=\"https://pkg.go.dev/builtin#error\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/builtin#error" + } + ], + { + "text": " types defined in ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-55" + }, + "filename": "errors/wrapping.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "wrapping.types" + } + ], + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-55" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.55", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-55\"\u003e", + "type": "hype.Link", + "url": "#listing-1-55" + } + ], + "tag": "\u003cref id=\"listing-1-55\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ". Each one contains a ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/wrapping.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "err", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " field that holds the error that is wrapping.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-55", + "type": "listing" + }, + "filename": "errors/wrapping.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "wrapping.types" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + { + "atom": "pre", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "src": "errors/src/wrapping-error/errors.go#errors" + }, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/wrapping-error/errors.go#errors" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "content": "type ErrorA struct {\n\terr error\n}\n\nfunc (e ErrorA) Error() string {\n\treturn fmt.Sprintf(\"[ErrorA] %s\", e.err)\n}\n\ntype ErrorB struct {\n\terr error\n}\n\nfunc (e ErrorB) Error() string {\n\treturn fmt.Sprintf(\"[ErrorB] %s\", e.err)\n}\n\ntype ErrorC struct {\n\terr error\n}\n\nfunc (e ErrorC) Error() string {\n\treturn fmt.Sprintf(\"[ErrorC] %s\", e.err)\n}", + "file": "errors/src/wrapping-error/errors.go", + "lang": "go", + "name": "errors", + "start": 5, + "end": 30 + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" src=\"errors/src/wrapping-error/errors.go#errors\"\u003e", + "type": "hype.SourceCode" + } + ] + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + }, + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.55:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "The three error types.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 55, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-55\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "errors/wrapping.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "In ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-56" + }, + "filename": "errors/wrapping.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "wrapping.wrapper" + } + ], + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-56" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.56", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-56\"\u003e", + "type": "hype.Link", + "url": "#listing-1-56" + } + ], + "tag": "\u003cref id=\"listing-1-56\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ", the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/wrapping.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Wrapper", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " function takes an error and the proceeds to wrap it in each of the three error types.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-56", + "type": "listing" + }, + "filename": "errors/wrapping.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "wrapping.wrapper" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + { + "atom": "pre", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "src": "errors/src/wrapping-error/errors.go#wrapper-short" + }, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/wrapping-error/errors.go#wrapper-short" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "content": "// Wrapper wraps an error with a bunch of\n// other errors.\n// ex. Wrapper(original) #=\u003e ErrorC -\u003e ErrorB -\u003e ErrorA -\u003e original\nfunc Wrapper(original error) error {\n\toriginal = ErrorA{original}\n\toriginal = ErrorB{original}\n\toriginal = ErrorC{original}\n\treturn original\n}", + "file": "errors/src/wrapping-error/errors.go", + "lang": "go", + "name": "wrapper-short", + "start": 32, + "end": 43 + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" src=\"errors/src/wrapping-error/errors.go#wrapper-short\"\u003e", + "type": "hype.SourceCode" + } + ] + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + }, + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.56:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "The ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Wrapper", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " function.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 56, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-56\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "errors/wrapping.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Another way to do this same wrapping is to use multiline initialization and fill each error type with the next error type, as seen in ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-57" + }, + "filename": "errors/wrapping.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "wrapping.long" + } + ], + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-57" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.57", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-57\"\u003e", + "type": "hype.Link", + "url": "#listing-1-57" + } + ], + "tag": "\u003cref id=\"listing-1-57\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ". Both of these are valid implementations of the same wrapping.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-57", + "type": "listing" + }, + "filename": "errors/wrapping.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "wrapping.long" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + { + "atom": "pre", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "src": "errors/src/wrapping-error/errors.go#wrapper-long" + }, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/wrapping-error/errors.go#wrapper-long" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "content": "// WrapperLong wraps an error with a bunch of\n// other errors.\n// ex. WrapperLong(original) #=\u003e ErrorC -\u003e ErrorB -\u003e ErrorA -\u003e original\nfunc WrapperLong(original error) error {\n\treturn ErrorC{\n\t\terr: ErrorB{\n\t\t\terr: ErrorA{\n\t\t\t\terr: original,\n\t\t\t},\n\t\t},\n\t}\n}", + "file": "errors/src/wrapping-error/errors.go", + "lang": "go", + "name": "wrapper-long", + "start": 45, + "end": 59 + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" src=\"errors/src/wrapping-error/errors.go#wrapper-long\"\u003e", + "type": "hype.SourceCode" + } + ] + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + }, + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.57:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "The ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Wrapper", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " function.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 57, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-57\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "h2", + "attributes": {}, + "filename": "errors/wrapping.md", + "html_node": { + "data": "h2", + "data_atom": "h2", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "level": 2, + "nodes": [ + { + "text": "Unwrapping Errors", + "type": "hype.Text" + } + ], + "tag": "\u003ch2\u003e", + "type": "hype.Heading" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "errors/wrapping.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "The ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "errors#Unwrap", + "href": "https://pkg.go.dev/errors#Unwrap", + "target": "_blank" + }, + "filename": "errors/wrapping.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/wrapping.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "errors.Unwrap", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"errors#Unwrap\" href=\"https://pkg.go.dev/errors#Unwrap\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/errors#Unwrap" + } + ], + { + "text": " function, ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-58" + }, + "filename": "errors/wrapping.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "unwrap.doc" + } + ], + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-58" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.58", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-58\"\u003e", + "type": "hype.Link", + "url": "#listing-1-58" + } + ], + "tag": "\u003cref id=\"listing-1-58\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ", can be used to unwrap an error until it reaches the original error. This will continue to peel the wrapped layers until it, hopefully, reaches the original error.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-58", + "type": "listing" + }, + "filename": "errors/wrapping.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "unwrap.doc" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "args": [ + "go", + "doc", + "errors.Unwrap" + ], + "atom": "cmd", + "attributes": { + "data-go-version": "go1.22.0", + "doc": "errors.Unwrap", + "exec": "go doc errors.Unwrap" + }, + "expected_exit": 0, + "filename": "errors", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "data-go-version", + "Val": "go1.22.0" + }, + { + "Namespace": "", + "Key": "doc", + "Val": "errors.Unwrap" + }, + { + "Namespace": "", + "Key": "exec", + "Val": "go doc errors.Unwrap" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "doc", + "errors.Unwrap" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypejs", + "duration": "1.392811583s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go doc errors.Unwrap\n\npackage errors // import \u0026#34;errors\u0026#34;\n\nfunc Unwrap(err error) error\n Unwrap returns the result of calling the Unwrap method on err, if err\u0026#39;s type\n contains an Unwrap method returning error. Otherwise, Unwrap returns nil.\n\n Unwrap only calls a method of the form \u0026#34;Unwrap() error\u0026#34;. In particular\n Unwrap does not unwrap errors returned by Join.", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "package errors // import \"errors\"\n\nfunc Unwrap(err error) error\n Unwrap returns the result of calling the Unwrap method on err, if err's type\n contains an Unwrap method returning error. Otherwise, Unwrap returns nil.\n\n Unwrap only calls a method of the form \"Unwrap() error\". In particular\n Unwrap does not unwrap errors returned by Join.", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "doc", + "errors.Unwrap" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypejs", + "duration": "1.392811583s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go doc errors.Unwrap\n\npackage errors // import \u0026#34;errors\u0026#34;\n\nfunc Unwrap(err error) error\n Unwrap returns the result of calling the Unwrap method on err, if err\u0026#39;s type\n contains an Unwrap method returning error. Otherwise, Unwrap returns nil.\n\n Unwrap only calls a method of the form \u0026#34;Unwrap() error\u0026#34;. In particular\n Unwrap does not unwrap errors returned by Join.", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "package errors // import \"errors\"\n\nfunc Unwrap(err error) error\n Unwrap returns the result of calling the Unwrap method on err, if err's type\n contains an Unwrap method returning error. Otherwise, Unwrap returns nil.\n\n Unwrap only calls a method of the form \"Unwrap() error\". In particular\n Unwrap does not unwrap errors returned by Join.", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd data-go-version=\"go1.22.0\" doc=\"errors.Unwrap\" exec=\"go doc errors.Unwrap\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.58:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "The ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "errors#Unwrap", + "href": "https://pkg.go.dev/errors#Unwrap", + "target": "_blank" + }, + "filename": "errors", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "for", + "Val": "errors#Unwrap" + }, + { + "Namespace": "", + "Key": "href", + "Val": "https://pkg.go.dev/errors#Unwrap" + }, + { + "Namespace": "", + "Key": "target", + "Val": "_blank" + } + ], + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "errors.Unwrap", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ] + ], + "tag": "\u003ca for=\"errors#Unwrap\" href=\"https://pkg.go.dev/errors#Unwrap\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/errors#Unwrap" + } + ], + { + "text": " function.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 58, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-58\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "errors/wrapping.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "In ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-59" + }, + "filename": "errors/wrapping.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "unwrap.test" + } + ], + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-59" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.59", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-59\"\u003e", + "type": "hype.Link", + "url": "#listing-1-59" + } + ], + "tag": "\u003cref id=\"listing-1-59\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": " the test has been updated to use the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "errors#Unwrap", + "href": "https://pkg.go.dev/errors#Unwrap", + "target": "_blank" + }, + "filename": "errors/wrapping.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/wrapping.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "errors.Unwrap", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"errors#Unwrap\" href=\"https://pkg.go.dev/errors#Unwrap\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/errors#Unwrap" + } + ], + { + "text": " function to unwrap the error until it reaches the original error. Unfortunately, however, the test will fail because the result of ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/wrapping.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "errors.Unwrap", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " is ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/wrapping.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "nil", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": ".", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-59", + "type": "listing" + }, + "filename": "errors/wrapping.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "unwrap.test" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + { + "atom": "pre", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "src": "errors/src/wrapping-error/errors_test.go#test-unwrap" + }, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/wrapping-error/errors_test.go#test-unwrap" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "content": "func Test_Unwrap(t *testing.T) {\n\tt.Parallel()\n\n\toriginal := errors.New(\"original error\")\n\twrapped := Wrapper(original)\n\n\tunwrapped := errors.Unwrap(wrapped)\n\tif unwrapped != original {\n\t\tt.Fatalf(\"expected %v, got %v\", original, unwrapped)\n\t}\n\n}", + "file": "errors/src/wrapping-error/errors_test.go", + "lang": "go", + "name": "test-unwrap", + "start": 23, + "end": 37 + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" src=\"errors/src/wrapping-error/errors_test.go#test-unwrap\"\u003e", + "type": "hype.SourceCode" + } + ] + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + }, + { + "atom": "hr", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "hr", + "data_atom": "hr", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [], + "tag": "\u003chr\u003e", + "type": "hype.Element" + }, + [ + { + "args": [ + "go", + "test", + "-v" + ], + "atom": "cmd", + "attributes": { + "data-go-version": "go1.22.0", + "exec": "go test -v", + "exit": "-1", + "src": "errors/src/wrapping-error", + "test": "-v" + }, + "expected_exit": -1, + "filename": "errors", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "data-go-version", + "Val": "go1.22.0" + }, + { + "Namespace": "", + "Key": "exec", + "Val": "go test -v" + }, + { + "Namespace": "", + "Key": "exit", + "Val": "-1" + }, + { + "Namespace": "", + "Key": "src", + "Val": "src/wrapping-error" + }, + { + "Namespace": "", + "Key": "test", + "Val": "-v" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "test", + "-v" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/09-errors/errors/src/wrapping-error", + "duration": "4.605706s", + "err": "exit status 1", + "exit": 1, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go test -v\n\n=== RUN Test_Wrapper\n=== PAUSE Test_Wrapper\n=== RUN Test_Unwrap\n=== PAUSE Test_Unwrap\n=== CONT Test_Wrapper\n--- PASS: Test_Wrapper (0.00s)\n=== CONT Test_Unwrap\n errors_test.go:32: expected original error, got \u0026lt;nil\u0026gt;\n--- FAIL: Test_Unwrap (0.00s)\nFAIL\nexit status 1\nFAIL\tdemo\t2.549s", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "=== RUN Test_Wrapper\n=== PAUSE Test_Wrapper\n=== RUN Test_Unwrap\n=== PAUSE Test_Unwrap\n=== CONT Test_Wrapper\n--- PASS: Test_Wrapper (0.00s)\n=== CONT Test_Unwrap\n errors_test.go:32: expected original error, got \u003cnil\u003e\n--- FAIL: Test_Unwrap (0.00s)\nFAIL\nexit status 1\nFAIL\tdemo\t2.549s", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "test", + "-v" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/09-errors/errors/src/wrapping-error", + "duration": "4.605706s", + "err": "exit status 1", + "exit": 1, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go test -v\n\n=== RUN Test_Wrapper\n=== PAUSE Test_Wrapper\n=== RUN Test_Unwrap\n=== PAUSE Test_Unwrap\n=== CONT Test_Wrapper\n--- PASS: Test_Wrapper (0.00s)\n=== CONT Test_Unwrap\n errors_test.go:32: expected original error, got \u0026lt;nil\u0026gt;\n--- FAIL: Test_Unwrap (0.00s)\nFAIL\nexit status 1\nFAIL\tdemo\t2.549s", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "=== RUN Test_Wrapper\n=== PAUSE Test_Wrapper\n=== RUN Test_Unwrap\n=== PAUSE Test_Unwrap\n=== CONT Test_Wrapper\n--- PASS: Test_Wrapper (0.00s)\n=== CONT Test_Unwrap\n errors_test.go:32: expected original error, got \u003cnil\u003e\n--- FAIL: Test_Unwrap (0.00s)\nFAIL\nexit status 1\nFAIL\tdemo\t2.549s", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd data-go-version=\"go1.22.0\" exec=\"go test -v\" exit=\"-1\" src=\"errors/src/wrapping-error\" test=\"-v\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.59:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "Using ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "errors#Unwrap", + "href": "https://pkg.go.dev/errors#Unwrap", + "target": "_blank" + }, + "filename": "errors", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "for", + "Val": "errors#Unwrap" + }, + { + "Namespace": "", + "Key": "href", + "Val": "https://pkg.go.dev/errors#Unwrap" + }, + { + "Namespace": "", + "Key": "target", + "Val": "_blank" + } + ], + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "errors.Unwrap", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ] + ], + "tag": "\u003ca for=\"errors#Unwrap\" href=\"https://pkg.go.dev/errors#Unwrap\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/errors#Unwrap" + } + ], + { + "text": " to get the original error.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 59, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-59\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "h2", + "attributes": {}, + "filename": "errors/wrapping.md", + "html_node": { + "data": "h2", + "data_atom": "h2", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "level": 2, + "nodes": [ + { + "text": "Unwrapping Custom Errors", + "type": "hype.Text" + } + ], + "tag": "\u003ch2\u003e", + "type": "hype.Heading" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "errors/wrapping.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "As the documentation states, ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-58" + }, + "filename": "errors/wrapping.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "unwrap.doc" + } + ], + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-58" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.58", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-58\"\u003e", + "type": "hype.Link", + "url": "#listing-1-58" + } + ], + "tag": "\u003cref id=\"listing-1-58\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ", ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "errors#Unwrap", + "href": "https://pkg.go.dev/errors#Unwrap", + "target": "_blank" + }, + "filename": "errors/wrapping.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/wrapping.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "errors.Unwrap", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"errors#Unwrap\" href=\"https://pkg.go.dev/errors#Unwrap\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/errors#Unwrap" + } + ], + { + "text": " returns the result of calling the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/wrapping.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Unwrap", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " method on an error, if the error's type contains an ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/wrapping.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Unwrap", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " method returning ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/wrapping.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "error", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": ". Otherwise, ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "errors#Unwrap", + "href": "https://pkg.go.dev/errors#Unwrap", + "target": "_blank" + }, + "filename": "errors/wrapping.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/wrapping.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "errors.Unwrap", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"errors#Unwrap\" href=\"https://pkg.go.dev/errors#Unwrap\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/errors#Unwrap" + } + ], + { + "text": " returns ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/wrapping.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "nil", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": ".", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "errors/wrapping.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "What the documentation is trying to say is that our custom error types need to implement the interface shown in ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-60" + }, + "filename": "errors/wrapping.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "unwrap.interface" + } + ], + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-60" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.60", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-60\"\u003e", + "type": "hype.Link", + "url": "#listing-1-60" + } + ], + "tag": "\u003cref id=\"listing-1-60\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ". Unfortunately, the Go standard library does not define this interface for you, outside of the documentation.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-60", + "type": "listing" + }, + "filename": "errors/wrapping.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "unwrap.interface" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + { + "atom": "pre", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "src": "errors/src/wrapped-broken/errors.go#interface" + }, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/wrapped-broken/errors.go#interface" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "content": "type Unwrapper interface {\n\tUnwrap() error\n}", + "file": "errors/src/wrapped-broken/errors.go", + "lang": "go", + "name": "interface", + "start": 8, + "end": 13 + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" src=\"errors/src/wrapped-broken/errors.go#interface\"\u003e", + "type": "hype.SourceCode" + } + ] + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + }, + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.60:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "The missing ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Unwrapper", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " interface.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 60, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-60\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "errors/wrapping.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Let's update the error types defined in ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-55" + }, + "filename": "errors/wrapping.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "wrapping.types" + } + ], + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-55" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.55", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-55\"\u003e", + "type": "hype.Link", + "url": "#listing-1-55" + } + ], + "tag": "\u003cref id=\"listing-1-55\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": " to implement the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/wrapping.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Unwrapper", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " interface. While ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-61" + }, + "filename": "errors/wrapping.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "unwrap.impl" + } + ], + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-61" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.61", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-61\"\u003e", + "type": "hype.Link", + "url": "#listing-1-61" + } + ], + "tag": "\u003cref id=\"listing-1-61\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": " only shows one implementation, all of our types will need to be made to implement the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/wrapping.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Unwrapper", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " interface. The implementation of this interface needs to make sure to call ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "errors#Unwrap", + "href": "https://pkg.go.dev/errors#Unwrap", + "target": "_blank" + }, + "filename": "errors/wrapping.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/wrapping.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "errors.Unwrap", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"errors#Unwrap\" href=\"https://pkg.go.dev/errors#Unwrap\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/errors#Unwrap" + } + ], + { + "text": " on the error it is wrapping.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-61", + "type": "listing" + }, + "filename": "errors/wrapping.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "unwrap.impl" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + { + "atom": "pre", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "src": "errors/src/wrapped-broken/errors.go#unwrap" + }, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/wrapped-broken/errors.go#unwrap" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "content": "func (e ErrorA) Unwrap() error {\n\treturn errors.Unwrap(e.err)\n}", + "file": "errors/src/wrapped-broken/errors.go", + "lang": "go", + "name": "unwrap", + "start": 24, + "end": 29 + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" src=\"errors/src/wrapped-broken/errors.go#unwrap\"\u003e", + "type": "hype.SourceCode" + } + ] + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + }, + { + "atom": "hr", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "hr", + "data_atom": "hr", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [], + "tag": "\u003chr\u003e", + "type": "hype.Element" + }, + [ + { + "args": [ + "go", + "test", + "-v" + ], + "atom": "cmd", + "attributes": { + "data-go-version": "go1.22.0", + "exec": "go test -v", + "exit": "-1", + "src": "errors/src/wrapped-broken", + "test": "-v" + }, + "expected_exit": -1, + "filename": "errors", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "data-go-version", + "Val": "go1.22.0" + }, + { + "Namespace": "", + "Key": "exec", + "Val": "go test -v" + }, + { + "Namespace": "", + "Key": "exit", + "Val": "-1" + }, + { + "Namespace": "", + "Key": "src", + "Val": "src/wrapped-broken" + }, + { + "Namespace": "", + "Key": "test", + "Val": "-v" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "test", + "-v" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/09-errors/errors/src/wrapped-broken", + "duration": "5.347319416s", + "err": "exit status 1", + "exit": 1, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go test -v\n\n=== RUN Test_Wrapper\n=== PAUSE Test_Wrapper\n=== RUN Test_Unwrap\n=== PAUSE Test_Unwrap\n=== CONT Test_Wrapper\n--- PASS: Test_Wrapper (0.00s)\n=== CONT Test_Unwrap\n errors_test.go:32: expected original error, got \u0026lt;nil\u0026gt;\n--- FAIL: Test_Unwrap (0.00s)\nFAIL\nexit status 1\nFAIL\tdemo\t3.242s", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "=== RUN Test_Wrapper\n=== PAUSE Test_Wrapper\n=== RUN Test_Unwrap\n=== PAUSE Test_Unwrap\n=== CONT Test_Wrapper\n--- PASS: Test_Wrapper (0.00s)\n=== CONT Test_Unwrap\n errors_test.go:32: expected original error, got \u003cnil\u003e\n--- FAIL: Test_Unwrap (0.00s)\nFAIL\nexit status 1\nFAIL\tdemo\t3.242s", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "test", + "-v" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/09-errors/errors/src/wrapped-broken", + "duration": "5.347319416s", + "err": "exit status 1", + "exit": 1, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go test -v\n\n=== RUN Test_Wrapper\n=== PAUSE Test_Wrapper\n=== RUN Test_Unwrap\n=== PAUSE Test_Unwrap\n=== CONT Test_Wrapper\n--- PASS: Test_Wrapper (0.00s)\n=== CONT Test_Unwrap\n errors_test.go:32: expected original error, got \u0026lt;nil\u0026gt;\n--- FAIL: Test_Unwrap (0.00s)\nFAIL\nexit status 1\nFAIL\tdemo\t3.242s", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "=== RUN Test_Wrapper\n=== PAUSE Test_Wrapper\n=== RUN Test_Unwrap\n=== PAUSE Test_Unwrap\n=== CONT Test_Wrapper\n--- PASS: Test_Wrapper (0.00s)\n=== CONT Test_Unwrap\n errors_test.go:32: expected original error, got \u003cnil\u003e\n--- FAIL: Test_Unwrap (0.00s)\nFAIL\nexit status 1\nFAIL\tdemo\t3.242s", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd data-go-version=\"go1.22.0\" exec=\"go test -v\" exit=\"-1\" src=\"errors/src/wrapped-broken\" test=\"-v\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.61:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "Implementing the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Unwrapper", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " interface.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 61, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-61\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "errors/wrapping.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "The tests in ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-61" + }, + "filename": "errors/wrapping.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "unwrap.impl" + } + ], + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-61" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.61", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-61\"\u003e", + "type": "hype.Link", + "url": "#listing-1-61" + } + ], + "tag": "\u003cref id=\"listing-1-61\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ", however, are still failing. If the error we are wrapping does not contain an ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/wrapping.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Unwrap", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " method, the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "errors#Unwrap", + "href": "https://pkg.go.dev/errors#Unwrap", + "target": "_blank" + }, + "filename": "errors/wrapping.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/wrapping.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "errors.Unwrap", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"errors#Unwrap\" href=\"https://pkg.go.dev/errors#Unwrap\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/errors#Unwrap" + } + ], + { + "text": " function will return ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/wrapping.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "nil", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " and we won't be able to get access to the original error.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "errors/wrapping.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "To fix this we need to check the error we are wrapping for the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/wrapping.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Unwrapper", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " interface. If it does, we can call ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "errors#Unwrap", + "href": "https://pkg.go.dev/errors#Unwrap", + "target": "_blank" + }, + "filename": "errors/wrapping.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/wrapping.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "errors.Unwrap", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"errors#Unwrap\" href=\"https://pkg.go.dev/errors#Unwrap\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/errors#Unwrap" + } + ], + { + "text": " with the error. If it does not exist, we can return the error as is.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-62", + "type": "listing" + }, + "filename": "errors/wrapping.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "finished" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + { + "atom": "pre", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "src": "errors/src/wrapped/errors.go#unwrap" + }, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/wrapped/errors.go#unwrap" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "content": "func (e ErrorA) Unwrap() error {\n\tif _, ok := e.err.(Unwrapper); ok {\n\t\treturn errors.Unwrap(e.err)\n\t}\n\n\treturn e.err\n}", + "file": "errors/src/wrapped/errors.go", + "lang": "go", + "name": "unwrap", + "start": 24, + "end": 33 + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" src=\"errors/src/wrapped/errors.go#unwrap\"\u003e", + "type": "hype.SourceCode" + } + ] + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + }, + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "args": [ + "go", + "test", + "-v" + ], + "atom": "cmd", + "attributes": { + "data-go-version": "go1.22.0", + "exec": "go test -v", + "src": "errors/src/wrapped", + "test": "-v" + }, + "expected_exit": 0, + "filename": "errors", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "data-go-version", + "Val": "go1.22.0" + }, + { + "Namespace": "", + "Key": "exec", + "Val": "go test -v" + }, + { + "Namespace": "", + "Key": "src", + "Val": "src/wrapped" + }, + { + "Namespace": "", + "Key": "test", + "Val": "-v" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "test", + "-v" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/09-errors/errors/src/wrapped", + "duration": "2.404932292s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go test -v\n\n=== RUN Test_Wrapper\n=== PAUSE Test_Wrapper\n=== RUN Test_Unwrap\n=== PAUSE Test_Unwrap\n=== CONT Test_Wrapper\n--- PASS: Test_Wrapper (0.00s)\n=== CONT Test_Unwrap\n--- PASS: Test_Unwrap (0.00s)\nPASS\nok \tdemo\t0.616s", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "=== RUN Test_Wrapper\n=== PAUSE Test_Wrapper\n=== RUN Test_Unwrap\n=== PAUSE Test_Unwrap\n=== CONT Test_Wrapper\n--- PASS: Test_Wrapper (0.00s)\n=== CONT Test_Unwrap\n--- PASS: Test_Unwrap (0.00s)\nPASS\nok \tdemo\t0.616s", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "test", + "-v" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/09-errors/errors/src/wrapped", + "duration": "2.404932292s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go test -v\n\n=== RUN Test_Wrapper\n=== PAUSE Test_Wrapper\n=== RUN Test_Unwrap\n=== PAUSE Test_Unwrap\n=== CONT Test_Wrapper\n--- PASS: Test_Wrapper (0.00s)\n=== CONT Test_Unwrap\n--- PASS: Test_Unwrap (0.00s)\nPASS\nok \tdemo\t0.616s", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "=== RUN Test_Wrapper\n=== PAUSE Test_Wrapper\n=== RUN Test_Unwrap\n=== PAUSE Test_Unwrap\n=== CONT Test_Wrapper\n--- PASS: Test_Wrapper (0.00s)\n=== CONT Test_Unwrap\n--- PASS: Test_Unwrap (0.00s)\nPASS\nok \tdemo\t0.616s", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd data-go-version=\"go1.22.0\" exec=\"go test -v\" src=\"errors/src/wrapped\" test=\"-v\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.62:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "Properly implementing the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Unwrap", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " method.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 62, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-62\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "errors/wrapping.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Now that we understand ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "errors#Unwrap", + "href": "https://pkg.go.dev/errors#Unwrap", + "target": "_blank" + }, + "filename": "errors/wrapping.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/wrapping.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "errors.Unwrap", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"errors#Unwrap\" href=\"https://pkg.go.dev/errors#Unwrap\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/errors#Unwrap" + } + ], + { + "text": ", we can fix the test in ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-54" + }, + "filename": "errors/wrapping.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "wrapped.error.bug" + } + ], + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-54" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.54", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-54\"\u003e", + "type": "hype.Link", + "url": "#listing-1-54" + } + ], + "tag": "\u003cref id=\"listing-1-54\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": " to get the original error.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-63", + "type": "listing" + }, + "filename": "errors/wrapping.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "wrapped.error.fixed" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + { + "atom": "pre", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "src": "errors/src/wrapped-fixed/store_test.go#test" + }, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/wrapped-fixed/store_test.go#test" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "content": "func Test_Store_All_NoTable(t *testing.T) {\n\tt.Parallel()\n\n\ts := \u0026Store{\n\t\tdata: map[string][]Model{},\n\t}\n\n\t_, err := s.All(\"users\")\n\tif err == nil {\n\t\tt.Fatal(\"expected error, got nil\")\n\t}\n\n\t// unwrap the error\n\terr = errors.Unwrap(err)\n\n\texp := \"users\"\n\te, ok := err.(ErrTableNotFound)\n\tif !ok {\n\t\tt.Fatalf(\"expected ErrTableNotFound, got %T\", err)\n\t}\n\n\tact := e.Table\n\tif act != exp {\n\t\tt.Fatalf(\"expected %q, got %q\", exp, act)\n\t}\n\n\tif e.OccurredAt.IsZero() {\n\t\tt.Fatal(\"expected non-zero time\")\n\t}\n}", + "file": "errors/src/wrapped-fixed/store_test.go", + "lang": "go", + "name": "test", + "start": 8, + "end": 40 + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" src=\"errors/src/wrapped-fixed/store_test.go#test\"\u003e", + "type": "hype.SourceCode" + } + ] + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + }, + { + "atom": "hr", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "hr", + "data_atom": "hr", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [], + "tag": "\u003chr\u003e", + "type": "hype.Element" + }, + [ + { + "args": [ + "go", + "test", + "-v" + ], + "atom": "cmd", + "attributes": { + "data-go-version": "go1.22.0", + "exec": "go test -v", + "src": "errors/src/wrapped-fixed", + "test": "-v" + }, + "expected_exit": 0, + "filename": "errors", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "data-go-version", + "Val": "go1.22.0" + }, + { + "Namespace": "", + "Key": "exec", + "Val": "go test -v" + }, + { + "Namespace": "", + "Key": "src", + "Val": "src/wrapped-fixed" + }, + { + "Namespace": "", + "Key": "test", + "Val": "-v" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "test", + "-v" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/09-errors/errors/src/wrapped-fixed", + "duration": "4.330629167s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go test -v\n\n=== RUN Test_Store_All_NoTable\n=== PAUSE Test_Store_All_NoTable\n=== CONT Test_Store_All_NoTable\n--- PASS: Test_Store_All_NoTable (0.00s)\nPASS\nok \tdemo\t2.280s", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "=== RUN Test_Store_All_NoTable\n=== PAUSE Test_Store_All_NoTable\n=== CONT Test_Store_All_NoTable\n--- PASS: Test_Store_All_NoTable (0.00s)\nPASS\nok \tdemo\t2.280s", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "test", + "-v" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/09-errors/errors/src/wrapped-fixed", + "duration": "4.330629167s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go test -v\n\n=== RUN Test_Store_All_NoTable\n=== PAUSE Test_Store_All_NoTable\n=== CONT Test_Store_All_NoTable\n--- PASS: Test_Store_All_NoTable (0.00s)\nPASS\nok \tdemo\t2.280s", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "=== RUN Test_Store_All_NoTable\n=== PAUSE Test_Store_All_NoTable\n=== CONT Test_Store_All_NoTable\n--- PASS: Test_Store_All_NoTable (0.00s)\nPASS\nok \tdemo\t2.280s", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd data-go-version=\"go1.22.0\" exec=\"go test -v\" src=\"errors/src/wrapped-fixed\" test=\"-v\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.63:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "The ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "WrappedError", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " type.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 63, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-63\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "h2", + "attributes": {}, + "filename": "errors/wrapping.md", + "html_node": { + "data": "h2", + "data_atom": "h2", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "level": 2, + "nodes": [ + { + "text": "To Wrap Or Not to Wrap", + "type": "hype.Text" + } + ], + "tag": "\u003ch2\u003e", + "type": "hype.Heading" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "errors/wrapping.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "We saw that you can use the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "fmt#Errorf", + "href": "https://pkg.go.dev/fmt#Errorf", + "target": "_blank" + }, + "filename": "errors/wrapping.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/wrapping.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "fmt.Errorf", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"fmt#Errorf\" href=\"https://pkg.go.dev/fmt#Errorf\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/fmt#Errorf" + } + ], + { + "text": " with the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/wrapping.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "%w", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " verb to wrap an error. This will allow for the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/wrapping.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "unwrapping", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " of an error later, either from the caller of your function/method or in a test.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "errors/wrapping.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "While the normal rule is to always wrap the errors with the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/wrapping.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "%w", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": ", there are exceptions. If you don't want some internal information or package specific information to not be wrapped, then it is ok to use the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/wrapping.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "%s", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " verb to hide any implementation details. Keep in mind, this is normally the exception and not the rule.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "errors/wrapping.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "If in doubt, it is usually safer to wrap the error so that other code that calls your package can check for specific errors later.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "tag": "\u003cpage\u003e", + "title": "Wrapping and Unwrapping Errors", + "type": "hype.Page" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "tag": "\u003cinclude src=\"errors/wrapping.md\"\u003e", + "type": "hype.Include" + } + ], + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "atom": "include", + "attributes": { + "src": "errors/as_is.md" + }, + "dir": "errors", + "filename": "module.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "errors/as_is.md" + } + ], + "data": "include", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "page", + "attributes": {}, + "filename": "errors/as_is.md", + "html_node": { + "data": "page", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "atom": "h1", + "attributes": {}, + "filename": "errors/as_is.md", + "html_node": { + "data": "h1", + "data_atom": "h1", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "level": 1, + "nodes": [ + { + "text": "Errors As/Is", + "type": "hype.Text" + } + ], + "tag": "\u003ch1\u003e", + "type": "hype.Heading" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "errors/as_is.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "While unwrapping an error allows us to get to the original, underlying error, it does not allow us to get access to any of the other errors that it might have been wrapped with. Consider ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-64" + }, + "filename": "errors/as_is.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "wrapper-short" + } + ], + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-64" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.64", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-64\"\u003e", + "type": "hype.Link", + "url": "#listing-1-64" + } + ], + "tag": "\u003cref id=\"listing-1-64\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ". When we unwrap the error returned from the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/as_is.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Wrapper", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " function we can get access to the original error passed in, but how do we check if the wrapped error has ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/as_is.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "ErrorB", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " in its stack and how do we get access to the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/as_is.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "ErrorA", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " error? The ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "errors", + "href": "https://pkg.go.dev/errors", + "target": "_blank" + }, + "filename": "errors/as_is.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/as_is.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "errors", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"errors\" href=\"https://pkg.go.dev/errors\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/errors" + } + ], + { + "text": " package provides two functions, ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "errors#Is", + "href": "https://pkg.go.dev/errors#Is", + "target": "_blank" + }, + "filename": "errors/as_is.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/as_is.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "errors.Is", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"errors#Is\" href=\"https://pkg.go.dev/errors#Is\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/errors#Is" + } + ], + { + "text": " and ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "errors#As", + "href": "https://pkg.go.dev/errors#As", + "target": "_blank" + }, + "filename": "errors/as_is.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/as_is.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "errors.As", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"errors#As\" href=\"https://pkg.go.dev/errors#As\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/errors#As" + } + ], + { + "text": ", that will help us with these questions.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-64", + "type": "listing" + }, + "filename": "errors/as_is.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "wrapper-short" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + { + "atom": "pre", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "src": "errors/src/wrapping-error/errors.go#wrapper-short" + }, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/wrapping-error/errors.go#wrapper-short" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "content": "// Wrapper wraps an error with a bunch of\n// other errors.\n// ex. Wrapper(original) #=\u003e ErrorC -\u003e ErrorB -\u003e ErrorA -\u003e original\nfunc Wrapper(original error) error {\n\toriginal = ErrorA{original}\n\toriginal = ErrorB{original}\n\toriginal = ErrorC{original}\n\treturn original\n}", + "file": "errors/src/wrapping-error/errors.go", + "lang": "go", + "name": "wrapper-short", + "start": 32, + "end": 43 + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" src=\"errors/src/wrapping-error/errors.go#wrapper-short\"\u003e", + "type": "hype.SourceCode" + } + ] + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + }, + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.64:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "A function that nests one error in many errors.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 64, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-64\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "h2", + "attributes": {}, + "filename": "errors/as_is.md", + "html_node": { + "data": "h2", + "data_atom": "h2", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "level": 2, + "nodes": [ + { + "text": "As", + "type": "hype.Text" + } + ], + "tag": "\u003ch2\u003e", + "type": "hype.Heading" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "errors/as_is.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "When working with errors, we often don't care about the underlying error, there are times, however, when we do care about the underlying error and we want to get access to it. The ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "errors#As", + "href": "https://pkg.go.dev/errors#As", + "target": "_blank" + }, + "filename": "errors/as_is.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/as_is.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "errors.As", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"errors#As\" href=\"https://pkg.go.dev/errors#As\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/errors#As" + } + ], + { + "text": ", ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-65" + }, + "filename": "errors/as_is.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "as.doc" + } + ], + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-65" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.65", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-65\"\u003e", + "type": "hype.Link", + "url": "#listing-1-65" + } + ], + "tag": "\u003cref id=\"listing-1-65\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ", function is designed to do this. It takes an ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "builtin#error", + "href": "https://pkg.go.dev/builtin#error", + "target": "_blank" + }, + "filename": "errors/as_is.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/as_is.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "error", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"builtin#error\" href=\"https://pkg.go.dev/builtin#error\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/builtin#error" + } + ], + { + "text": " and a type to match against. If the error matches the type, it will return the underlying error. If the error does not match the type, it will return ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/as_is.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "nil", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": ".", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-65", + "type": "listing" + }, + "filename": "errors/as_is.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "as.doc" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "args": [ + "go", + "doc", + "errors.As" + ], + "atom": "cmd", + "attributes": { + "data-go-version": "go1.22.0", + "doc": "errors.As", + "exec": "go doc errors.As" + }, + "expected_exit": 0, + "filename": "errors", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "data-go-version", + "Val": "go1.22.0" + }, + { + "Namespace": "", + "Key": "doc", + "Val": "errors.As" + }, + { + "Namespace": "", + "Key": "exec", + "Val": "go doc errors.As" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "doc", + "errors.As" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypejs", + "duration": "1.028157041s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go doc errors.As\n\npackage errors // import \u0026#34;errors\u0026#34;\n\nfunc As(err error, target any) bool\n As finds the first error in err\u0026#39;s tree that matches target, and if one\n is found, sets target to that error value and returns true. Otherwise,\n it returns false.\n\n The tree consists of err itself, followed by the errors obtained by\n repeatedly calling its Unwrap() error or Unwrap() []error method. When err\n wraps multiple errors, As examines err followed by a depth-first traversal\n of its children.\n\n An error matches target if the error\u0026#39;s concrete value is assignable to the\n value pointed to by target, or if the error has a method As(interface{})\n bool such that As(target) returns true. In the latter case, the As method is\n responsible for setting target.\n\n An error type might provide an As method so it can be treated as if it were\n a different error type.\n\n As panics if target is not a non-nil pointer to either a type that\n implements error, or to any interface type.", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "package errors // import \"errors\"\n\nfunc As(err error, target any) bool\n As finds the first error in err's tree that matches target, and if one\n is found, sets target to that error value and returns true. Otherwise,\n it returns false.\n\n The tree consists of err itself, followed by the errors obtained by\n repeatedly calling its Unwrap() error or Unwrap() []error method. When err\n wraps multiple errors, As examines err followed by a depth-first traversal\n of its children.\n\n An error matches target if the error's concrete value is assignable to the\n value pointed to by target, or if the error has a method As(interface{})\n bool such that As(target) returns true. In the latter case, the As method is\n responsible for setting target.\n\n An error type might provide an As method so it can be treated as if it were\n a different error type.\n\n As panics if target is not a non-nil pointer to either a type that\n implements error, or to any interface type.", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "doc", + "errors.As" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypejs", + "duration": "1.028157041s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go doc errors.As\n\npackage errors // import \u0026#34;errors\u0026#34;\n\nfunc As(err error, target any) bool\n As finds the first error in err\u0026#39;s tree that matches target, and if one\n is found, sets target to that error value and returns true. Otherwise,\n it returns false.\n\n The tree consists of err itself, followed by the errors obtained by\n repeatedly calling its Unwrap() error or Unwrap() []error method. When err\n wraps multiple errors, As examines err followed by a depth-first traversal\n of its children.\n\n An error matches target if the error\u0026#39;s concrete value is assignable to the\n value pointed to by target, or if the error has a method As(interface{})\n bool such that As(target) returns true. In the latter case, the As method is\n responsible for setting target.\n\n An error type might provide an As method so it can be treated as if it were\n a different error type.\n\n As panics if target is not a non-nil pointer to either a type that\n implements error, or to any interface type.", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "package errors // import \"errors\"\n\nfunc As(err error, target any) bool\n As finds the first error in err's tree that matches target, and if one\n is found, sets target to that error value and returns true. Otherwise,\n it returns false.\n\n The tree consists of err itself, followed by the errors obtained by\n repeatedly calling its Unwrap() error or Unwrap() []error method. When err\n wraps multiple errors, As examines err followed by a depth-first traversal\n of its children.\n\n An error matches target if the error's concrete value is assignable to the\n value pointed to by target, or if the error has a method As(interface{})\n bool such that As(target) returns true. In the latter case, the As method is\n responsible for setting target.\n\n An error type might provide an As method so it can be treated as if it were\n a different error type.\n\n As panics if target is not a non-nil pointer to either a type that\n implements error, or to any interface type.", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd data-go-version=\"go1.22.0\" doc=\"errors.As\" exec=\"go doc errors.As\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.65:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "The ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "errors#As", + "href": "https://pkg.go.dev/errors#As", + "target": "_blank" + }, + "filename": "errors", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "for", + "Val": "errors#As" + }, + { + "Namespace": "", + "Key": "href", + "Val": "https://pkg.go.dev/errors#As" + }, + { + "Namespace": "", + "Key": "target", + "Val": "_blank" + } + ], + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "errors.As", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ] + ], + "tag": "\u003ca for=\"errors#As\" href=\"https://pkg.go.dev/errors#As\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/errors#As" + } + ], + { + "text": " function.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 65, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-65\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "errors/as_is.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Like the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "errors#Unwrap", + "href": "https://pkg.go.dev/errors#Unwrap", + "target": "_blank" + }, + "filename": "errors/as_is.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/as_is.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "errors.Unwrap", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"errors#Unwrap\" href=\"https://pkg.go.dev/errors#Unwrap\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/errors#Unwrap" + } + ], + { + "text": " function, ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "errors#As", + "href": "https://pkg.go.dev/errors#As", + "target": "_blank" + }, + "filename": "errors/as_is.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/as_is.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "errors.As", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"errors#As\" href=\"https://pkg.go.dev/errors#As\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/errors#As" + } + ], + { + "text": " ", + "type": "hype.Text" + }, + { + "atom": "strong", + "attributes": {}, + "filename": "errors/as_is.md", + "html_node": { + "data": "strong", + "data_atom": "strong", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "also", + "type": "hype.Text" + } + ], + "tag": "\u003cstrong\u003e", + "type": "hype.Element" + }, + { + "text": " has a documented, but unpublished, interface, ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-66" + }, + "filename": "errors/as_is.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "as-interface" + } + ], + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-66" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.66", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-66\"\u003e", + "type": "hype.Link", + "url": "#listing-1-66" + } + ], + "tag": "\u003cref id=\"listing-1-66\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ", that can be implemented on custom errors.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-66", + "type": "listing" + }, + "filename": "errors/as_is.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "as-interface" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + { + "atom": "pre", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "src": "errors/src/as/errors.go#as-interface" + }, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/as/errors.go#as-interface" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "content": "type AsError interface {\n\tAs(target any) bool\n}", + "file": "errors/src/as/errors.go", + "lang": "go", + "name": "as-interface", + "start": 15, + "end": 20 + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" src=\"errors/src/as/errors.go#as-interface\"\u003e", + "type": "hype.SourceCode" + } + ] + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + }, + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.66:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "The ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "AsError", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " interface.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 66, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-66\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "errors/as_is.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "In order for the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "errors#As", + "href": "https://pkg.go.dev/errors#As", + "target": "_blank" + }, + "filename": "errors/as_is.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/as_is.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "errors.As", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"errors#As\" href=\"https://pkg.go.dev/errors#As\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/errors#As" + } + ], + { + "text": " function to work properly, we need to implement an ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/as_is.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "As", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " method on our error types. This method will be called when ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "errors#As", + "href": "https://pkg.go.dev/errors#As", + "target": "_blank" + }, + "filename": "errors/as_is.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/as_is.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "errors.As", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"errors#As\" href=\"https://pkg.go.dev/errors#As\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/errors#As" + } + ], + { + "text": " is called on our error. The ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/as_is.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "As", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " method should return ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/as_is.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "true", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " if the error matches the target, and ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/as_is.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "false", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " otherwise. If ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/as_is.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "false", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": ", we need to call ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "errors#As", + "href": "https://pkg.go.dev/errors#As", + "target": "_blank" + }, + "filename": "errors/as_is.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/as_is.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "errors.As", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"errors#As\" href=\"https://pkg.go.dev/errors#As\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/errors#As" + } + ], + { + "text": " on our error's underlying error. If ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/as_is.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "true", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": ", we can return ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/as_is.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "true", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " and set the target to the current error.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-67", + "type": "listing" + }, + "filename": "errors/as_is.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "as.example" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + { + "atom": "pre", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "src": "errors/src/as/errors.go#as" + }, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/as/errors.go#as" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "content": "func (e ErrorA) As(target any) bool {\n\tex, ok := target.(*ErrorA)\n\tif !ok {\n\t\t// if the target is not an ErrorA,\n\t\t// pass the underlying error up the chain\n\t\t// by calling errors.As with the underlying error\n\t\t// and the target error\n\t\treturn errors.As(e.err, target)\n\t}\n\n\t// set the target to the current error\n\t(*ex) = e\n\treturn true\n}", + "file": "errors/src/as/errors.go", + "lang": "go", + "name": "as", + "start": 64, + "end": 80 + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" src=\"errors/src/as/errors.go#as\"\u003e", + "type": "hype.SourceCode" + } + ] + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + }, + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.67:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "Implementing the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "AsError", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " interface.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 67, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-67\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "errors/as_is.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "It is important to note that in order to set the target to the current error, we must first dereference the target pointer. This is because the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/as_is.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "As", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " method is responsible for setting the target to the current error. If we don't dereference the target pointer, any changes we make would be lost when the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/as_is.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "As", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " method returns.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "errors/as_is.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "As we can see from the test we are able to take the wrapped error and extract the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/as_is.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "ErrorA", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " type from the error stack. The ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/as_is.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "As", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " method sets the value of ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/as_is.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "act", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " to the error in the stack and we are able to then access the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/as_is.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "ErrorA", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " type directly.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-68", + "type": "listing" + }, + "filename": "errors/as_is.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "as.test" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + { + "atom": "pre", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "src": "errors/src/as/errors_test.go#test-as" + }, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/as/errors_test.go#test-as" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "content": "func Test_As(t *testing.T) {\n\tt.Parallel()\n\n\toriginal := errors.New(\"original error\")\n\twrapped := Wrapper(original)\n\n\tact := ErrorA{}\n\n\tok := errors.As(wrapped, \u0026act)\n\tif !ok {\n\t\tt.Fatalf(\"expected %v to act as %v\", wrapped, act)\n\t}\n\n\tif act.err == nil {\n\t\tt.Fatalf(\"expected non-nil, got nil\")\n\t}\n\n}", + "file": "errors/src/as/errors_test.go", + "lang": "go", + "name": "test-as", + "start": 8, + "end": 28 + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" src=\"errors/src/as/errors_test.go#test-as\"\u003e", + "type": "hype.SourceCode" + } + ] + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + }, + { + "atom": "hr", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "hr", + "data_atom": "hr", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [], + "tag": "\u003chr\u003e", + "type": "hype.Element" + }, + [ + { + "args": [ + "go", + "test", + "-v" + ], + "atom": "cmd", + "attributes": { + "data-go-version": "go1.22.0", + "exec": "go test -v", + "src": "errors/src/as", + "test": "-v" + }, + "expected_exit": 0, + "filename": "errors", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "data-go-version", + "Val": "go1.22.0" + }, + { + "Namespace": "", + "Key": "exec", + "Val": "go test -v" + }, + { + "Namespace": "", + "Key": "src", + "Val": "src/as" + }, + { + "Namespace": "", + "Key": "test", + "Val": "-v" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "test", + "-v" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/09-errors/errors/src/as", + "duration": "3.469591791s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go test -v\n\n=== RUN Test_As\n=== PAUSE Test_As\n=== CONT Test_As\n--- PASS: Test_As (0.00s)\nPASS\nok \tdemo\t1.466s", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "=== RUN Test_As\n=== PAUSE Test_As\n=== CONT Test_As\n--- PASS: Test_As (0.00s)\nPASS\nok \tdemo\t1.466s", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "test", + "-v" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/09-errors/errors/src/as", + "duration": "3.469591791s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go test -v\n\n=== RUN Test_As\n=== PAUSE Test_As\n=== CONT Test_As\n--- PASS: Test_As (0.00s)\nPASS\nok \tdemo\t1.466s", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "=== RUN Test_As\n=== PAUSE Test_As\n=== CONT Test_As\n--- PASS: Test_As (0.00s)\nPASS\nok \tdemo\t1.466s", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd data-go-version=\"go1.22.0\" exec=\"go test -v\" src=\"errors/src/as\" test=\"-v\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.68:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "Testing the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "AsError", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " implementation.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 68, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-68\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "h2", + "attributes": {}, + "filename": "errors/as_is.md", + "html_node": { + "data": "h2", + "data_atom": "h2", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "level": 2, + "nodes": [ + { + "text": "Is", + "type": "hype.Text" + } + ], + "tag": "\u003ch2\u003e", + "type": "hype.Heading" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "errors/as_is.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "While the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "errors#As", + "href": "https://pkg.go.dev/errors#As", + "target": "_blank" + }, + "filename": "errors/as_is.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/as_is.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "errors.As", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"errors#As\" href=\"https://pkg.go.dev/errors#As\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/errors#As" + } + ], + { + "text": " function, ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-65" + }, + "filename": "errors/as_is.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "as.doc" + } + ], + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-65" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.65", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-65\"\u003e", + "type": "hype.Link", + "url": "#listing-1-65" + } + ], + "tag": "\u003cref id=\"listing-1-65\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ", is used to check for the type of an error, the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "errors#Is", + "href": "https://pkg.go.dev/errors#Is", + "target": "_blank" + }, + "filename": "errors/as_is.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/as_is.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "errors.Is", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"errors#Is\" href=\"https://pkg.go.dev/errors#Is\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/errors#Is" + } + ], + { + "text": " function, ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-69" + }, + "filename": "errors/as_is.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "is.doc" + } + ], + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-69" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.69", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-69\"\u003e", + "type": "hype.Link", + "url": "#listing-1-69" + } + ], + "tag": "\u003cref id=\"listing-1-69\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ", is used to check if an error in the error chain matches a specific error type. This provides a quick ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/as_is.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "true/false", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " check for an error type.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-69", + "type": "listing" + }, + "filename": "errors/as_is.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "is.doc" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "args": [ + "go", + "doc", + "errors.Is" + ], + "atom": "cmd", + "attributes": { + "data-go-version": "go1.22.0", + "doc": "errors.Is", + "exec": "go doc errors.Is" + }, + "expected_exit": 0, + "filename": "errors", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "data-go-version", + "Val": "go1.22.0" + }, + { + "Namespace": "", + "Key": "doc", + "Val": "errors.Is" + }, + { + "Namespace": "", + "Key": "exec", + "Val": "go doc errors.Is" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "doc", + "errors.Is" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypejs", + "duration": "1.040883208s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go doc errors.Is\n\npackage errors // import \u0026#34;errors\u0026#34;\n\nfunc Is(err, target error) bool\n Is reports whether any error in err\u0026#39;s tree matches target.\n\n The tree consists of err itself, followed by the errors obtained by\n repeatedly calling its Unwrap() error or Unwrap() []error method. When err\n wraps multiple errors, Is examines err followed by a depth-first traversal\n of its children.\n\n An error is considered to match a target if it is equal to that target or if\n it implements a method Is(error) bool such that Is(target) returns true.\n\n An error type might provide an Is method so it can be treated as equivalent\n to an existing error. For example, if MyError defines\n\n func (m MyError) Is(target error) bool { return target == fs.ErrExist }\n\n then Is(MyError{}, fs.ErrExist) returns true. See syscall.Errno.Is for an\n example in the standard library. An Is method should only shallowly compare\n err and the target and not call Unwrap on either.", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "package errors // import \"errors\"\n\nfunc Is(err, target error) bool\n Is reports whether any error in err's tree matches target.\n\n The tree consists of err itself, followed by the errors obtained by\n repeatedly calling its Unwrap() error or Unwrap() []error method. When err\n wraps multiple errors, Is examines err followed by a depth-first traversal\n of its children.\n\n An error is considered to match a target if it is equal to that target or if\n it implements a method Is(error) bool such that Is(target) returns true.\n\n An error type might provide an Is method so it can be treated as equivalent\n to an existing error. For example, if MyError defines\n\n func (m MyError) Is(target error) bool { return target == fs.ErrExist }\n\n then Is(MyError{}, fs.ErrExist) returns true. See syscall.Errno.Is for an\n example in the standard library. An Is method should only shallowly compare\n err and the target and not call Unwrap on either.", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "doc", + "errors.Is" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypejs", + "duration": "1.040883208s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go doc errors.Is\n\npackage errors // import \u0026#34;errors\u0026#34;\n\nfunc Is(err, target error) bool\n Is reports whether any error in err\u0026#39;s tree matches target.\n\n The tree consists of err itself, followed by the errors obtained by\n repeatedly calling its Unwrap() error or Unwrap() []error method. When err\n wraps multiple errors, Is examines err followed by a depth-first traversal\n of its children.\n\n An error is considered to match a target if it is equal to that target or if\n it implements a method Is(error) bool such that Is(target) returns true.\n\n An error type might provide an Is method so it can be treated as equivalent\n to an existing error. For example, if MyError defines\n\n func (m MyError) Is(target error) bool { return target == fs.ErrExist }\n\n then Is(MyError{}, fs.ErrExist) returns true. See syscall.Errno.Is for an\n example in the standard library. An Is method should only shallowly compare\n err and the target and not call Unwrap on either.", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "package errors // import \"errors\"\n\nfunc Is(err, target error) bool\n Is reports whether any error in err's tree matches target.\n\n The tree consists of err itself, followed by the errors obtained by\n repeatedly calling its Unwrap() error or Unwrap() []error method. When err\n wraps multiple errors, Is examines err followed by a depth-first traversal\n of its children.\n\n An error is considered to match a target if it is equal to that target or if\n it implements a method Is(error) bool such that Is(target) returns true.\n\n An error type might provide an Is method so it can be treated as equivalent\n to an existing error. For example, if MyError defines\n\n func (m MyError) Is(target error) bool { return target == fs.ErrExist }\n\n then Is(MyError{}, fs.ErrExist) returns true. See syscall.Errno.Is for an\n example in the standard library. An Is method should only shallowly compare\n err and the target and not call Unwrap on either.", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd data-go-version=\"go1.22.0\" doc=\"errors.Is\" exec=\"go doc errors.Is\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.69:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "The ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "errors#Is", + "href": "https://pkg.go.dev/errors#Is", + "target": "_blank" + }, + "filename": "errors", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "for", + "Val": "errors#Is" + }, + { + "Namespace": "", + "Key": "href", + "Val": "https://pkg.go.dev/errors#Is" + }, + { + "Namespace": "", + "Key": "target", + "Val": "_blank" + } + ], + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "errors.Is", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ] + ], + "tag": "\u003ca for=\"errors#Is\" href=\"https://pkg.go.dev/errors#Is\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/errors#Is" + } + ], + { + "text": " function.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 69, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-69\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "errors/as_is.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "The ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "errors#Is", + "href": "https://pkg.go.dev/errors#Is", + "target": "_blank" + }, + "filename": "errors/as_is.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/as_is.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "errors.Is", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"errors#Is\" href=\"https://pkg.go.dev/errors#Is\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/errors#Is" + } + ], + { + "text": " documentation, like ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "errors#As", + "href": "https://pkg.go.dev/errors#As", + "target": "_blank" + }, + "filename": "errors/as_is.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/as_is.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "errors.As", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"errors#As\" href=\"https://pkg.go.dev/errors#As\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/errors#As" + } + ], + { + "text": " and ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "errors#Unwrap", + "href": "https://pkg.go.dev/errors#Unwrap", + "target": "_blank" + }, + "filename": "errors/as_is.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/as_is.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "errors.Unwrap", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"errors#Unwrap\" href=\"https://pkg.go.dev/errors#Unwrap\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/errors#Unwrap" + } + ], + { + "text": ", has a documented, but unpublished, interface. This interface is defined in ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-70" + }, + "filename": "errors/as_is.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "is-interface" + } + ], + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-70" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.70", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-70\"\u003e", + "type": "hype.Link", + "url": "#listing-1-70" + } + ], + "tag": "\u003cref id=\"listing-1-70\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ".", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-70", + "type": "listing" + }, + "filename": "errors/as_is.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "is-interface" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + { + "atom": "pre", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "src": "errors/src/is/errors.go#is-interface" + }, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/is/errors.go#is-interface" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "content": "type IsError interface {\n\tIs(target error) bool\n}", + "file": "errors/src/is/errors.go", + "lang": "go", + "name": "is-interface", + "start": 22, + "end": 27 + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" src=\"errors/src/is/errors.go#is-interface\"\u003e", + "type": "hype.SourceCode" + } + ] + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + }, + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.70:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "The ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "IsError", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " interface.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 70, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-70\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "errors/as_is.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Like with ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "errors#As", + "href": "https://pkg.go.dev/errors#As", + "target": "_blank" + }, + "filename": "errors/as_is.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/as_is.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "errors.As", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"errors#As\" href=\"https://pkg.go.dev/errors#As\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/errors#As" + } + ], + { + "text": " we have to implement the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/as_is.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Is", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " method for our custom error types, ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-71" + }, + "filename": "errors/as_is.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "is.example" + } + ], + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-71" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.71", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-71\"\u003e", + "type": "hype.Link", + "url": "#listing-1-71" + } + ], + "tag": "\u003cref id=\"listing-1-71\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ". If our error types is the same type as the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/as_is.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "target", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " error then we can return ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/as_is.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "true", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": ". If the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/as_is.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "target", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " error is not a much we then need to call ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "errors#Is", + "href": "https://pkg.go.dev/errors#Is", + "target": "_blank" + }, + "filename": "errors/as_is.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/as_is.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "errors.Is", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"errors#Is\" href=\"https://pkg.go.dev/errors#Is\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/errors#Is" + } + ], + { + "text": " with our underlying error and the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/as_is.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "target", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " error so that error can be checked as well.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-71", + "type": "listing" + }, + "filename": "errors/as_is.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "is.example" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + { + "atom": "pre", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "src": "errors/src/is/errors.go#is" + }, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/is/errors.go#is" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "content": "func (e ErrorA) Is(target error) bool {\n\tif _, ok := target.(ErrorA); ok {\n\t\t// return true if target is ErrorA\n\t\treturn true\n\t}\n\n\t// if not, pass the underlying error up the chain\n\t// by calling errors.Is with the underlying error\n\t// and the target error\n\treturn errors.Is(e.err, target)\n}", + "file": "errors/src/is/errors.go", + "lang": "go", + "name": "is", + "start": 49, + "end": 62 + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" src=\"errors/src/is/errors.go#is\"\u003e", + "type": "hype.SourceCode" + } + ] + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + }, + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.71:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "Implementing the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "IsError", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " interface.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 71, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-71\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "errors/as_is.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Finally, in ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-72" + }, + "filename": "errors/as_is.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "is.test" + } + ], + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-72" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.72", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-72\"\u003e", + "type": "hype.Link", + "url": "#listing-1-72" + } + ], + "tag": "\u003cref id=\"listing-1-72\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ", we can write a test to assert that our ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/as_is.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Is", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " method works as expected.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-72", + "type": "listing" + }, + "filename": "errors/as_is.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "is.test" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + { + "atom": "pre", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "src": "errors/src/is/errors_test.go#test-is" + }, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/is/errors_test.go#test-is" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "content": "func Test_Is(t *testing.T) {\n\tt.Parallel()\n\n\toriginal := errors.New(\"original error\")\n\twrapped := Wrapper(original)\n\n\texp := ErrorB{}\n\n\tok := errors.Is(wrapped, exp)\n\tif !ok {\n\t\tt.Fatalf(\"expected %v to be %v\", wrapped, exp)\n\t}\n\n}", + "file": "errors/src/is/errors_test.go", + "lang": "go", + "name": "test-is", + "start": 8, + "end": 24 + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" src=\"errors/src/is/errors_test.go#test-is\"\u003e", + "type": "hype.SourceCode" + } + ] + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + }, + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "args": [ + "go", + "test", + "-v" + ], + "atom": "cmd", + "attributes": { + "data-go-version": "go1.22.0", + "exec": "go test -v", + "src": "errors/src/is", + "test": "-v" + }, + "expected_exit": 0, + "filename": "errors", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "data-go-version", + "Val": "go1.22.0" + }, + { + "Namespace": "", + "Key": "exec", + "Val": "go test -v" + }, + { + "Namespace": "", + "Key": "src", + "Val": "src/is" + }, + { + "Namespace": "", + "Key": "test", + "Val": "-v" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "test", + "-v" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/09-errors/errors/src/is", + "duration": "2.019886708s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go test -v\n\n=== RUN Test_Is\n=== PAUSE Test_Is\n=== CONT Test_Is\n--- PASS: Test_Is (0.00s)\nPASS\nok \tdemo\t0.423s", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "=== RUN Test_Is\n=== PAUSE Test_Is\n=== CONT Test_Is\n--- PASS: Test_Is (0.00s)\nPASS\nok \tdemo\t0.423s", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "test", + "-v" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/09-errors/errors/src/is", + "duration": "2.019886708s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go test -v\n\n=== RUN Test_Is\n=== PAUSE Test_Is\n=== CONT Test_Is\n--- PASS: Test_Is (0.00s)\nPASS\nok \tdemo\t0.423s", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "=== RUN Test_Is\n=== PAUSE Test_Is\n=== CONT Test_Is\n--- PASS: Test_Is (0.00s)\nPASS\nok \tdemo\t0.423s", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd data-go-version=\"go1.22.0\" exec=\"go test -v\" src=\"errors/src/is\" test=\"-v\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.72:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "Testing the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "IsError", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " implementation.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 72, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-72\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "tag": "\u003cpage\u003e", + "title": "Errors As/Is", + "type": "hype.Page" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "tag": "\u003cinclude src=\"errors/as_is.md\"\u003e", + "type": "hype.Include" + } + ], + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "atom": "include", + "attributes": { + "src": "errors/summary.md" + }, + "dir": "errors", + "filename": "module.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "errors/summary.md" + } + ], + "data": "include", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "page", + "attributes": {}, + "filename": "errors/summary.md", + "html_node": { + "data": "page", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "atom": "h1", + "attributes": {}, + "filename": "errors/summary.md", + "html_node": { + "data": "h1", + "data_atom": "h1", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "level": 1, + "nodes": [ + { + "text": "Stack Traces", + "type": "hype.Text" + } + ], + "tag": "\u003ch1\u003e", + "type": "hype.Heading" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "errors/summary.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Using a stack trace to debug your code can be very helpful at times. A stack trace shows where you are at in the code, and how you got there by printing a list of all calling functions.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "errors/summary.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "The ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "runtime/debug", + "href": "https://pkg.go.dev/runtime/debug", + "target": "_blank" + }, + "filename": "errors/summary.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/summary.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "runtime/debug", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"runtime/debug\" href=\"https://pkg.go.dev/runtime/debug\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/runtime/debug" + } + ], + { + "text": " package provides a couple of functions that can be use to get, or print, a stack trace. The ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "runtime/debug#Stack", + "href": "https://pkg.go.dev/runtime/debug#Stack", + "target": "_blank" + }, + "filename": "errors/summary.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/summary.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "debug.Stack", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"runtime/debug#Stack\" href=\"https://pkg.go.dev/runtime/debug#Stack\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/runtime/debug#Stack" + } + ], + { + "text": " function, ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-73" + }, + "filename": "errors/summary.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "stack.doc" + } + ], + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-73" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.73", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-73\"\u003e", + "type": "hype.Link", + "url": "#listing-1-73" + } + ], + "tag": "\u003cref id=\"listing-1-73\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ", will return a slice of bytes that represent the stack trace.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-73", + "type": "listing" + }, + "filename": "errors/summary.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "stack.doc" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "args": [ + "go", + "doc", + "runtime/debug.Stack" + ], + "atom": "cmd", + "attributes": { + "data-go-version": "go1.22.0", + "doc": "runtime/debug.Stack", + "exec": "go doc runtime/debug.Stack" + }, + "expected_exit": 0, + "filename": "errors", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "data-go-version", + "Val": "go1.22.0" + }, + { + "Namespace": "", + "Key": "doc", + "Val": "runtime/debug.Stack" + }, + { + "Namespace": "", + "Key": "exec", + "Val": "go doc runtime/debug.Stack" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "doc", + "runtime/debug.Stack" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypejs", + "duration": "1.669139458s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go doc runtime/debug.Stack\n\npackage debug // import \u0026#34;runtime/debug\u0026#34;\n\nfunc Stack() []byte\n Stack returns a formatted stack trace of the goroutine that calls it. It\n calls runtime.Stack with a large enough buffer to capture the entire trace.", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "package debug // import \"runtime/debug\"\n\nfunc Stack() []byte\n Stack returns a formatted stack trace of the goroutine that calls it. It\n calls runtime.Stack with a large enough buffer to capture the entire trace.", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "doc", + "runtime/debug.Stack" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypejs", + "duration": "1.669139458s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go doc runtime/debug.Stack\n\npackage debug // import \u0026#34;runtime/debug\u0026#34;\n\nfunc Stack() []byte\n Stack returns a formatted stack trace of the goroutine that calls it. It\n calls runtime.Stack with a large enough buffer to capture the entire trace.", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "package debug // import \"runtime/debug\"\n\nfunc Stack() []byte\n Stack returns a formatted stack trace of the goroutine that calls it. It\n calls runtime.Stack with a large enough buffer to capture the entire trace.", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd data-go-version=\"go1.22.0\" doc=\"runtime/debug.Stack\" exec=\"go doc runtime/debug.Stack\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.73:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "The ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "runtime/debug#Stack", + "href": "https://pkg.go.dev/runtime/debug#Stack", + "target": "_blank" + }, + "filename": "errors", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "for", + "Val": "runtime/debug#Stack" + }, + { + "Namespace": "", + "Key": "href", + "Val": "https://pkg.go.dev/runtime/debug#Stack" + }, + { + "Namespace": "", + "Key": "target", + "Val": "_blank" + } + ], + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "debug.Stack", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ] + ], + "tag": "\u003ca for=\"runtime/debug#Stack\" href=\"https://pkg.go.dev/runtime/debug#Stack\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/runtime/debug#Stack" + } + ], + { + "text": " function", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 73, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-73\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "errors/summary.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "The ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "runtime/debug#PrintStack", + "href": "https://pkg.go.dev/runtime/debug#PrintStack", + "target": "_blank" + }, + "filename": "errors/summary.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/summary.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "debug.PrintStack", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"runtime/debug#PrintStack\" href=\"https://pkg.go.dev/runtime/debug#PrintStack\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/runtime/debug#PrintStack" + } + ], + { + "text": " function, ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-74" + }, + "filename": "errors/summary.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "print.doc" + } + ], + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-74" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.74", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-74\"\u003e", + "type": "hype.Link", + "url": "#listing-1-74" + } + ], + "tag": "\u003cref id=\"listing-1-74\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ", will print the stack trace to the standard output.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-74", + "type": "listing" + }, + "filename": "errors/summary.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "print.doc" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "args": [ + "go", + "doc", + "runtime/debug.PrintStack" + ], + "atom": "cmd", + "attributes": { + "data-go-version": "go1.22.0", + "doc": "runtime/debug.PrintStack", + "exec": "go doc runtime/debug.PrintStack" + }, + "expected_exit": 0, + "filename": "errors", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "data-go-version", + "Val": "go1.22.0" + }, + { + "Namespace": "", + "Key": "doc", + "Val": "runtime/debug.PrintStack" + }, + { + "Namespace": "", + "Key": "exec", + "Val": "go doc runtime/debug.PrintStack" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "doc", + "runtime/debug.PrintStack" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypejs", + "duration": "996.697875ms", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go doc runtime/debug.PrintStack\n\npackage debug // import \u0026#34;runtime/debug\u0026#34;\n\nfunc PrintStack()\n PrintStack prints to standard error the stack trace returned by\n runtime.Stack.", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "package debug // import \"runtime/debug\"\n\nfunc PrintStack()\n PrintStack prints to standard error the stack trace returned by\n runtime.Stack.", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "doc", + "runtime/debug.PrintStack" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypejs", + "duration": "996.697875ms", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go doc runtime/debug.PrintStack\n\npackage debug // import \u0026#34;runtime/debug\u0026#34;\n\nfunc PrintStack()\n PrintStack prints to standard error the stack trace returned by\n runtime.Stack.", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "package debug // import \"runtime/debug\"\n\nfunc PrintStack()\n PrintStack prints to standard error the stack trace returned by\n runtime.Stack.", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd data-go-version=\"go1.22.0\" doc=\"runtime/debug.PrintStack\" exec=\"go doc runtime/debug.PrintStack\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.74:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "The ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "runtime/debug#PrintStack", + "href": "https://pkg.go.dev/runtime/debug#PrintStack", + "target": "_blank" + }, + "filename": "errors", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "for", + "Val": "runtime/debug#PrintStack" + }, + { + "Namespace": "", + "Key": "href", + "Val": "https://pkg.go.dev/runtime/debug#PrintStack" + }, + { + "Namespace": "", + "Key": "target", + "Val": "_blank" + } + ], + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "debug.PrintStack", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ] + ], + "tag": "\u003ca for=\"runtime/debug#PrintStack\" href=\"https://pkg.go.dev/runtime/debug#PrintStack\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/runtime/debug#PrintStack" + } + ], + { + "text": " function", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 74, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-74\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "errors/summary.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "In ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-75" + }, + "filename": "errors/summary.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "stack" + } + ], + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-75" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.75", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-75\"\u003e", + "type": "hype.Link", + "url": "#listing-1-75" + } + ], + "tag": "\u003cref id=\"listing-1-75\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ", we print the stack trace of a program to standard output, using ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "runtime/debug#PrintStack", + "href": "https://pkg.go.dev/runtime/debug#PrintStack", + "target": "_blank" + }, + "filename": "errors/summary.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "errors/summary.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "debug.PrintStack", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"runtime/debug#PrintStack\" href=\"https://pkg.go.dev/runtime/debug#PrintStack\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/runtime/debug#PrintStack" + } + ], + { + "text": ".", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-75", + "type": "listing" + }, + "filename": "errors/summary.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "stack" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + { + "atom": "pre", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "src": "errors/src/stack/main.go" + }, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/stack/main.go" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "text": "package main\n\nimport \u0026#34;runtime/debug\u0026#34;\n\nfunc main() {\n\tFirst()\n}\n\nfunc First() {\n\tSecond()\n}\n\nfunc Second() {\n\tThird()\n}\n\nfunc Third() {\n\tdebug.PrintStack()\n}\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" src=\"errors/src/stack/main.go\"\u003e", + "type": "hype.SourceCode" + } + ] + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + }, + { + "atom": "hr", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "hr", + "data_atom": "hr", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [], + "tag": "\u003chr\u003e", + "type": "hype.Element" + }, + [ + { + "args": [ + "go", + "run", + "." + ], + "atom": "cmd", + "attributes": { + "data-go-version": "go1.22.0", + "exec": "go run .", + "run": ".", + "src": "errors/src/stack" + }, + "expected_exit": 0, + "filename": "errors", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "data-go-version", + "Val": "go1.22.0" + }, + { + "Namespace": "", + "Key": "exec", + "Val": "go run ." + }, + { + "Namespace": "", + "Key": "run", + "Val": "." + }, + { + "Namespace": "", + "Key": "src", + "Val": "src/stack" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "run", + "." + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/09-errors/errors/src/stack", + "duration": "2.964499791s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go run .\n\ngoroutine 1 [running]:\nruntime/debug.Stack()\n\t/usr/local/go/src/runtime/debug/stack.go:24 +0x64\nruntime/debug.PrintStack()\n\t/usr/local/go/src/runtime/debug/stack.go:16 +0x1c\nmain.Third(...)\n\t/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/errors/src/stack/main.go:18\nmain.Second(...)\n\t/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/errors/src/stack/main.go:14\nmain.First(...)\n\t/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/errors/src/stack/main.go:10\nmain.main()\n\t/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/errors/src/stack/main.go:6 +0x28", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "goroutine 1 [running]:\nruntime/debug.Stack()\n\t/usr/local/go/src/runtime/debug/stack.go:24 +0x64\nruntime/debug.PrintStack()\n\t/usr/local/go/src/runtime/debug/stack.go:16 +0x1c\nmain.Third(...)\n\t/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/errors/src/stack/main.go:18\nmain.Second(...)\n\t/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/errors/src/stack/main.go:14\nmain.First(...)\n\t/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/errors/src/stack/main.go:10\nmain.main()\n\t/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/errors/src/stack/main.go:6 +0x28", + "stdout": "", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "run", + "." + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/09-errors/errors/src/stack", + "duration": "2.964499791s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go run .\n\ngoroutine 1 [running]:\nruntime/debug.Stack()\n\t/usr/local/go/src/runtime/debug/stack.go:24 +0x64\nruntime/debug.PrintStack()\n\t/usr/local/go/src/runtime/debug/stack.go:16 +0x1c\nmain.Third(...)\n\t/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/errors/src/stack/main.go:18\nmain.Second(...)\n\t/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/errors/src/stack/main.go:14\nmain.First(...)\n\t/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/errors/src/stack/main.go:10\nmain.main()\n\t/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/errors/src/stack/main.go:6 +0x28", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "goroutine 1 [running]:\nruntime/debug.Stack()\n\t/usr/local/go/src/runtime/debug/stack.go:24 +0x64\nruntime/debug.PrintStack()\n\t/usr/local/go/src/runtime/debug/stack.go:16 +0x1c\nmain.Third(...)\n\t/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/errors/src/stack/main.go:18\nmain.Second(...)\n\t/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/errors/src/stack/main.go:14\nmain.First(...)\n\t/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/errors/src/stack/main.go:10\nmain.main()\n\t/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/errors/src/stack/main.go:6 +0x28", + "stdout": "", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd data-go-version=\"go1.22.0\" exec=\"go run .\" run=\".\" src=\"errors/src/stack\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.75:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "Printing a stack trace.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 75, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-75\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "tag": "\u003cpage\u003e", + "title": "Stack Traces", + "type": "hype.Page" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "tag": "\u003cinclude src=\"errors/summary.md\"\u003e", + "type": "hype.Include" + } + ], + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "atom": "page", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "page", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "atom": "h1", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "h1", + "data_atom": "h1", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "level": 1, + "nodes": [ + { + "text": "Summary", + "type": "hype.Text" + } + ], + "tag": "\u003ch1\u003e", + "type": "hype.Heading" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "In this ", + "type": "hype.Text" + }, + { + "atom": "binding", + "attributes": { + "part": "" + }, + "filename": "module.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "part", + "Val": "" + } + ], + "data": "binding", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [], + "tag": "\u003cbinding part=\"\"\u003e", + "type": "hype.Element" + }, + { + "text": " we discussed Go's error handling in depth. We covered error handling, and creation, in our code. We learned how to create custom implementations of ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "builtin#error", + "href": "https://pkg.go.dev/builtin#error", + "target": "_blank" + }, + "filename": "module.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "error", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"builtin#error\" href=\"https://pkg.go.dev/builtin#error\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/builtin#error" + } + ], + { + "text": " interface. Next, we saw how a panic can crash an application, and we discussed various ways to recover from panics. We saw that we can use ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "errors#Unwrap", + "href": "https://pkg.go.dev/errors#Unwrap", + "target": "_blank" + }, + "filename": "module.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "errors.Unwrap", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"errors#Unwrap\" href=\"https://pkg.go.dev/errors#Unwrap\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/errors#Unwrap" + } + ], + { + "text": " to try and get the original error from a wrapped error. We also saw how to use ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "errors#As", + "href": "https://pkg.go.dev/errors#As", + "target": "_blank" + }, + "filename": "module.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "errors.As", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"errors#As\" href=\"https://pkg.go.dev/errors#As\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/errors#As" + } + ], + { + "text": " to try assert an error has a certain type in its chain, and if so, it binds the error to a variable to be used in the rest of the function. Finally, we saw how to use ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "errors#Is", + "href": "https://pkg.go.dev/errors#Is", + "target": "_blank" + }, + "filename": "module.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "errors.Is", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"errors#Is\" href=\"https://pkg.go.dev/errors#Is\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/errors#Is" + } + ], + { + "text": " to check if an error in the chain is of a certain type.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "tag": "\u003cpage\u003e", + "title": "Summary", + "type": "hype.Page" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "tag": "\u003cbody\u003e", + "type": "hype.Body" + } + ] + ], + "tag": "\u003chtml\u003e", + "type": "hype.Element" + } + ], + "tag": "", + "type": "hype.Element" + } + ], + "parser": { + "type": "hype.Parser", + "root": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/09-errors", + "section": 1, + "contents": "# Errors\n\nThis \u003cbinding part\u003e\u003c/binding\u003e will cover the benefits of how Go's error model results in more reliable code. We will cover how to handle basic errors and return errors as an interface that satisfies the error type. Additionally, concepts such as custom error types, panics, recovering from panics, and sentinel errors are also covered.\n\n\u003cinclude src=\"errors/basics.md\"\u003e\u003c/include\u003e\n\n\u003cinclude src=\"panic/panic.md\"\u003e\u003c/include\u003e\n\n\u003cinclude src=\"errors/custom.md\"\u003e\u003c/include\u003e\n\n\u003cinclude src=\"errors/wrapping.md\"\u003e\u003c/include\u003e\n\n\u003cinclude src=\"errors/as_is.md\"\u003e\u003c/include\u003e\n\n\u003cinclude src=\"errors/summary.md\"\u003e\u003c/include\u003e\n\n# Summary\n\nIn this \u003cbinding part\u003e\u003c/binding\u003e we discussed Go's error handling in depth. We covered error handling, and creation, in our code. We learned how to create custom implementations of \u003cgodoc\u003ebuiltin#error\u003c/godoc\u003e interface. Next, we saw how a panic can crash an application, and we discussed various ways to recover from panics. We saw that we can use \u003cgodoc\u003eerrors#Unwrap\u003c/godoc\u003e to try and get the original error from a wrapped error. We also saw how to use \u003cgodoc\u003eerrors#As\u003c/godoc\u003e to try assert an error has a certain type in its chain, and if so, it binds the error to a variable to be used in the rest of the function. Finally, we saw how to use \u003cgodoc\u003eerrors#Is\u003c/godoc\u003e to check if an error in the chain is of a certain type.\n" + }, + "root": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/09-errors", + "section_id": 1, + "snippets": { + "rules": { + ".go": "// %s", + ".html": "\u003c!-- %s --\u003e", + ".js": "// %s", + ".md": "\u003c!-- %s --\u003e", + ".rb": "# %s", + ".ts": "// %s" + }, + "snippets": { + "errors/src/as/errors.go": { + "as": { + "content": "func (e ErrorA) As(target any) bool {\n\tex, ok := target.(*ErrorA)\n\tif !ok {\n\t\t// if the target is not an ErrorA,\n\t\t// pass the underlying error up the chain\n\t\t// by calling errors.As with the underlying error\n\t\t// and the target error\n\t\treturn errors.As(e.err, target)\n\t}\n\n\t// set the target to the current error\n\t(*ex) = e\n\treturn true\n}", + "file": "errors/src/as/errors.go", + "lang": "go", + "name": "as", + "start": 64, + "end": 80 + }, + "as-interface": { + "content": "type AsError interface {\n\tAs(target any) bool\n}", + "file": "errors/src/as/errors.go", + "lang": "go", + "name": "as-interface", + "start": 15, + "end": 20 + }, + "errors": { + "content": "type ErrorA struct {\n\terr error\n}\n\nfunc (e ErrorA) Error() string {\n\treturn fmt.Sprintf(\"[ErrorA] %s\", e.err)\n}\n\nfunc (e ErrorA) Unwrap() error {\n\tif _, ok := e.err.(Unwrapper); ok {\n\t\treturn errors.Unwrap(e.err)\n\t}\n\n\treturn e.err\n}\n\n\nfunc (e ErrorA) Is(target error) bool {\n\tif _, ok := target.(ErrorA); ok {\n\t\t// return true if target is ErrorA\n\t\treturn true\n\t}\n\n\t// if not, pass the underlying error up the chain\n\t// by calling errors.Is with the underlying error\n\t// and the target error\n\treturn errors.Is(e.err, target)\n}\n\n\nfunc (e ErrorA) As(target any) bool {\n\tex, ok := target.(*ErrorA)\n\tif !ok {\n\t\t// if the target is not an ErrorA,\n\t\t// pass the underlying error up the chain\n\t\t// by calling errors.As with the underlying error\n\t\t// and the target error\n\t\treturn errors.As(e.err, target)\n\t}\n\n\t// set the target to the current error\n\t(*ex) = e\n\treturn true\n}\n\n\ntype ErrorB struct {\n\terr error\n}\n\nfunc (e ErrorB) Error() string {\n\treturn fmt.Sprintf(\"[ErrorB] %s\", e.err)\n}\n\nfunc (e ErrorB) Unwrap() error {\n\tif _, ok := e.err.(Unwrapper); ok {\n\t\treturn errors.Unwrap(e.err)\n\t}\n\n\treturn e.err\n}\n\nfunc (e ErrorB) Is(target error) bool {\n\tif _, ok := target.(ErrorB); ok {\n\t\treturn true\n\t}\n\treturn errors.Is(e.err, target)\n}\n\nfunc (e ErrorB) As(target any) bool {\n\tex, ok := target.(*ErrorB)\n\tif !ok {\n\t\treturn errors.As(e.err, target)\n\t}\n\n\t(*ex) = e\n\treturn true\n}\n\ntype ErrorC struct {\n\terr error\n}\n\nfunc (e ErrorC) Error() string {\n\treturn fmt.Sprintf(\"[ErrorC] %s\", e.err)\n}\n\nfunc (e ErrorC) Unwrap() error {\n\tif _, ok := e.err.(Unwrapper); ok {\n\t\treturn errors.Unwrap(e.err)\n\t}\n\n\treturn e.err\n}\n\nfunc (e ErrorC) Is(target error) bool {\n\tif _, ok := target.(ErrorC); ok {\n\t\treturn true\n\t}\n\treturn errors.Is(e.err, target)\n}\n\nfunc (e ErrorC) As(target any) bool {\n\tex, ok := target.(*ErrorC)\n\tif !ok {\n\t\treturn errors.As(e.err, target)\n\t}\n\n\t(*ex) = e\n\treturn true\n}", + "file": "errors/src/as/errors.go", + "lang": "go", + "name": "errors", + "start": 29, + "end": 148 + }, + "is": { + "content": "func (e ErrorA) Is(target error) bool {\n\tif _, ok := target.(ErrorA); ok {\n\t\t// return true if target is ErrorA\n\t\treturn true\n\t}\n\n\t// if not, pass the underlying error up the chain\n\t// by calling errors.Is with the underlying error\n\t// and the target error\n\treturn errors.Is(e.err, target)\n}", + "file": "errors/src/as/errors.go", + "lang": "go", + "name": "is", + "start": 49, + "end": 62 + }, + "is-interface": { + "content": "type IsError interface {\n\tIs(target error) bool\n}", + "file": "errors/src/as/errors.go", + "lang": "go", + "name": "is-interface", + "start": 22, + "end": 27 + }, + "unwrap": { + "content": "func (e ErrorA) Unwrap() error {\n\tif _, ok := e.err.(Unwrapper); ok {\n\t\treturn errors.Unwrap(e.err)\n\t}\n\n\treturn e.err\n}", + "file": "errors/src/as/errors.go", + "lang": "go", + "name": "unwrap", + "start": 38, + "end": 47 + }, + "unwrapper.interface": { + "content": "type Unwrapper interface {\n\tUnwrap() error\n}", + "file": "errors/src/as/errors.go", + "lang": "go", + "name": "unwrapper.interface", + "start": 8, + "end": 13 + }, + "wrapper-short": { + "content": "// Wrapper wraps an error with a bunch of\n// other errors.\n// ex. Wrapper(original) #=\u003e ErrorC -\u003e ErrorB -\u003e ErrorA -\u003e original\nfunc Wrapper(original error) error {\n\toriginal = ErrorA{original}\n\toriginal = ErrorB{original}\n\toriginal = ErrorC{original}\n\treturn original\n}", + "file": "errors/src/as/errors.go", + "lang": "go", + "name": "wrapper-short", + "start": 150, + "end": 161 + } + }, + "errors/src/as/errors_test.go": { + "test-as": { + "content": "func Test_As(t *testing.T) {\n\tt.Parallel()\n\n\toriginal := errors.New(\"original error\")\n\twrapped := Wrapper(original)\n\n\tact := ErrorA{}\n\n\tok := errors.As(wrapped, \u0026act)\n\tif !ok {\n\t\tt.Fatalf(\"expected %v to act as %v\", wrapped, act)\n\t}\n\n\tif act.err == nil {\n\t\tt.Fatalf(\"expected non-nil, got nil\")\n\t}\n\n}", + "file": "errors/src/as/errors_test.go", + "lang": "go", + "name": "test-as", + "start": 8, + "end": 28 + } + }, + "errors/src/custom-table-err/errors.go": { + "err-table-not-found": { + "content": "type ErrTableNotFound struct {\n\tTable string\n\tOccurredAt time.Time\n}\n\nfunc (e ErrTableNotFound) Error() string {\n\treturn fmt.Sprintf(\"[%s] table not found %s\", e.OccurredAt, e.Table)\n}", + "file": "errors/src/custom-table-err/errors.go", + "lang": "go", + "name": "err-table-not-found", + "start": 8, + "end": 18 + } + }, + "errors/src/custom-table-err/store.go": { + "all": { + "content": "// All returns all models in the store for the given table name.\n// If no models exist, an error is returned.\nfunc (s *Store) All(tn string) ([]Model, error) {\n\tdb := s.data\n\n\t// if the underlying data is nil, return an error\n\tif db == nil {\n\t\treturn nil, fmt.Errorf(\"no data\")\n\t}\n\n\t// check to make sure table exists\n\tmods, ok := db[tn]\n\n\t// if table doesn't exist, return an error\n\tif !ok {\n\t\treturn nil, ErrTableNotFound{\n\t\t\tTable: tn,\n\t\t\tOccurredAt: time.Now(),\n\t\t}\n\t}\n\n\t// return the slice of models\n\treturn mods, nil\n}", + "file": "errors/src/custom-table-err/store.go", + "lang": "go", + "name": "all", + "start": 21, + "end": 47 + }, + "store": { + "content": "// Model is a key/value pair representing a model in the store.\n// e.g. {\"id\": 1, \"name\": \"bob\"}\ntype Model map[string]any\n\n// Store is a table based key/value store.\ntype Store struct {\n\tdata map[string][]Model\n}", + "file": "errors/src/custom-table-err/store.go", + "lang": "go", + "name": "store", + "start": 8, + "end": 19 + } + }, + "errors/src/custom-table-err/store_test.go": { + "test": { + "content": "func Test_Store_All_NoTable(t *testing.T) {\n\tt.Parallel()\n\n\ts := \u0026Store{\n\t\tdata: map[string][]Model{},\n\t}\n\n\t_, err := s.All(\"users\")\n\tif err == nil {\n\t\tt.Fatal(\"expected error, got nil\")\n\t}\n\n\texp := \"users\"\n\te, ok := err.(ErrTableNotFound)\n\tif !ok {\n\t\tt.Fatalf(\"expected ErrTableNotFound, got %T\", err)\n\t}\n\n\tact := e.Table\n\tif act != exp {\n\t\tt.Fatalf(\"expected %q, got %q\", exp, act)\n\t}\n\n\tif e.OccurredAt.IsZero() {\n\t\tt.Fatal(\"expected non-zero time\")\n\t}\n}", + "file": "errors/src/custom-table-err/store_test.go", + "lang": "go", + "name": "test", + "start": 5, + "end": 36 + }, + "test_error": { + "content": "exp := \"users\"\ne, ok := err.(ErrTableNotFound)\nif !ok {\n\tt.Fatalf(\"expected ErrTableNotFound, got %T\", err)\n}\n\nact := e.Table\nif act != exp {\n\tt.Fatalf(\"expected %q, got %q\", exp, act)\n}\n\nif e.OccurredAt.IsZero() {\n\tt.Fatal(\"expected non-zero time\")\n}", + "file": "errors/src/custom-table-err/store_test.go", + "lang": "go", + "name": "test_error", + "start": 18, + "end": 33 + } + }, + "errors/src/custom/store.go": { + "all": { + "content": "// All returns all models in the store for the given table name.\n// If no models exist, an error is returned.\nfunc (s *Store) All(tn string) ([]Model, error) {\n\tdb := s.data\n\n\t// if the underlying data is nil, return an error\n\tif db == nil {\n\t\treturn nil, fmt.Errorf(\"no data\")\n\t}\n\n\t// check to make sure table exists\n\tmods, ok := db[tn]\n\n\t// if table doesn't exist, return an error\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"table %s not found\", tn)\n\t}\n\n\t// return the slice of models\n\treturn mods, nil\n}", + "file": "errors/src/custom/store.go", + "lang": "go", + "name": "all", + "start": 18, + "end": 41 + }, + "store": { + "content": "// Model is a key/value pair representing a model in the store.\n// e.g. {\"id\": 1, \"name\": \"bob\"}\ntype Model map[string]any\n\n// Store is a table based key/value store.\ntype Store struct {\n\tdata map[string][]Model\n}", + "file": "errors/src/custom/store.go", + "lang": "go", + "name": "store", + "start": 5, + "end": 16 + } + }, + "errors/src/custom/store_test.go": { + "test": { + "content": "func Test_Store_All_NoTable(t *testing.T) {\n\tt.Parallel()\n\n\ts := \u0026Store{\n\t\tdata: map[string][]Model{},\n\t}\n\n\t_, err := s.All(\"users\")\n\tif err == nil {\n\t\tt.Fatal(\"expected error, got nil\")\n\t}\n\n\texp := \"table users not found\"\n\tact := err.Error()\n\tif act != exp {\n\t\tt.Fatalf(\"expected %q, got %q\", exp, act)\n\t}\n}", + "file": "errors/src/custom/store_test.go", + "lang": "go", + "name": "test", + "start": 5, + "end": 27 + }, + "test_error": { + "content": "exp := \"table users not found\"\nact := err.Error()\nif act != exp {\n\tt.Fatalf(\"expected %q, got %q\", exp, act)\n}", + "file": "errors/src/custom/store_test.go", + "lang": "go", + "name": "test_error", + "start": 18, + "end": 24 + } + }, + "errors/src/handling-java/main.java": { + "example": { + "content": "public static void main(String args[]) {\n try {\n // Open the file\n FileInputStream fstream = new FileInputStream(\"example.txt\");\n\n // Get the object of DataInputStream\n DataInputStream in = new DataInputStream(fstream);\n BufferedReader br = new BufferedReader(new InputStreamReader(in));\n String strLine;\n\n // Read File Line By Line\n while ((strLine = br.readLine()) != null) {\n // Print the content on the console\n System.out.println(strLine);\n }\n\n // Close the input stream\n in.close();\n } catch (IOException e) {\n System.err.println(\"IO Error: \" + e.getMessage());\n } catch (Exception e) {\n // Catch exception if any\n System.err.println(\"Error: \" + e.getMessage());\n }\n}", + "file": "errors/src/handling-java/main.java", + "lang": "java", + "name": "example", + "start": 5, + "end": 31 + } + }, + "errors/src/handling/main.go": { + "example": { + "content": "func readFile() error {\n\n\t// open the file\n\tf, err := os.Open(\"example.txt\")\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// close the file when done\n\tdefer f.Close()\n\n\t// open buffered scanner with file\n\tscanner := bufio.NewScanner(f)\n\n\t// scan through each line of the file\n\tfor scanner.Scan() {\n\n\t\t// print line to the console\n\t\tfmt.Println(scanner.Text())\n\t}\n\n\t// if there was an error while scanning\n\t// return the error to the calling function\n\tif err := scanner.Err(); err != nil {\n\t\treturn err\n\t}\n\n\t// everything was good, return nil\n\treturn nil\n}", + "file": "errors/src/handling/main.go", + "lang": "go", + "name": "example", + "start": 17, + "end": 49 + } + }, + "errors/src/is/errors.go": { + "as": { + "content": "func (e ErrorA) As(target any) bool {\n\tex, ok := target.(*ErrorA)\n\tif !ok {\n\t\t// if the target is not an ErrorA,\n\t\t// pass the underlying error up the chain\n\t\t// by calling errors.As with the underlying error\n\t\t// and the target error\n\t\treturn errors.As(e.err, target)\n\t}\n\n\t// set the target to the current error\n\t(*ex) = e\n\treturn true\n}", + "file": "errors/src/is/errors.go", + "lang": "go", + "name": "as", + "start": 64, + "end": 80 + }, + "as-interface": { + "content": "type AsError interface {\n\tAs(target any) bool\n}", + "file": "errors/src/is/errors.go", + "lang": "go", + "name": "as-interface", + "start": 15, + "end": 20 + }, + "errors": { + "content": "type ErrorA struct {\n\terr error\n}\n\nfunc (e ErrorA) Error() string {\n\treturn fmt.Sprintf(\"[ErrorA] %s\", e.err)\n}\n\nfunc (e ErrorA) Unwrap() error {\n\tif _, ok := e.err.(Unwrapper); ok {\n\t\treturn errors.Unwrap(e.err)\n\t}\n\n\treturn e.err\n}\n\n\nfunc (e ErrorA) Is(target error) bool {\n\tif _, ok := target.(ErrorA); ok {\n\t\t// return true if target is ErrorA\n\t\treturn true\n\t}\n\n\t// if not, pass the underlying error up the chain\n\t// by calling errors.Is with the underlying error\n\t// and the target error\n\treturn errors.Is(e.err, target)\n}\n\n\nfunc (e ErrorA) As(target any) bool {\n\tex, ok := target.(*ErrorA)\n\tif !ok {\n\t\t// if the target is not an ErrorA,\n\t\t// pass the underlying error up the chain\n\t\t// by calling errors.As with the underlying error\n\t\t// and the target error\n\t\treturn errors.As(e.err, target)\n\t}\n\n\t// set the target to the current error\n\t(*ex) = e\n\treturn true\n}\n\n\ntype ErrorB struct {\n\terr error\n}\n\nfunc (e ErrorB) Error() string {\n\treturn fmt.Sprintf(\"[ErrorB] %s\", e.err)\n}\n\nfunc (e ErrorB) Unwrap() error {\n\tif _, ok := e.err.(Unwrapper); ok {\n\t\treturn errors.Unwrap(e.err)\n\t}\n\n\treturn e.err\n}\n\nfunc (e ErrorB) Is(target error) bool {\n\tif _, ok := target.(ErrorB); ok {\n\t\treturn true\n\t}\n\treturn errors.Is(e.err, target)\n}\n\nfunc (e ErrorB) As(target any) bool {\n\tex, ok := target.(*ErrorB)\n\tif !ok {\n\t\treturn errors.As(e.err, target)\n\t}\n\n\t(*ex) = e\n\treturn true\n}\n\ntype ErrorC struct {\n\terr error\n}\n\nfunc (e ErrorC) Error() string {\n\treturn fmt.Sprintf(\"[ErrorC] %s\", e.err)\n}\n\nfunc (e ErrorC) Unwrap() error {\n\tif _, ok := e.err.(Unwrapper); ok {\n\t\treturn errors.Unwrap(e.err)\n\t}\n\n\treturn e.err\n}\n\nfunc (e ErrorC) Is(target error) bool {\n\tif _, ok := target.(ErrorC); ok {\n\t\treturn true\n\t}\n\treturn errors.Is(e.err, target)\n}\n\nfunc (e ErrorC) As(target any) bool {\n\tex, ok := target.(*ErrorC)\n\tif !ok {\n\t\treturn errors.As(e.err, target)\n\t}\n\n\t(*ex) = e\n\treturn true\n}", + "file": "errors/src/is/errors.go", + "lang": "go", + "name": "errors", + "start": 29, + "end": 148 + }, + "is": { + "content": "func (e ErrorA) Is(target error) bool {\n\tif _, ok := target.(ErrorA); ok {\n\t\t// return true if target is ErrorA\n\t\treturn true\n\t}\n\n\t// if not, pass the underlying error up the chain\n\t// by calling errors.Is with the underlying error\n\t// and the target error\n\treturn errors.Is(e.err, target)\n}", + "file": "errors/src/is/errors.go", + "lang": "go", + "name": "is", + "start": 49, + "end": 62 + }, + "is-interface": { + "content": "type IsError interface {\n\tIs(target error) bool\n}", + "file": "errors/src/is/errors.go", + "lang": "go", + "name": "is-interface", + "start": 22, + "end": 27 + }, + "unwrap": { + "content": "func (e ErrorA) Unwrap() error {\n\tif _, ok := e.err.(Unwrapper); ok {\n\t\treturn errors.Unwrap(e.err)\n\t}\n\n\treturn e.err\n}", + "file": "errors/src/is/errors.go", + "lang": "go", + "name": "unwrap", + "start": 38, + "end": 47 + }, + "unwrapper.interface": { + "content": "type Unwrapper interface {\n\tUnwrap() error\n}", + "file": "errors/src/is/errors.go", + "lang": "go", + "name": "unwrapper.interface", + "start": 8, + "end": 13 + }, + "wrapper-short": { + "content": "// Wrapper wraps an error with a bunch of\n// other errors.\n// ex. Wrapper(original) #=\u003e ErrorC -\u003e ErrorB -\u003e ErrorA -\u003e original\nfunc Wrapper(original error) error {\n\toriginal = ErrorA{original}\n\toriginal = ErrorB{original}\n\toriginal = ErrorC{original}\n\treturn original\n}", + "file": "errors/src/is/errors.go", + "lang": "go", + "name": "wrapper-short", + "start": 150, + "end": 161 + } + }, + "errors/src/is/errors_test.go": { + "test-is": { + "content": "func Test_Is(t *testing.T) {\n\tt.Parallel()\n\n\toriginal := errors.New(\"original error\")\n\twrapped := Wrapper(original)\n\n\texp := ErrorB{}\n\n\tok := errors.Is(wrapped, exp)\n\tif !ok {\n\t\tt.Fatalf(\"expected %v to be %v\", wrapped, exp)\n\t}\n\n}", + "file": "errors/src/is/errors_test.go", + "lang": "go", + "name": "test-is", + "start": 8, + "end": 24 + } + }, + "errors/src/newing/main.go": { + "basic": { + "content": "err = errors.New(\"error executing command\")", + "file": "errors/src/newing/main.go", + "lang": "go", + "name": "basic", + "start": 22, + "end": 24 + }, + "errorf": { + "content": "err = fmt.Errorf(\"error at %s\", time.Now())", + "file": "errors/src/newing/main.go", + "lang": "go", + "name": "errorf", + "start": 12, + "end": 14 + }, + "new": { + "content": "err = errors.New(fmt.Sprintf(\"error at %s\", time.Now()))", + "file": "errors/src/newing/main.go", + "lang": "go", + "name": "new", + "start": 18, + "end": 20 + } + }, + "errors/src/using/using.go": { + "example": { + "content": "func Get(key string) (string, error) {\n\tm := map[string]string{\n\t\t\"a\": \"A\",\n\t\t\"b\": \"B\",\n\t}\n\n\tif v, ok := m[key]; ok {\n\t\treturn v, nil\n\t}\n\n\treturn \"\", fmt.Errorf(\"no key found %s\", key)\n}", + "file": "errors/src/using/using.go", + "lang": "go", + "name": "example", + "start": 5, + "end": 19 + } + }, + "errors/src/using/using_test.go": { + "test": { + "content": "func Test_Get(t *testing.T) {\n\tt.Parallel()\n\n\tact, err := Get(\"a\")\n\tif err != nil {\n\t\tt.Fatalf(\"expect no error, got %s\", err)\n\t}\n\n\texp := \"A\"\n\tif act != exp {\n\t\tt.Fatalf(\"expected %s, got %s\", exp, act)\n\t}\n\n\t_, err = Get(\"?\")\n\tif err == nil {\n\t\tt.Fatalf(\"expected an error, got nil\")\n\t}\n}", + "file": "errors/src/using/using_test.go", + "lang": "go", + "name": "test", + "start": 5, + "end": 25 + } + }, + "errors/src/wrapped-broken/errors.go": { + "errors": { + "content": "type ErrorA struct {\n\terr error\n}\n\nfunc (e ErrorA) Error() string {\n\treturn fmt.Sprintf(\"[ErrorA] %s\", e.err)\n}\n\nfunc (e ErrorA) Unwrap() error {\n\treturn errors.Unwrap(e.err)\n}\n\n\ntype ErrorB struct {\n\terr error\n}\n\nfunc (e ErrorB) Error() string {\n\treturn fmt.Sprintf(\"[ErrorB] %s\", e.err)\n}\n\nfunc (e ErrorB) Unwrap() error {\n\treturn errors.Unwrap(e.err)\n}\n\ntype ErrorC struct {\n\terr error\n}\n\nfunc (e ErrorC) Error() string {\n\treturn fmt.Sprintf(\"[ErrorC] %s\", e.err)\n}\n\nfunc (e ErrorC) Unwrap() error {\n\treturn errors.Unwrap(e.err)\n}", + "file": "errors/src/wrapped-broken/errors.go", + "lang": "go", + "name": "errors", + "start": 15, + "end": 55 + }, + "interface": { + "content": "type Unwrapper interface {\n\tUnwrap() error\n}", + "file": "errors/src/wrapped-broken/errors.go", + "lang": "go", + "name": "interface", + "start": 8, + "end": 13 + }, + "unwrap": { + "content": "func (e ErrorA) Unwrap() error {\n\treturn errors.Unwrap(e.err)\n}", + "file": "errors/src/wrapped-broken/errors.go", + "lang": "go", + "name": "unwrap", + "start": 24, + "end": 29 + }, + "wrapper-long": { + "content": "// WrapperLong wraps an error with a bunch of\n// other errors.\n// ex. WrapperLong(original) #=\u003e ErrorC -\u003e ErrorB -\u003e ErrorA -\u003e original\nfunc WrapperLong(original error) error {\n\treturn ErrorC{\n\t\terr: ErrorB{\n\t\t\terr: ErrorA{\n\t\t\t\terr: original,\n\t\t\t},\n\t\t},\n\t}\n}", + "file": "errors/src/wrapped-broken/errors.go", + "lang": "go", + "name": "wrapper-long", + "start": 70, + "end": 84 + }, + "wrapper-short": { + "content": "// Wrapper wraps an error with a bunch of\n// other errors.\n// ex. Wrapper(original) #=\u003e ErrorC -\u003e ErrorB -\u003e ErrorA -\u003e original\nfunc Wrapper(original error) error {\n\toriginal = ErrorA{original}\n\toriginal = ErrorB{original}\n\toriginal = ErrorC{original}\n\treturn original\n}", + "file": "errors/src/wrapped-broken/errors.go", + "lang": "go", + "name": "wrapper-short", + "start": 57, + "end": 68 + } + }, + "errors/src/wrapped-error/store.go": { + "all": { + "content": "// All returns all models in the store for the given table name.\n// If no models exist, an error is returned.\nfunc (s *Store) All(tn string) ([]Model, error) {\n\tdb := s.data\n\n\t// if the underlying data is nil, return an error\n\tif db == nil {\n\t\treturn nil, fmt.Errorf(\"no data\")\n\t}\n\n\t// check to make sure table exists\n\tmods, ok := db[tn]\n\n\t// if table doesn't exist, return an error\n\tif !ok {\n\t\terr := ErrTableNotFound{\n\t\t\tTable: tn,\n\t\t\tOccurredAt: time.Now(),\n\t\t}\n\t\treturn nil, fmt.Errorf(\"[Store.All] %w\", err)\n\t}\n\n\t// return the slice of models\n\treturn mods, nil\n}", + "file": "errors/src/wrapped-error/store.go", + "lang": "go", + "name": "all", + "start": 21, + "end": 48 + }, + "store": { + "content": "// Model is a key/value pair representing a model in the store.\n// e.g. {\"id\": 1, \"name\": \"bob\"}\ntype Model map[string]any\n\n// Store is a table based key/value store.\ntype Store struct {\n\tdata map[string][]Model\n}", + "file": "errors/src/wrapped-error/store.go", + "lang": "go", + "name": "store", + "start": 8, + "end": 19 + } + }, + "errors/src/wrapped-error/store_test.go": { + "test": { + "content": "func Test_Store_All_NoTable(t *testing.T) {\n\tt.Parallel()\n\n\ts := \u0026Store{\n\t\tdata: map[string][]Model{},\n\t}\n\n\t_, err := s.All(\"users\")\n\tif err == nil {\n\t\tt.Fatal(\"expected error, got nil\")\n\t}\n\n\texp := \"users\"\n\te, ok := err.(ErrTableNotFound)\n\tif !ok {\n\t\tt.Fatalf(\"expected ErrTableNotFound, got %T\", err)\n\t}\n\n\tact := e.Table\n\tif act != exp {\n\t\tt.Fatalf(\"expected %q, got %q\", exp, act)\n\t}\n\n\tif e.OccurredAt.IsZero() {\n\t\tt.Fatal(\"expected non-zero time\")\n\t}\n}", + "file": "errors/src/wrapped-error/store_test.go", + "lang": "go", + "name": "test", + "start": 5, + "end": 34 + } + }, + "errors/src/wrapped-fixed/store_test.go": { + "test": { + "content": "func Test_Store_All_NoTable(t *testing.T) {\n\tt.Parallel()\n\n\ts := \u0026Store{\n\t\tdata: map[string][]Model{},\n\t}\n\n\t_, err := s.All(\"users\")\n\tif err == nil {\n\t\tt.Fatal(\"expected error, got nil\")\n\t}\n\n\t// unwrap the error\n\terr = errors.Unwrap(err)\n\n\texp := \"users\"\n\te, ok := err.(ErrTableNotFound)\n\tif !ok {\n\t\tt.Fatalf(\"expected ErrTableNotFound, got %T\", err)\n\t}\n\n\tact := e.Table\n\tif act != exp {\n\t\tt.Fatalf(\"expected %q, got %q\", exp, act)\n\t}\n\n\tif e.OccurredAt.IsZero() {\n\t\tt.Fatal(\"expected non-zero time\")\n\t}\n}", + "file": "errors/src/wrapped-fixed/store_test.go", + "lang": "go", + "name": "test", + "start": 8, + "end": 40 + } + }, + "errors/src/wrapped/errors.go": { + "errors": { + "content": "type ErrorA struct {\n\terr error\n}\n\nfunc (e ErrorA) Error() string {\n\treturn fmt.Sprintf(\"[ErrorA] %s\", e.err)\n}\n\nfunc (e ErrorA) Unwrap() error {\n\tif _, ok := e.err.(Unwrapper); ok {\n\t\treturn errors.Unwrap(e.err)\n\t}\n\n\treturn e.err\n}\n\n\ntype ErrorB struct {\n\terr error\n}\n\nfunc (e ErrorB) Error() string {\n\treturn fmt.Sprintf(\"[ErrorB] %s\", e.err)\n}\n\nfunc (e ErrorB) Unwrap() error {\n\tif _, ok := e.err.(Unwrapper); ok {\n\t\treturn errors.Unwrap(e.err)\n\t}\n\n\treturn e.err\n}\n\ntype ErrorC struct {\n\terr error\n}\n\nfunc (e ErrorC) Error() string {\n\treturn fmt.Sprintf(\"[ErrorC] %s\", e.err)\n}\n\nfunc (e ErrorC) Unwrap() error {\n\tif _, ok := e.err.(Unwrapper); ok {\n\t\treturn errors.Unwrap(e.err)\n\t}\n\n\treturn e.err\n}", + "file": "errors/src/wrapped/errors.go", + "lang": "go", + "name": "errors", + "start": 15, + "end": 67 + }, + "interface": { + "content": "type Unwrapper interface {\n\tUnwrap() error\n}", + "file": "errors/src/wrapped/errors.go", + "lang": "go", + "name": "interface", + "start": 8, + "end": 13 + }, + "unwrap": { + "content": "func (e ErrorA) Unwrap() error {\n\tif _, ok := e.err.(Unwrapper); ok {\n\t\treturn errors.Unwrap(e.err)\n\t}\n\n\treturn e.err\n}", + "file": "errors/src/wrapped/errors.go", + "lang": "go", + "name": "unwrap", + "start": 24, + "end": 33 + }, + "wrapper-long": { + "content": "// WrapperLong wraps an error with a bunch of\n// other errors.\n// ex. WrapperLong(original) #=\u003e ErrorC -\u003e ErrorB -\u003e ErrorA -\u003e original\nfunc WrapperLong(original error) error {\n\treturn ErrorC{\n\t\terr: ErrorB{\n\t\t\terr: ErrorA{\n\t\t\t\terr: original,\n\t\t\t},\n\t\t},\n\t}\n}", + "file": "errors/src/wrapped/errors.go", + "lang": "go", + "name": "wrapper-long", + "start": 82, + "end": 96 + }, + "wrapper-short": { + "content": "// Wrapper wraps an error with a bunch of\n// other errors.\n// ex. Wrapper(original) #=\u003e ErrorC -\u003e ErrorB -\u003e ErrorA -\u003e original\nfunc Wrapper(original error) error {\n\toriginal = ErrorA{original}\n\toriginal = ErrorB{original}\n\toriginal = ErrorC{original}\n\treturn original\n}", + "file": "errors/src/wrapped/errors.go", + "lang": "go", + "name": "wrapper-short", + "start": 69, + "end": 80 + } + }, + "errors/src/wrapping-error/errors.go": { + "errors": { + "content": "type ErrorA struct {\n\terr error\n}\n\nfunc (e ErrorA) Error() string {\n\treturn fmt.Sprintf(\"[ErrorA] %s\", e.err)\n}\n\ntype ErrorB struct {\n\terr error\n}\n\nfunc (e ErrorB) Error() string {\n\treturn fmt.Sprintf(\"[ErrorB] %s\", e.err)\n}\n\ntype ErrorC struct {\n\terr error\n}\n\nfunc (e ErrorC) Error() string {\n\treturn fmt.Sprintf(\"[ErrorC] %s\", e.err)\n}", + "file": "errors/src/wrapping-error/errors.go", + "lang": "go", + "name": "errors", + "start": 5, + "end": 30 + }, + "wrapper-long": { + "content": "// WrapperLong wraps an error with a bunch of\n// other errors.\n// ex. WrapperLong(original) #=\u003e ErrorC -\u003e ErrorB -\u003e ErrorA -\u003e original\nfunc WrapperLong(original error) error {\n\treturn ErrorC{\n\t\terr: ErrorB{\n\t\t\terr: ErrorA{\n\t\t\t\terr: original,\n\t\t\t},\n\t\t},\n\t}\n}", + "file": "errors/src/wrapping-error/errors.go", + "lang": "go", + "name": "wrapper-long", + "start": 45, + "end": 59 + }, + "wrapper-short": { + "content": "// Wrapper wraps an error with a bunch of\n// other errors.\n// ex. Wrapper(original) #=\u003e ErrorC -\u003e ErrorB -\u003e ErrorA -\u003e original\nfunc Wrapper(original error) error {\n\toriginal = ErrorA{original}\n\toriginal = ErrorB{original}\n\toriginal = ErrorC{original}\n\treturn original\n}", + "file": "errors/src/wrapping-error/errors.go", + "lang": "go", + "name": "wrapper-short", + "start": 32, + "end": 43 + } + }, + "errors/src/wrapping-error/errors_test.go": { + "test-unwrap": { + "content": "func Test_Unwrap(t *testing.T) {\n\tt.Parallel()\n\n\toriginal := errors.New(\"original error\")\n\twrapped := Wrapper(original)\n\n\tunwrapped := errors.Unwrap(wrapped)\n\tif unwrapped != original {\n\t\tt.Fatalf(\"expected %v, got %v\", original, unwrapped)\n\t}\n\n}", + "file": "errors/src/wrapping-error/errors_test.go", + "lang": "go", + "name": "test-unwrap", + "start": 23, + "end": 37 + }, + "test-wrapper": { + "content": "func Test_Wrapper(t *testing.T) {\n\tt.Parallel()\n\n\toriginal := errors.New(\"original error\")\n\twrapped := Wrapper(original)\n\n\t_, ok := wrapped.(ErrorC)\n\tif !ok {\n\t\tt.Fatalf(\"expected ErrorC, got %T\", wrapped)\n\t}\n}", + "file": "errors/src/wrapping-error/errors_test.go", + "lang": "go", + "name": "test-wrapper", + "start": 8, + "end": 21 + } + }, + "panic/src/assert/broken/main.go": { + "example": { + "content": "func main() {\n\n\t// create a buffer\n\t// to write to\n\tbb := \u0026bytes.Buffer{}\n\n\t// data to be written\n\tdata := []byte(\"Hello, world!\")\n\n\t// call WriteToFile\n\t// passing the buffer\n\t// and the data\n\terr := WriteToFile(bb, data)\n\n\t// check for errors\n\tif err != nil {\n\t\tfmt.Println(err)\n\t\tos.Exit(1)\n\t}\n}", + "file": "panic/src/assert/broken/main.go", + "lang": "go", + "name": "example", + "start": 10, + "end": 32 + }, + "write": { + "content": "func WriteToFile(w io.Writer, data []byte) error {\n\n\t// assert that w is a file\n\tf := w.(*os.File)\n\n\t// defer closing the file\n\tdefer f.Close()\n\n\t// log the file name\n\tfmt.Printf(\"writing to file %s\\n\", f.Name())\n\n\t// write the data\n\t_, err := f.Write(data)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}", + "file": "panic/src/assert/broken/main.go", + "lang": "go", + "name": "write", + "start": 34, + "end": 55 + } + }, + "panic/src/assert/fixed/main.go": { + "example": { + "content": "func main() {\n\n\t// create a buffer\n\t// to write to\n\tbb := \u0026bytes.Buffer{}\n\n\t// data to be written\n\tdata := []byte(\"Hello, world!\")\n\n\t// call WriteToFile\n\t// passing the buffer\n\t// and the data\n\terr := WriteToFile(bb, data)\n\n\t// check for errors\n\tif err != nil {\n\t\tfmt.Println(err)\n\t\tos.Exit(1)\n\t}\n}", + "file": "panic/src/assert/fixed/main.go", + "lang": "go", + "name": "example", + "start": 10, + "end": 32 + }, + "write": { + "content": "func WriteToFile(w io.Writer, data []byte) error {\n\n\t// assert that w is a file\n\tf, ok := w.(*os.File)\n\n\t// check the assertion was successful\n\tif !ok {\n\t\treturn fmt.Errorf(\"expected *os.File, got %T\", w)\n\t}\n\n\t// defer closing the file\n\tdefer f.Close()\n\n\t// log the file name\n\tfmt.Printf(\"writing to file %s\\n\", f.Name())\n\n\t// write the data\n\t_, err := f.Write(data)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}", + "file": "panic/src/assert/fixed/main.go", + "lang": "go", + "name": "write", + "start": 34, + "end": 60 + } + }, + "panic/src/basics/main.go": { + "example": { + "content": "func main() {\n\ta := []string{}\n\ta[42] = \"Bring a towel\"\n}", + "file": "panic/src/basics/main.go", + "lang": "go", + "name": "example", + "start": 3, + "end": 9 + }, + "out": { + "content": "\"runtime error: index out of range [42] with length 0\"\nStack:\n\t3 0x0000000001058e55 in main.main\n\t at main.go:6", + "file": "panic/src/basics/main.go", + "lang": "go", + "name": "out", + "start": 12, + "end": 17 + } + }, + "panic/src/func/broken/main.go": { + "example": { + "content": "func main() {\n\n\t// create a new function\n\t// type variable\n\tvar fn func() string\n\n\t// print the results\n\t// of the function\n\tfmt.Println(fn())\n}", + "file": "panic/src/func/broken/main.go", + "lang": "go", + "name": "example", + "start": 7, + "end": 19 + } + }, + "panic/src/func/fixed/main.go": { + "example": { + "content": "func main() {\n\n\t// create a new function\n\t// type variable\n\tvar fn func() string\n\n\t// back the fn variable\n\t// with a function\n\tfn = func() string {\n\t\treturn \"Hello, World!\"\n\t}\n\n\t// print the results\n\t// of the function\n\tfmt.Println(fn())\n}", + "file": "panic/src/func/fixed/main.go", + "lang": "go", + "name": "example", + "start": 7, + "end": 25 + } + }, + "panic/src/interface/backed/main.go": { + "example": { + "content": "func main() {\n\n\t// initialize a stream\n\t// with STDOUT as the writer\n\ts := Stream{\n\t\tWriter: os.Stdout,\n\t}\n\n\tfmt.Fprintf(s, \"Hello Gophers!\")\n}", + "file": "panic/src/interface/backed/main.go", + "lang": "go", + "name": "example", + "start": 13, + "end": 25 + } + }, + "panic/src/interface/empty/main.go": { + "example": { + "content": "func main() {\n\n\t// initialize a stream\n\t// without a writer\n\ts := Stream{}\n\n\tfmt.Fprintf(s, \"Hello Gophers!\")\n}", + "file": "panic/src/interface/empty/main.go", + "lang": "go", + "name": "example", + "start": 15, + "end": 25 + }, + "type": { + "content": "type Stream struct {\n\tio.Writer\n}", + "file": "panic/src/interface/empty/main.go", + "lang": "go", + "name": "type", + "start": 8, + "end": 13 + } + }, + "panic/src/matcher/bad/main.go": { + "bad": { + "content": "func main() {\n\n\t// create a matcher function\n\tm := func(r rune) bool {\n\t\t// simulate doing something bad...\n\t\tpanic(\"hahaha\")\n\n\t\t// unreachable code\n\t\treturn false\n\t}\n\n\t// sanitize the string\n\ts, err := sanitize(m, \"go is awesome\")\n\tif err != nil {\n\t\t// handle the error\n\t\tlog.Fatal(err)\n\t}\n\n\t// print the sanitized string\n\tfmt.Println(s)\n}", + "file": "panic/src/matcher/bad/main.go", + "lang": "go", + "name": "bad", + "start": 8, + "end": 31 + }, + "matcher": { + "content": "type matcher func(rune) bool\n\nfunc sanitize(m matcher, s string) (string, error) {\n\tvar val string\n\n\t// iterate over the runes in the string\n\tfor _, c := range s {\n\n\t\t// call the matcher function\n\t\t// with the rune as the argument\n\t\tif m(c) {\n\t\t\t// append `*` to the result\n\t\t\tval = val + \"*\"\n\t\t\t// continue to the next rune\n\t\t\tcontinue\n\t\t}\n\n\t\t// append the rune to the result\n\t\tval = val + string(c)\n\t}\n\n\t// return the sanitized string\n\treturn val, nil\n}", + "file": "panic/src/matcher/bad/main.go", + "lang": "go", + "name": "matcher", + "start": 33, + "end": 59 + } + }, + "panic/src/matcher/good/main.go": { + "matcher": { + "content": "func sanitize(m matcher, s string) (val string, err error) {\n\t// guard against an invalid matcher that could panic\n\tdefer func() {\n\t\tif e := recover(); e != nil {\n\t\t\terr = fmt.Errorf(\"invalid matcher. panic occurred: %v\", e)\n\t\t}\n\t}()\n\n\tfor _, c := range s {\n\t\tif m(c) {\n\t\t\tval = val + \"*\"\n\t\t\tcontinue\n\t\t}\n\t\tval = val + string(c)\n\t}\n\treturn\n}", + "file": "panic/src/matcher/good/main.go", + "lang": "go", + "name": "matcher", + "start": 25, + "end": 44 + } + }, + "panic/src/recover-broken/recover.go": { + "example": { + "content": "func DoSomething(input int) error {\n\tswitch input {\n\tcase 0:\n\t\t// input was 0, return no error (nil)\n\t\treturn nil\n\tcase 1:\n\t\t// input was 1, panic with the string \"one\"\n\t\tpanic(\"one\")\n\t}\n\n\t// no case was matched\n\treturn nil\n}", + "file": "panic/src/recover-broken/recover.go", + "lang": "go", + "name": "example", + "start": 3, + "end": 18 + } + }, + "panic/src/recover-broken/recover_test.go": { + "test": { + "content": "func Test_DoSomething(t *testing.T) {\n\tt.Parallel()\n\n\terr := DoSomething(0)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\terr = DoSomething(1)\n\n\tif err != nil {\n\t\tt.Fatal(\"expected nil, got\", err)\n\t}\n}", + "file": "panic/src/recover-broken/recover_test.go", + "lang": "go", + "name": "test", + "start": 7, + "end": 23 + } + }, + "panic/src/recover-named/recover.go": { + "example": { + "content": "func DoSomething(input int) (err error) {\n\t// defer a function to recover from the panic\n\tdefer func() {\n\t\tp := recover()\n\t\tif p == nil {\n\t\t\t// a nil was return, no panic was raised\n\t\t\t// return from the deferred function.\n\t\t\treturn\n\t\t}\n\n\t\t// check if the recovered value is already an error\n\t\tif e, ok := p.(error); ok {\n\t\t\t// assign the recovered error to the perr variable\n\t\t\t// outside of the anonymous function scope\n\t\t\terr = e\n\t\t\treturn\n\t\t}\n\n\t\t// a non-error value was recovered\n\t\t// create a new error, `ErrNonErrCaught`, with\n\t\t// information about the recovered value\n\t\tmsg := fmt.Sprintf(\"non-error panic type %T %s\", p, p)\n\t\terr = ErrNonErrCaught(msg)\n\t}()\n\n\tswitch input {\n\tcase 0:\n\t\t// input was 0, return no error (nil)\n\t\treturn nil\n\tcase 1:\n\t\t// input was 1, panic with the string \"one\"\n\t\tpanic(\"one\")\n\t}\n\n\t// no case was matched\n\treturn nil\n}\n\ntype ErrNonErrCaught string\n\nfunc (e ErrNonErrCaught) Error() string {\n\treturn string(e)\n}", + "file": "panic/src/recover-named/recover.go", + "lang": "go", + "name": "example", + "start": 7, + "end": 52 + } + }, + "panic/src/recover-named/recover_test.go": { + "test": { + "content": "func Test_DoSomething(t *testing.T) {\n\tt.Parallel()\n\n\terr := DoSomething(0)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\terr = DoSomething(1)\n\n\tif err != ErrNonErrCaught(\"non-error panic type string one\") {\n\t\tt.Fatal(\"expected ErrNonErrCaught, got\", err)\n\t}\n}", + "file": "panic/src/recover-named/recover_test.go", + "lang": "go", + "name": "test", + "start": 7, + "end": 23 + } + }, + "panic/src/recover/main.go": { + "example": { + "content": "func main() {\n\tdefer func() {\n\t\tif i := recover(); i != nil {\n\t\t\tfmt.Println(\"oh no, a panic occurred:\", i)\n\t\t}\n\t}()\n\n\ta := []string{}\n\ta[42] = \"Bring a towel\"\n}", + "file": "panic/src/recover/main.go", + "lang": "go", + "name": "example", + "start": 5, + "end": 17 + } + }, + "panic/src/slices/broken/main.go": { + "example": { + "content": "func main() {\n\n\t// create a slice\n\tnames := []string{\"Kurt\", \"Janis\", \"Jimi\", \"Amy\"}\n\n\t// find index 42\n\ts, err := find(names, 42)\n\n\t// check for errors\n\tif err != nil {\n\t\tfmt.Println(err)\n\t\tos.Exit(1)\n\t}\n\n\t// print the result\n\tfmt.Println(\"found: \", s)\n}", + "file": "panic/src/slices/broken/main.go", + "lang": "go", + "name": "example", + "start": 8, + "end": 27 + }, + "find": { + "content": "func find(names []string, index int) (string, error) {\n\n\t// find the name at the index\n\ts := names[index]\n\n\t// return an error if the value is empty\n\tif len(s) == 0 {\n\t\treturn s, fmt.Errorf(\"index %d empty\", index)\n\t}\n\n\t// return the name\n\treturn s, nil\n}", + "file": "panic/src/slices/broken/main.go", + "lang": "go", + "name": "find", + "start": 29, + "end": 44 + } + }, + "panic/src/slices/fixed/main.go": { + "example": { + "content": "func main() {\n\n\t// create a slice\n\tnames := []string{\"Kurt\", \"Janis\", \"Jimi\", \"Amy\"}\n\n\t// find index 42\n\ts, err := find(names, 42)\n\n\t// check for errors\n\tif err != nil {\n\t\tfmt.Println(err)\n\t\tos.Exit(1)\n\t}\n\n\t// print the result\n\tfmt.Println(\"found: \", s)\n}", + "file": "panic/src/slices/fixed/main.go", + "lang": "go", + "name": "example", + "start": 8, + "end": 27 + }, + "find": { + "content": "func find(names []string, index int) (string, error) {\n\n\t// check for out of bounds index\n\tif index \u003e= len(names) {\n\t\treturn \"\", fmt.Errorf(\"out of bounds index %d [%d]\", index, len(names))\n\t}\n\n\t// find the name at the index\n\ts := names[index]\n\n\t// return an error if the value is empty\n\tif len(s) == 0 {\n\t\treturn s, fmt.Errorf(\"index %d empty\", index)\n\t}\n\n\t// return the name\n\treturn s, nil\n}", + "file": "panic/src/slices/fixed/main.go", + "lang": "go", + "name": "find", + "start": 29, + "end": 49 + } + } + } + }, + "title": "Errors", + "type": "hype.Document" +} diff --git a/src/testdata/10-generics.json b/src/testdata/10-generics.json new file mode 100644 index 0000000..8d3e547 --- /dev/null +++ b/src/testdata/10-generics.json @@ -0,0 +1,19942 @@ +{ + "filename": "module.md", + "id": "ae9a2d53-1b0f-4246-8781-d2520896c38a", + "nodes": [ + { + "atom": "", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "", + "data_atom": "", + "namespace": "", + "node_type": "html.DocumentNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "html", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "html", + "data_atom": "html", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "head", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "head", + "data_atom": "head", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [], + "tag": "\u003chead\u003e", + "type": "hype.Element" + }, + [ + { + "atom": "body", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "body", + "data_atom": "body", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "page", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "page", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "atom": "h1", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "h1", + "data_atom": "h1", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "level": 1, + "nodes": [ + { + "text": "Generics", + "type": "hype.Text" + } + ], + "tag": "\u003ch1\u003e", + "type": "hype.Heading" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "a", + "attributes": { + "href": "https://en.wikipedia.org/wiki/Generic_programming", + "target": "_blank" + }, + "filename": "module.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "href", + "Val": "https://en.wikipedia.org/wiki/Generic_programming" + } + ], + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Generics", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"https://en.wikipedia.org/wiki/Generic_programming\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://en.wikipedia.org/wiki/Generic_programming" + } + ], + { + "text": " were first introduced to Go with the release of ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "href": "https://go.dev/blog/intro-generics", + "target": "_blank" + }, + "filename": "module.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "href", + "Val": "https://go.dev/blog/intro-generics" + } + ], + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Go 1.18", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"https://go.dev/blog/intro-generics\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://go.dev/blog/intro-generics" + } + ], + { + "text": ". Go 1.18 was release in March of 2022, during the writing of this ", + "type": "hype.Text" + }, + { + "atom": "binding", + "attributes": { + "whole": "" + }, + "filename": "module.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "whole", + "Val": "" + } + ], + "data": "binding", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [], + "tag": "\u003cbinding whole=\"\"\u003e", + "type": "hype.Element" + }, + { + "text": ". We, like the Go team, have tried our best to present the current idioms and thoughts on the how, what, when, where, and why questions about generics in Go.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "h2", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "h2", + "data_atom": "h2", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "level": 2, + "nodes": [ + { + "text": "What are Generics?", + "type": "hype.Text" + } + ], + "tag": "\u003ch2\u003e", + "type": "hype.Heading" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Generic programming is a programming paradigm that allows us to stub out the implementation of a function with a type that will be provided later. This has benefits for both writing, and using, generic functions. With generics we can write functions that can work with multiple types directly, without having to write the same function multiple times, once for each type. When using generic functions, we can continue use our types as concrete types, instead of interface representations.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "h2", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "h2", + "data_atom": "h2", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "level": 2, + "nodes": [ + { + "text": "The Problem with Interfaces", + "type": "hype.Text" + } + ], + "tag": "\u003ch2\u003e", + "type": "hype.Heading" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Interfaces in Go are a powerful concept that allows developers to create flexible and reusable code. Interfaces allow us to define a set of methods that describe the behavior of a type. Any type that implements those methods, and behaviors, is considered to implement that interface.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "We have already discussed the benefits and drawbacks of interfaces earlier in this ", + "type": "hype.Text" + }, + { + "atom": "binding", + "attributes": { + "whole": "" + }, + "filename": "module.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "whole", + "Val": "" + } + ], + "data": "binding", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [], + "tag": "\u003cbinding whole=\"\"\u003e", + "type": "hype.Element" + }, + { + "text": " so we don't have to re-iterate the benefits of interfaces, but let's discuss some problems with interfaces. For example, consider the function defined in ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-1" + }, + "filename": "module.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "keys.any.doc" + } + ], + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-1" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.1", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-1\"\u003e", + "type": "hype.Link", + "url": "#listing-1-1" + } + ], + "tag": "\u003cref id=\"listing-1-1\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ", and the problem of how to write a function that will return the keys for a given map.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-1", + "type": "listing" + }, + "filename": "module.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "keys.any.doc" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "args": [ + "go", + "doc", + "-cmd", + "-u", + "-src", + "-short", + "Keys" + ], + "atom": "cmd", + "attributes": { + "exec": "go doc -cmd -u -src -short Keys", + "hide-cmd": "", + "language": "go", + "src": "src/keys/any", + "sym": "Keys" + }, + "expected_exit": 0, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "exec", + "Val": "go doc -cmd -u -src -short Keys" + }, + { + "Namespace": "", + "Key": "hide-cmd", + "Val": "" + }, + { + "Namespace": "", + "Key": "language", + "Val": "go" + }, + { + "Namespace": "", + "Key": "src", + "Val": "src/keys/any" + }, + { + "Namespace": "", + "Key": "sym", + "Val": "Keys" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "doc", + "-cmd", + "-u", + "-src", + "-short", + "Keys" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/10-generics/src/keys/any", + "duration": "1.60923075s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "text": "func Keys(m map[any]any) []any {\n\n\t// make a slice of the keys\n\tkeys := make([]any, 0, len(m))\n\n\t// iterate over the map\n\tfor k := range m {\n\n\t\t// add the key to the slice\n\t\tkeys = append(keys, k)\n\t}\n\n\t// return the keys\n\treturn keys\n}", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "func Keys(m map[any]any) []any {\n\n\t// make a slice of the keys\n\tkeys := make([]any, 0, len(m))\n\n\t// iterate over the map\n\tfor k := range m {\n\n\t\t// add the key to the slice\n\t\tkeys = append(keys, k)\n\t}\n\n\t// return the keys\n\treturn keys\n}", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "doc", + "-cmd", + "-u", + "-src", + "-short", + "Keys" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/10-generics/src/keys/any", + "duration": "1.60923075s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "text": "func Keys(m map[any]any) []any {\n\n\t// make a slice of the keys\n\tkeys := make([]any, 0, len(m))\n\n\t// iterate over the map\n\tfor k := range m {\n\n\t\t// add the key to the slice\n\t\tkeys = append(keys, k)\n\t}\n\n\t// return the keys\n\treturn keys\n}", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "func Keys(m map[any]any) []any {\n\n\t// make a slice of the keys\n\tkeys := make([]any, 0, len(m))\n\n\t// iterate over the map\n\tfor k := range m {\n\n\t\t// add the key to the slice\n\t\tkeys = append(keys, k)\n\t}\n\n\t// return the keys\n\treturn keys\n}", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd exec=\"go doc -cmd -u -src -short Keys\" hide-cmd=\"\" language=\"go\" src=\"src/keys/any\" sym=\"Keys\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.1:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "A function that returns the keys of a map.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 1, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-1\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Go is a statically typed language and so we have to specify the type of the map that we want to get the keys from. A map needs to have both its key and value types specified. We also need to specify the type of slice this function will be returning. In order for this function to support all map types we need to use the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "any", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": ", or empty interface, type which will match any type.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "While this means we can write a function that we return a list of keys from a map, it also means that this function is difficult to use. Consider a test, ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-2" + }, + "filename": "module.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "keys.any.test" + } + ], + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-2" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.2", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-2\"\u003e", + "type": "hype.Link", + "url": "#listing-1-2" + } + ], + "tag": "\u003cref id=\"listing-1-2\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ", that tries use a map that isn't of type ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "map[any]any", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": ". This code fails to compile because the type of map in the test is not compatible with the type of map required by the function.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-2", + "type": "listing" + }, + "filename": "module.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "keys.any.test" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "src": "src/keys/any/keys_test.go#example" + }, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/keys/any/keys_test.go#example" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "content": "func Test_Keys(t *testing.T) {\n\tt.Parallel()\n\n\t// create a map with some values\n\tm := map[int]string{\n\t\t1: \"one\",\n\t\t2: \"two\",\n\t\t3: \"three\",\n\t}\n\n\t// get the keys\n\tact := Keys(m)\n\n\t// sort the returned keys for comparison\n\tsort.Slice(act, func(i, j int) bool {\n\t\treturn act[i] \u003c act[j]\n\t})\n\n\t// set the expected values\n\texp := []int{1, 2, 3}\n\n\t// assert the length of the actual and expected values\n\tal := len(act)\n\tel := len(exp)\n\tif al != el {\n\t\tt.Fatalf(\"expected %d, but got %d\", el, al)\n\t}\n\n\t// loop through the expected values and\n\t// assert they are in the actual values\n\tfor i, v := range exp {\n\t\tif v != act[i] {\n\t\t\tt.Fatalf(\"expected %d, but got %d\", v, act[i])\n\t\t}\n\t}\n\n}", + "file": "src/keys/any/keys_test.go", + "lang": "go", + "name": "example", + "start": 8, + "end": 47 + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" src=\"src/keys/any/keys_test.go#example\"\u003e", + "type": "hype.SourceCode" + } + ] + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + }, + { + "atom": "hr", + "attributes": {}, + "filename": "", + "html_node": { + "data": "hr", + "data_atom": "hr", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [], + "tag": "\u003chr\u003e", + "type": "hype.Element" + }, + [ + { + "args": [ + "go", + "test", + "-v" + ], + "atom": "cmd", + "attributes": { + "data-go-version": "go1.22.0", + "exec": "go test -v", + "exit": "-1", + "src": "src/keys/any", + "test": "-v" + }, + "expected_exit": -1, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "data-go-version", + "Val": "go1.22.0" + }, + { + "Namespace": "", + "Key": "exec", + "Val": "go test -v" + }, + { + "Namespace": "", + "Key": "exit", + "Val": "-1" + }, + { + "Namespace": "", + "Key": "src", + "Val": "src/keys/any" + }, + { + "Namespace": "", + "Key": "test", + "Val": "-v" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "test", + "-v" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/10-generics/src/keys/any", + "duration": "2.056072666s", + "err": "exit status 1", + "exit": 1, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go test -v\n\nFAIL\tdemo [build failed]\n\n# demo [demo.test]\n./keys_test.go:20:14: cannot use m (variable of type map[int]string) as map[any]any value in argument to Keys\n./keys_test.go:24:10: invalid operation: act[i] \u0026lt; act[j] (operator \u0026lt; not defined on interface)", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "# demo [demo.test]\n./keys_test.go:20:14: cannot use m (variable of type map[int]string) as map[any]any value in argument to Keys\n./keys_test.go:24:10: invalid operation: act[i] \u003c act[j] (operator \u003c not defined on interface)", + "stdout": "FAIL\tdemo [build failed]", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "test", + "-v" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/10-generics/src/keys/any", + "duration": "2.056072666s", + "err": "exit status 1", + "exit": 1, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go test -v\n\nFAIL\tdemo [build failed]\n\n# demo [demo.test]\n./keys_test.go:20:14: cannot use m (variable of type map[int]string) as map[any]any value in argument to Keys\n./keys_test.go:24:10: invalid operation: act[i] \u0026lt; act[j] (operator \u0026lt; not defined on interface)", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "# demo [demo.test]\n./keys_test.go:20:14: cannot use m (variable of type map[int]string) as map[any]any value in argument to Keys\n./keys_test.go:24:10: invalid operation: act[i] \u003c act[j] (operator \u003c not defined on interface)", + "stdout": "FAIL\tdemo [build failed]", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd data-go-version=\"go1.22.0\" exec=\"go test -v\" exit=\"-1\" src=\"src/keys/any\" test=\"-v\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.2:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "Compilation error caused by a type mismatch.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 2, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-2\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "In ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-3" + }, + "filename": "module.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "keys.fixed" + } + ], + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-3" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.3", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-3\"\u003e", + "type": "hype.Link", + "url": "#listing-1-3" + } + ], + "tag": "\u003cref id=\"listing-1-3\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": " is an attempt to solve this problem. First, we need to create a new, interstitial map of the correct type, and copy all of the keys from the original map into the new map. The same is true of trying to handle the results. We need to loop through the returned slice of keys, asserts the keys are of the correct type, and then copy those values into a new slice of the correct type.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-3", + "type": "listing" + }, + "filename": "module.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "keys.fixed" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "src": "src/keys/fixed/keys_test.go#example" + }, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/keys/fixed/keys_test.go#example" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "content": "func Test_Keys(t *testing.T) {\n\tt.Parallel()\n\n\t// create a map with some values\n\tm := map[int]string{\n\t\t1: \"one\",\n\t\t2: \"two\",\n\t\t3: \"three\",\n\t}\n\n\t// create an interstitial map to pass to the function\n\tim := map[any]any{}\n\n\t// copy the map into the interstitial map\n\tfor k, v := range m {\n\t\tim[k] = v\n\t}\n\n\t// get the keys\n\tkeys := Keys(im)\n\n\t// create a slice to hold the keys as\n\t// integers for comparison\n\tact := make([]int, 0, len(keys))\n\n\t// copy the keys into the integer slice\n\tfor _, k := range keys {\n\t\t// assert that the key is an int\n\t\ti, ok := k.(int)\n\t\tif !ok {\n\t\t\tt.Fatalf(\"expected type int, got %T\", k)\n\t\t}\n\n\t\tact = append(act, i)\n\t}\n\n\t// sort the returned keys for comparison\n\tsort.Slice(act, func(i, j int) bool {\n\t\treturn act[i] \u003c act[j]\n\t})\n\n\t// set the expected values\n\texp := []int{1, 2, 3}\n\n\t// assert the length of the actual and expected values\n\tal := len(act)\n\tel := len(exp)\n\tif al != el {\n\t\tt.Fatalf(\"expected %d, but got %d\", el, al)\n\t}\n\n\t// loop through the expected values and\n\t// assert they are in the actual values\n\tfor i, v := range exp {\n\t\tif v != act[i] {\n\t\t\tt.Fatalf(\"expected %d, but got %d\", v, act[i])\n\t\t}\n\t}\n\n}", + "file": "src/keys/fixed/keys_test.go", + "lang": "go", + "name": "example", + "start": 8, + "end": 70 + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" src=\"src/keys/fixed/keys_test.go#example\"\u003e", + "type": "hype.SourceCode" + } + ] + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + }, + { + "atom": "hr", + "attributes": {}, + "filename": "", + "html_node": { + "data": "hr", + "data_atom": "hr", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [], + "tag": "\u003chr\u003e", + "type": "hype.Element" + }, + [ + { + "args": [ + "go", + "test", + "-v" + ], + "atom": "cmd", + "attributes": { + "data-go-version": "go1.22.0", + "exec": "go test -v", + "src": "src/keys/fixed", + "test": "-v" + }, + "expected_exit": 0, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "data-go-version", + "Val": "go1.22.0" + }, + { + "Namespace": "", + "Key": "exec", + "Val": "go test -v" + }, + { + "Namespace": "", + "Key": "src", + "Val": "src/keys/fixed" + }, + { + "Namespace": "", + "Key": "test", + "Val": "-v" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "test", + "-v" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/10-generics/src/keys/fixed", + "duration": "2.725567125s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go test -v\n\n=== RUN Test_Keys\n=== PAUSE Test_Keys\n=== CONT Test_Keys\n--- PASS: Test_Keys (0.00s)\nPASS\nok \tdemo\t0.767s", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "=== RUN Test_Keys\n=== PAUSE Test_Keys\n=== CONT Test_Keys\n--- PASS: Test_Keys (0.00s)\nPASS\nok \tdemo\t0.767s", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "test", + "-v" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/10-generics/src/keys/fixed", + "duration": "2.725567125s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go test -v\n\n=== RUN Test_Keys\n=== PAUSE Test_Keys\n=== CONT Test_Keys\n--- PASS: Test_Keys (0.00s)\nPASS\nok \tdemo\t0.767s", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "=== RUN Test_Keys\n=== PAUSE Test_Keys\n=== CONT Test_Keys\n--- PASS: Test_Keys (0.00s)\nPASS\nok \tdemo\t0.767s", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd data-go-version=\"go1.22.0\" exec=\"go test -v\" src=\"src/keys/fixed\" test=\"-v\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.3:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "Copying maps to satisfy a type constraint.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 3, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-3\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "While ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-3" + }, + "filename": "module.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "keys.fixed" + } + ], + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-3" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.3", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-3\"\u003e", + "type": "hype.Link", + "url": "#listing-1-3" + } + ], + "tag": "\u003cref id=\"listing-1-3\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": " fixes the tests, it is a very cumbersome way to work with a function such as this. Generics, were designed to help solve exactly this sort of problem.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "h2", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "h2", + "data_atom": "h2", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "level": 2, + "nodes": [ + { + "text": "Type Constraints", + "type": "hype.Text" + } + ], + "tag": "\u003ch2\u003e", + "type": "hype.Heading" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Generics in Go introduced a new concept to the language, called Type Constraints. Type Constraints allow us to specify that a type fits within a certain set of constraints. This is useful when we want to write a function that can work with multiple types, but we want to be able to specify that the function can only work with a specific type.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "For example, so far have been using an ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "int", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " for the key type in a map, and ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "string", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " for the value type. This is fine, but we can use generics to make this more flexible. We may want to use an ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "int32", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " or a ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "float64", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " for the key type, and ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "any", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " value for the value type.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Generics allows us to specify those types as constraints when defining a function or a type. Constraints are added with ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "[]", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " after the name of the function or type, but before any parameters. ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-4" + }, + "filename": "module.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "anatomy" + } + ], + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-4" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.4", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-4\"\u003e", + "type": "hype.Link", + "url": "#listing-1-4" + } + ], + "tag": "\u003cref id=\"listing-1-4\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": " lays out the anatomy of a generic function.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-4", + "type": "listing" + }, + "filename": "module.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "anatomy" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go" + }, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "class", + "Val": "language-go" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "text": "func Name[constraints](parameters) (returns) {\n\t// ...\n}\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\"\u003e", + "type": "hype.FencedCode" + } + ] + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + }, + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.4:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "Anatomy of a generic function.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 4, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-4\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "For example, in ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-5" + }, + "filename": "module.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "slicer.doc" + } + ], + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-5" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.5", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-5\"\u003e", + "type": "hype.Link", + "url": "#listing-1-5" + } + ], + "tag": "\u003cref id=\"listing-1-5\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ", we define a ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Slicer", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " function that defines a constraint, type ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "T", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": ", which can be of ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "any", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " type. That new ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "T", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " type can then be used in the function signature. In ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-5" + }, + "filename": "module.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "slicer.doc" + } + ], + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-5" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.5", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-5\"\u003e", + "type": "hype.Link", + "url": "#listing-1-5" + } + ], + "tag": "\u003cref id=\"listing-1-5\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ", the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Slicer", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " function will return a slice of ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "T", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " values.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-5", + "type": "listing" + }, + "filename": "module.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "slicer.doc" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "args": [ + "go", + "doc", + "-cmd", + "-u", + "-src", + "-short", + "Slicer" + ], + "atom": "cmd", + "attributes": { + "exec": "go doc -cmd -u -src -short Slicer", + "hide-cmd": "", + "language": "go", + "src": "src/slicer", + "sym": "Slicer" + }, + "expected_exit": 0, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "exec", + "Val": "go doc -cmd -u -src -short Slicer" + }, + { + "Namespace": "", + "Key": "hide-cmd", + "Val": "" + }, + { + "Namespace": "", + "Key": "language", + "Val": "go" + }, + { + "Namespace": "", + "Key": "src", + "Val": "src/slicer" + }, + { + "Namespace": "", + "Key": "sym", + "Val": "Slicer" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "doc", + "-cmd", + "-u", + "-src", + "-short", + "Slicer" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/10-generics/src/slicer", + "duration": "337.315542ms", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "text": "func Slicer[T any](input T) []T {\n\treturn []T{input}\n}", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "func Slicer[T any](input T) []T {\n\treturn []T{input}\n}", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "doc", + "-cmd", + "-u", + "-src", + "-short", + "Slicer" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/10-generics/src/slicer", + "duration": "337.315542ms", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "text": "func Slicer[T any](input T) []T {\n\treturn []T{input}\n}", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "func Slicer[T any](input T) []T {\n\treturn []T{input}\n}", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd exec=\"go doc -cmd -u -src -short Slicer\" hide-cmd=\"\" language=\"go\" src=\"src/slicer\" sym=\"Slicer\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.5:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "A generic function that returns a slice of values.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 5, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-5\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "When calling the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Slicer", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " function, as seen in ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-6" + }, + "filename": "module.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "slicer.example" + } + ], + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-6" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.6", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-6\"\u003e", + "type": "hype.Link", + "url": "#listing-1-6" + } + ], + "tag": "\u003cref id=\"listing-1-6\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": " we can pass any type, and it returns a slice of that same type back.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-6", + "type": "listing" + }, + "filename": "module.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "slicer.example" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "src": "src/slicer/slicer_test.go#example" + }, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/slicer/slicer_test.go#example" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "content": "func Test_Slicer(t *testing.T) {\n\tt.Parallel()\n\n\t// create input string\n\tinput := \"Hello World\"\n\n\t// capture output []string\n\tact := Slicer(input)\n\n\texp := []string{input}\n\n\tif len(act) != len(exp) {\n\t\tt.Fatalf(\"expected %v, got %v\", exp, act)\n\t}\n\n\tfor i, v := range exp {\n\t\tif act[i] != v {\n\t\t\tt.Fatalf(\"expected %v, got %v\", exp, act)\n\t\t}\n\t}\n\n}", + "file": "src/slicer/slicer_test.go", + "lang": "go", + "name": "example", + "start": 7, + "end": 31 + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" src=\"src/slicer/slicer_test.go#example\"\u003e", + "type": "hype.SourceCode" + } + ] + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + }, + { + "atom": "hr", + "attributes": {}, + "filename": "", + "html_node": { + "data": "hr", + "data_atom": "hr", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [], + "tag": "\u003chr\u003e", + "type": "hype.Element" + }, + [ + { + "args": [ + "go", + "test", + "-v" + ], + "atom": "cmd", + "attributes": { + "data-go-version": "go1.22.0", + "exec": "go test -v", + "src": "src/slicer", + "test": "-v" + }, + "expected_exit": 0, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "data-go-version", + "Val": "go1.22.0" + }, + { + "Namespace": "", + "Key": "exec", + "Val": "go test -v" + }, + { + "Namespace": "", + "Key": "src", + "Val": "src/slicer" + }, + { + "Namespace": "", + "Key": "test", + "Val": "-v" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "test", + "-v" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/10-generics/src/slicer", + "duration": "4.2328525s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go test -v\n\n=== RUN Test_Slicer\n=== PAUSE Test_Slicer\n=== CONT Test_Slicer\n--- PASS: Test_Slicer (0.00s)\nPASS\nok \tdemo\t2.079s", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "=== RUN Test_Slicer\n=== PAUSE Test_Slicer\n=== CONT Test_Slicer\n--- PASS: Test_Slicer (0.00s)\nPASS\nok \tdemo\t2.079s", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "test", + "-v" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/10-generics/src/slicer", + "duration": "4.2328525s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go test -v\n\n=== RUN Test_Slicer\n=== PAUSE Test_Slicer\n=== CONT Test_Slicer\n--- PASS: Test_Slicer (0.00s)\nPASS\nok \tdemo\t2.079s", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "=== RUN Test_Slicer\n=== PAUSE Test_Slicer\n=== CONT Test_Slicer\n--- PASS: Test_Slicer (0.00s)\nPASS\nok \tdemo\t2.079s", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd data-go-version=\"go1.22.0\" exec=\"go test -v\" src=\"src/slicer\" test=\"-v\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.6:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "Calling a generic function.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 6, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-6\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "In our tests we passed a ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "string", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " type to the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Slicer", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " function. At compile time, sees that we are calling the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Slicer", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " function with a ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "string", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " type and then inserts a function with the appropriate typed signature. For example, by passing a ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "string", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " type to the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Slicer", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " function, the compiler generates a function that looks like ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-7" + }, + "filename": "module.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "static.slicer.out" + } + ], + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-7" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.7", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-7\"\u003e", + "type": "hype.Link", + "url": "#listing-1-7" + } + ], + "tag": "\u003cref id=\"listing-1-7\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ".", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-7", + "type": "listing" + }, + "filename": "module.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "static.slicer.out" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "args": [ + "go", + "doc", + "-cmd", + "-u", + "-src", + "-short", + "Slicer" + ], + "atom": "cmd", + "attributes": { + "exec": "go doc -cmd -u -src -short Slicer", + "hide-cmd": "", + "language": "go", + "src": "src/slicer-static", + "sym": "Slicer" + }, + "expected_exit": 0, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "exec", + "Val": "go doc -cmd -u -src -short Slicer" + }, + { + "Namespace": "", + "Key": "hide-cmd", + "Val": "" + }, + { + "Namespace": "", + "Key": "language", + "Val": "go" + }, + { + "Namespace": "", + "Key": "src", + "Val": "src/slicer-static" + }, + { + "Namespace": "", + "Key": "sym", + "Val": "Slicer" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "doc", + "-cmd", + "-u", + "-src", + "-short", + "Slicer" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/10-generics/src/slicer-static", + "duration": "1.528136334s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "text": "func Slicer(input string) []string {\n\treturn []string{input}\n}", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "func Slicer(input string) []string {\n\treturn []string{input}\n}", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "doc", + "-cmd", + "-u", + "-src", + "-short", + "Slicer" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/10-generics/src/slicer-static", + "duration": "1.528136334s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "text": "func Slicer(input string) []string {\n\treturn []string{input}\n}", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "func Slicer(input string) []string {\n\treturn []string{input}\n}", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd exec=\"go doc -cmd -u -src -short Slicer\" hide-cmd=\"\" language=\"go\" src=\"src/slicer-static\" sym=\"Slicer\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.7:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "A static function that returns a slice of strings.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 7, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-7\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "h2", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "h2", + "data_atom": "h2", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "level": 2, + "nodes": [ + { + "text": "Multiple Generic Types", + "type": "hype.Text" + } + ], + "tag": "\u003ch2\u003e", + "type": "hype.Heading" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "With an understanding of the basics of generics, let's revisit the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Keys", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " function in ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-8" + }, + "filename": "module.md", + "html_node": { + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-8" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.8", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-8\"\u003e", + "type": "hype.Link", + "url": "#listing-1-8" + } + ], + "tag": "\u003cref id=\"listing-1-8\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ", and update it to support generics.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-8", + "type": "listing" + }, + "filename": "module.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "fixed.keys.dey" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "args": [ + "go", + "doc", + "-cmd", + "-u", + "-src", + "-short", + "Keys" + ], + "atom": "cmd", + "attributes": { + "exec": "go doc -cmd -u -src -short Keys", + "hide-cmd": "", + "language": "go", + "src": "src/keys/fixed", + "sym": "Keys" + }, + "expected_exit": 0, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "exec", + "Val": "go doc -cmd -u -src -short Keys" + }, + { + "Namespace": "", + "Key": "hide-cmd", + "Val": "" + }, + { + "Namespace": "", + "Key": "language", + "Val": "go" + }, + { + "Namespace": "", + "Key": "src", + "Val": "src/keys/fixed" + }, + { + "Namespace": "", + "Key": "sym", + "Val": "Keys" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "doc", + "-cmd", + "-u", + "-src", + "-short", + "Keys" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/10-generics/src/keys/fixed", + "duration": "1.797201875s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "text": "// snippet: def\nfunc Keys(m map[any]any) []any {\n\t// snippet: def\n\n\t// make a slice of the keys\n\tkeys := make([]any, 0, len(m))\n\n\t// iterate over the map\n\tfor k := range m {\n\n\t\t// add the key to the slice\n\t\tkeys = append(keys, k)\n\t}\n\n\t// return the keys\n\treturn keys\n}", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "// snippet: def\nfunc Keys(m map[any]any) []any {\n\t// snippet: def\n\n\t// make a slice of the keys\n\tkeys := make([]any, 0, len(m))\n\n\t// iterate over the map\n\tfor k := range m {\n\n\t\t// add the key to the slice\n\t\tkeys = append(keys, k)\n\t}\n\n\t// return the keys\n\treturn keys\n}", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "doc", + "-cmd", + "-u", + "-src", + "-short", + "Keys" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/10-generics/src/keys/fixed", + "duration": "1.797201875s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "text": "// snippet: def\nfunc Keys(m map[any]any) []any {\n\t// snippet: def\n\n\t// make a slice of the keys\n\tkeys := make([]any, 0, len(m))\n\n\t// iterate over the map\n\tfor k := range m {\n\n\t\t// add the key to the slice\n\t\tkeys = append(keys, k)\n\t}\n\n\t// return the keys\n\treturn keys\n}", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "// snippet: def\nfunc Keys(m map[any]any) []any {\n\t// snippet: def\n\n\t// make a slice of the keys\n\tkeys := make([]any, 0, len(m))\n\n\t// iterate over the map\n\tfor k := range m {\n\n\t\t// add the key to the slice\n\t\tkeys = append(keys, k)\n\t}\n\n\t// return the keys\n\treturn keys\n}", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd exec=\"go doc -cmd -u -src -short Keys\" hide-cmd=\"\" language=\"go\" src=\"src/keys/fixed\" sym=\"Keys\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.8:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "The ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Keys", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " function before generics.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 8, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-8\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "A map has both a key and a value type. We can use generics to specify which types are allowed to be used for both. In ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-9" + }, + "filename": "module.md", + "html_node": { + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-9" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.9", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-9\"\u003e", + "type": "hype.Link", + "url": "#listing-1-9" + } + ], + "tag": "\u003cref id=\"listing-1-9\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ", we can specify that the key type, ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "K", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": ", must of a type ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "int", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": ", but the value type, ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "V", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": ", can be of any type.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-9", + "type": "listing" + }, + "filename": "module.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "generic.start.def" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "args": [ + "go", + "doc", + "-cmd", + "-u", + "-src", + "-short", + "Keys" + ], + "atom": "cmd", + "attributes": { + "exec": "go doc -cmd -u -src -short Keys", + "hide-cmd": "", + "language": "go", + "src": "src/keys/generic/start", + "sym": "Keys" + }, + "expected_exit": 0, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "exec", + "Val": "go doc -cmd -u -src -short Keys" + }, + { + "Namespace": "", + "Key": "hide-cmd", + "Val": "" + }, + { + "Namespace": "", + "Key": "language", + "Val": "go" + }, + { + "Namespace": "", + "Key": "src", + "Val": "src/keys/generic/start" + }, + { + "Namespace": "", + "Key": "sym", + "Val": "Keys" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "doc", + "-cmd", + "-u", + "-src", + "-short", + "Keys" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/10-generics/src/keys/generic/start", + "duration": "1.091841292s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "text": "// snippet: def\nfunc Keys[K int, V any](m map[K]V) []K {\n\t// snippet: def\n\n\t// make a slice of the keys\n\tkeys := make([]K, 0, len(m))\n\n\t// iterate over the map\n\tfor k := range m {\n\n\t\t// add the key to the slice\n\t\tkeys = append(keys, k)\n\t}\n\n\t// return the keys\n\treturn keys\n}", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "// snippet: def\nfunc Keys[K int, V any](m map[K]V) []K {\n\t// snippet: def\n\n\t// make a slice of the keys\n\tkeys := make([]K, 0, len(m))\n\n\t// iterate over the map\n\tfor k := range m {\n\n\t\t// add the key to the slice\n\t\tkeys = append(keys, k)\n\t}\n\n\t// return the keys\n\treturn keys\n}", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "doc", + "-cmd", + "-u", + "-src", + "-short", + "Keys" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/10-generics/src/keys/generic/start", + "duration": "1.091841292s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "text": "// snippet: def\nfunc Keys[K int, V any](m map[K]V) []K {\n\t// snippet: def\n\n\t// make a slice of the keys\n\tkeys := make([]K, 0, len(m))\n\n\t// iterate over the map\n\tfor k := range m {\n\n\t\t// add the key to the slice\n\t\tkeys = append(keys, k)\n\t}\n\n\t// return the keys\n\treturn keys\n}", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "// snippet: def\nfunc Keys[K int, V any](m map[K]V) []K {\n\t// snippet: def\n\n\t// make a slice of the keys\n\tkeys := make([]K, 0, len(m))\n\n\t// iterate over the map\n\tfor k := range m {\n\n\t\t// add the key to the slice\n\t\tkeys = append(keys, k)\n\t}\n\n\t// return the keys\n\treturn keys\n}", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd exec=\"go doc -cmd -u -src -short Keys\" hide-cmd=\"\" language=\"go\" src=\"src/keys/generic/start\" sym=\"Keys\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.9:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "The ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Keys", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " function after generics.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 9, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-9\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "With the changes in ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-9" + }, + "filename": "module.md", + "html_node": { + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-9" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.9", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-9\"\u003e", + "type": "hype.Link", + "url": "#listing-1-9" + } + ], + "tag": "\u003cref id=\"listing-1-9\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": " we can pass a map of key type ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "int", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " and a value type of ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "string", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " to the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Keys", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " function and it will return a slice of ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "int", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " values.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-10", + "type": "listing" + }, + "filename": "module.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "generic.start.test" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "src": "src/keys/generic/start/keys_test.go#example" + }, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/keys/generic/start/keys_test.go#example" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "content": "func Test_Keys(t *testing.T) {\n\tt.Parallel()\n\n\t// create a map with some values\n\tm := map[int]string{\n\t\t1: \"one\",\n\t\t2: \"two\",\n\t\t3: \"three\",\n\t}\n\n\t// get the keys\n\tact := Keys(m)\n\n\t// sort the returned keys for comparison\n\tsort.Slice(act, func(i, j int) bool {\n\t\treturn act[i] \u003c act[j]\n\t})\n\n\t// set the expected values\n\texp := []int{1, 2, 3}\n\n\t// assert the length of the actual and expected values\n\tif len(exp) != len(act) {\n\t\tt.Fatalf(\"expected len(%d), but got len(%d)\", len(exp), len(act))\n\t}\n\n\t// assert the types of the actual and expected values\n\tat := fmt.Sprintf(\"%T\", act)\n\tet := fmt.Sprintf(\"%T\", exp)\n\n\tif at != et {\n\t\tt.Fatalf(\"expected type %s, but got type %s\", et, at)\n\t}\n\n\t// loop through the expected values and\n\t// assert they are in the actual values\n\tfor i, v := range exp {\n\t\tif v != act[i] {\n\t\t\tt.Fatalf(\"expected %d, but got %d\", v, act[i])\n\t\t}\n\t}\n\n}", + "file": "src/keys/generic/start/keys_test.go", + "lang": "go", + "name": "example", + "start": 9, + "end": 54 + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" src=\"src/keys/generic/start/keys_test.go#example\"\u003e", + "type": "hype.SourceCode" + } + ] + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + }, + { + "atom": "hr", + "attributes": {}, + "filename": "", + "html_node": { + "data": "hr", + "data_atom": "hr", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [], + "tag": "\u003chr\u003e", + "type": "hype.Element" + }, + [ + { + "args": [ + "go", + "test", + "-v" + ], + "atom": "cmd", + "attributes": { + "data-go-version": "go1.22.0", + "exec": "go test -v", + "src": "src/keys/generic/start", + "test": "-v" + }, + "expected_exit": 0, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "data-go-version", + "Val": "go1.22.0" + }, + { + "Namespace": "", + "Key": "exec", + "Val": "go test -v" + }, + { + "Namespace": "", + "Key": "src", + "Val": "src/keys/generic/start" + }, + { + "Namespace": "", + "Key": "test", + "Val": "-v" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "test", + "-v" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/10-generics/src/keys/generic/start", + "duration": "4.367696666s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go test -v\n\n=== RUN Test_Keys\n=== PAUSE Test_Keys\n=== CONT Test_Keys\n--- PASS: Test_Keys (0.00s)\nPASS\nok \tdemo\t2.203s", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "=== RUN Test_Keys\n=== PAUSE Test_Keys\n=== CONT Test_Keys\n--- PASS: Test_Keys (0.00s)\nPASS\nok \tdemo\t2.203s", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "test", + "-v" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/10-generics/src/keys/generic/start", + "duration": "4.367696666s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go test -v\n\n=== RUN Test_Keys\n=== PAUSE Test_Keys\n=== CONT Test_Keys\n--- PASS: Test_Keys (0.00s)\nPASS\nok \tdemo\t2.203s", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "=== RUN Test_Keys\n=== PAUSE Test_Keys\n=== CONT Test_Keys\n--- PASS: Test_Keys (0.00s)\nPASS\nok \tdemo\t2.203s", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd data-go-version=\"go1.22.0\" exec=\"go test -v\" src=\"src/keys/generic/start\" test=\"-v\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.10:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "Tests now passing after using generics in ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-9" + }, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "generic.start.def" + } + ], + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-9" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.9", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-9\"\u003e", + "type": "hype.Link", + "url": "#listing-1-9" + } + ], + "tag": "\u003cref id=\"listing-1-9\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ".", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 10, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-10\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "As ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-10" + }, + "filename": "module.md", + "html_node": { + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-10" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.10", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-10\"\u003e", + "type": "hype.Link", + "url": "#listing-1-10" + } + ], + "tag": "\u003cref id=\"listing-1-10\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": " shows, This however, doesn't work if we want to use a map key of type ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "string", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " or ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "float64", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": ". To do this we will need to specify a bigger set of constraints for the key type.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "h2", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "h2", + "data_atom": "h2", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "level": 2, + "nodes": [ + { + "text": "Instantiating Generic Functions", + "type": "hype.Text" + } + ], + "tag": "\u003ch2\u003e", + "type": "hype.Heading" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "When calling a generic function, or creating a new value of a generic type, the Go compiler needs to know which types are being provided for the generic parameters. So far, we have been letting the Go compiler infer the types of the generic parameters based on the types of the values passed in. In ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-11" + }, + "filename": "module.md", + "html_node": { + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-11" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.11", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-11\"\u003e", + "type": "hype.Link", + "url": "#listing-1-11" + } + ], + "tag": "\u003cref id=\"listing-1-11\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ", a variable, ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "fn", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": ", is being declared and initialized with the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Keys", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " function from ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-9" + }, + "filename": "module.md", + "html_node": { + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-9" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.9", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-9\"\u003e", + "type": "hype.Link", + "url": "#listing-1-9" + } + ], + "tag": "\u003cref id=\"listing-1-9\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ". When the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "fn", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " variable is called, the compiler is unable to infer the types of the generic parameters. The result is a compilation error.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-11", + "type": "listing" + }, + "filename": "module.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "instantiation.broken" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "src": "src/instantiation/broken/keys_test.go#example" + }, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/instantiation/broken/keys_test.go#example" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "content": "// create a function variable pointing\n// to the Keys function\nfn := Keys\n\n// get the keys\nact := fn(m)", + "file": "src/instantiation/broken/keys_test.go", + "lang": "go", + "name": "example", + "start": 19, + "end": 26 + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" src=\"src/instantiation/broken/keys_test.go#example\"\u003e", + "type": "hype.SourceCode" + } + ] + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + }, + { + "atom": "hr", + "attributes": {}, + "filename": "", + "html_node": { + "data": "hr", + "data_atom": "hr", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [], + "tag": "\u003chr\u003e", + "type": "hype.Element" + }, + [ + { + "args": [ + "go", + "test", + "-v" + ], + "atom": "cmd", + "attributes": { + "data-go-version": "go1.22.0", + "exec": "go test -v", + "exit": "-1", + "src": "src/instantiation/broken", + "test": "-v" + }, + "expected_exit": -1, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "data-go-version", + "Val": "go1.22.0" + }, + { + "Namespace": "", + "Key": "exec", + "Val": "go test -v" + }, + { + "Namespace": "", + "Key": "exit", + "Val": "-1" + }, + { + "Namespace": "", + "Key": "src", + "Val": "src/instantiation/broken" + }, + { + "Namespace": "", + "Key": "test", + "Val": "-v" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "test", + "-v" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/10-generics/src/instantiation/broken", + "duration": "2.107544875s", + "err": "exit status 1", + "exit": 1, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go test -v\n\nFAIL\tdemo [build failed]\n\n# demo [demo.test]\n./keys_test.go:22:8: cannot use generic function Keys without instantiation", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "# demo [demo.test]\n./keys_test.go:22:8: cannot use generic function Keys without instantiation", + "stdout": "FAIL\tdemo [build failed]", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "test", + "-v" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/10-generics/src/instantiation/broken", + "duration": "2.107544875s", + "err": "exit status 1", + "exit": 1, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go test -v\n\nFAIL\tdemo [build failed]\n\n# demo [demo.test]\n./keys_test.go:22:8: cannot use generic function Keys without instantiation", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "# demo [demo.test]\n./keys_test.go:22:8: cannot use generic function Keys without instantiation", + "stdout": "FAIL\tdemo [build failed]", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd data-go-version=\"go1.22.0\" exec=\"go test -v\" exit=\"-1\" src=\"src/instantiation/broken\" test=\"-v\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.11:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "The ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Keys", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " function before instantiation.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 11, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-11\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "In these situations we need to provide the compiler with the types of the generic parameters. In ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-12" + }, + "filename": "module.md", + "html_node": { + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-12" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.12", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-12\"\u003e", + "type": "hype.Link", + "url": "#listing-1-12" + } + ], + "tag": "\u003cref id=\"listing-1-12\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": " The types, ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "int", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " and ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "string", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": ", are being provided when grabbing a reference to the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Keys", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " function for the variable ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "fn", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": ".", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-12", + "type": "listing" + }, + "filename": "module.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "instantiation.fixed" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "src": "src/instantiation/fixed/keys_test.go#example" + }, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/instantiation/fixed/keys_test.go#example" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "content": "// create a function variable pointing\n// to the Keys function\nfn := Keys[int, string]\n\n// get the keys\nact := fn(m)", + "file": "src/instantiation/fixed/keys_test.go", + "lang": "go", + "name": "example", + "start": 19, + "end": 26 + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" src=\"src/instantiation/fixed/keys_test.go#example\"\u003e", + "type": "hype.SourceCode" + } + ] + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + }, + { + "atom": "hr", + "attributes": {}, + "filename": "", + "html_node": { + "data": "hr", + "data_atom": "hr", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [], + "tag": "\u003chr\u003e", + "type": "hype.Element" + }, + [ + { + "args": [ + "go", + "test", + "-v" + ], + "atom": "cmd", + "attributes": { + "data-go-version": "go1.22.0", + "exec": "go test -v", + "src": "src/instantiation/fixed", + "test": "-v" + }, + "expected_exit": 0, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "data-go-version", + "Val": "go1.22.0" + }, + { + "Namespace": "", + "Key": "exec", + "Val": "go test -v" + }, + { + "Namespace": "", + "Key": "src", + "Val": "src/instantiation/fixed" + }, + { + "Namespace": "", + "Key": "test", + "Val": "-v" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "test", + "-v" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/10-generics/src/instantiation/fixed", + "duration": "5.230820625s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go test -v\n\n=== RUN Test_Keys\n=== PAUSE Test_Keys\n=== CONT Test_Keys\n--- PASS: Test_Keys (0.00s)\nPASS\nok \tdemo\t3.018s", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "=== RUN Test_Keys\n=== PAUSE Test_Keys\n=== CONT Test_Keys\n--- PASS: Test_Keys (0.00s)\nPASS\nok \tdemo\t3.018s", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "test", + "-v" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/10-generics/src/instantiation/fixed", + "duration": "5.230820625s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go test -v\n\n=== RUN Test_Keys\n=== PAUSE Test_Keys\n=== CONT Test_Keys\n--- PASS: Test_Keys (0.00s)\nPASS\nok \tdemo\t3.018s", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "=== RUN Test_Keys\n=== PAUSE Test_Keys\n=== CONT Test_Keys\n--- PASS: Test_Keys (0.00s)\nPASS\nok \tdemo\t3.018s", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd data-go-version=\"go1.22.0\" exec=\"go test -v\" src=\"src/instantiation/fixed\" test=\"-v\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.12:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "The ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Keys", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " function after instantiation.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 12, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-12\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "h2", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "h2", + "data_atom": "h2", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "level": 2, + "nodes": [ + { + "text": "Defining Constraints", + "type": "hype.Text" + } + ], + "tag": "\u003ch2\u003e", + "type": "hype.Heading" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "So far we have been using pretty simple types, such as ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "int", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " and ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "any", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " for the key and value types. But what if we wanted to use more types than just these? To specify which types can be used for a generic parameter, we can use constraints. Constraints are defined in a similar way to interfaces, but instead of specifying a set of methods, we specify a set of types.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "As a start we can define a constraint, ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-13" + }, + "filename": "module.md", + "html_node": { + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-13" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.13", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-13\"\u003e", + "type": "hype.Link", + "url": "#listing-1-13" + } + ], + "tag": "\u003cref id=\"listing-1-13\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": " that requires the type to be an ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "int", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": ".", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-13", + "type": "listing" + }, + "filename": "module.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "mapkey.doc" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "args": [ + "go", + "doc", + "-cmd", + "-u", + "-src", + "-short", + "MapKey" + ], + "atom": "cmd", + "attributes": { + "exec": "go doc -cmd -u -src -short MapKey", + "hide-cmd": "", + "language": "go", + "src": "src/constraints/defining", + "sym": "MapKey" + }, + "expected_exit": 0, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "exec", + "Val": "go doc -cmd -u -src -short MapKey" + }, + { + "Namespace": "", + "Key": "hide-cmd", + "Val": "" + }, + { + "Namespace": "", + "Key": "language", + "Val": "go" + }, + { + "Namespace": "", + "Key": "src", + "Val": "src/constraints/defining" + }, + { + "Namespace": "", + "Key": "sym", + "Val": "MapKey" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "doc", + "-cmd", + "-u", + "-src", + "-short", + "MapKey" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/10-generics/src/constraints/defining", + "duration": "989.092125ms", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "text": "// MapKey is a set of a constraints\n// on types that can be used as map keys.\ntype MapKey interface {\n\tint\n}", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "// MapKey is a set of a constraints\n// on types that can be used as map keys.\ntype MapKey interface {\n\tint\n}", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "doc", + "-cmd", + "-u", + "-src", + "-short", + "MapKey" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/10-generics/src/constraints/defining", + "duration": "989.092125ms", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "text": "// MapKey is a set of a constraints\n// on types that can be used as map keys.\ntype MapKey interface {\n\tint\n}", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "// MapKey is a set of a constraints\n// on types that can be used as map keys.\ntype MapKey interface {\n\tint\n}", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd exec=\"go doc -cmd -u -src -short MapKey\" hide-cmd=\"\" language=\"go\" src=\"src/constraints/defining\" sym=\"MapKey\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.13:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "A constraint that requires the type to be an ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "int", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": ".", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 13, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-13\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "With the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "MapKey", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " constraint defined in ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-13" + }, + "filename": "module.md", + "html_node": { + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-13" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.13", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-13\"\u003e", + "type": "hype.Link", + "url": "#listing-1-13" + } + ], + "tag": "\u003cref id=\"listing-1-13\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ", we can update the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Keys", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " function to use it instead of ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "int", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " in ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-14" + }, + "filename": "module.md", + "html_node": { + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-14" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.14", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-14\"\u003e", + "type": "hype.Link", + "url": "#listing-1-14" + } + ], + "tag": "\u003cref id=\"listing-1-14\"\u003e", + "type": "hype.Ref" + } + ] + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-14", + "type": "listing" + }, + "filename": "module.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "defining.def" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "src": "src/constraints/defining/keys.go#def" + }, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/constraints/defining/keys.go#def" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "content": "func Keys[K MapKey, V any](m map[K]V) []K {\n\n\t// make a slice of the keys\n\tkeys := make([]K, 0, len(m))\n\n\t// iterate over the map\n\tfor k := range m {\n\n\t\t// add the key to the slice\n\t\tkeys = append(keys, k)\n\t}\n\n\t// return the keys\n\treturn keys\n}", + "file": "src/constraints/defining/keys.go", + "lang": "go", + "name": "def", + "start": 9, + "end": 26 + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" src=\"src/constraints/defining/keys.go#def\"\u003e", + "type": "hype.SourceCode" + } + ] + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + }, + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.14:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "The ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Keys", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " function using the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "MapKey", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " constraint.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 14, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-14\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "h2", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "h2", + "data_atom": "h2", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "level": 2, + "nodes": [ + { + "text": "Multiple Type Constraints", + "type": "hype.Text" + } + ], + "tag": "\u003ch2\u003e", + "type": "hype.Heading" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Currently, the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "MapKey", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " constraint only allows an ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "int", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " to be used for the key. In ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-15" + }, + "filename": "module.md", + "html_node": { + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-15" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.15", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-15\"\u003e", + "type": "hype.Link", + "url": "#listing-1-15" + } + ], + "tag": "\u003cref id=\"listing-1-15\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": "we to try and use the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Keys", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " function with a map using a key type of ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "float64", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": ". The result is a compilation error.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-15", + "type": "listing" + }, + "filename": "module.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "floats" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "src": "src/constraints/floats/keys_test.go#example" + }, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/constraints/floats/keys_test.go#example" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "content": "// create a map with some values\nm := map[float64]string{\n\t1.1: \"one\",\n\t2.2: \"two\",\n\t3.3: \"three\",\n}\n\n// get the keys\nact := Keys(m)\n\n// sort the returned keys for comparison\nsort.Slice(act, func(i, j int) bool {\n\treturn act[i] \u003c act[j]\n})\n\n// set the expected values\nexp := []float64{1.1, 2.2, 3.3}\n\n// assert the length of the actual and expected values\nif len(exp) != len(act) {\n\tt.Fatalf(\"expected len(%d), but got len(%d)\", len(exp), len(act))\n}\n\n// assert the types of the actual and expected values\nat := fmt.Sprintf(\"%T\", act)\net := fmt.Sprintf(\"%T\", exp)\n\nif at != et {\n\tt.Fatalf(\"expected type %s, but got type %s\", et, at)\n}\n\n// loop through the expected values and\n// assert they are in the actual values\nfor i, v := range exp {\n\tif v != act[i] {\n\t\tt.Fatalf(\"expected %d, but got %d\", v, act[i])\n\t}\n}", + "file": "src/constraints/floats/keys_test.go", + "lang": "go", + "name": "example", + "start": 12, + "end": 51 + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" src=\"src/constraints/floats/keys_test.go#example\"\u003e", + "type": "hype.SourceCode" + } + ] + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + }, + { + "atom": "hr", + "attributes": {}, + "filename": "", + "html_node": { + "data": "hr", + "data_atom": "hr", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [], + "tag": "\u003chr\u003e", + "type": "hype.Element" + }, + [ + { + "args": [ + "go", + "test", + "-v" + ], + "atom": "cmd", + "attributes": { + "data-go-version": "go1.22.0", + "exec": "go test -v", + "exit": "-1", + "src": "src/constraints/floats", + "test": "-v" + }, + "expected_exit": -1, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "data-go-version", + "Val": "go1.22.0" + }, + { + "Namespace": "", + "Key": "exec", + "Val": "go test -v" + }, + { + "Namespace": "", + "Key": "exit", + "Val": "-1" + }, + { + "Namespace": "", + "Key": "src", + "Val": "src/constraints/floats" + }, + { + "Namespace": "", + "Key": "test", + "Val": "-v" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "test", + "-v" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/10-generics/src/constraints/floats", + "duration": "1.761518834s", + "err": "exit status 1", + "exit": 1, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go test -v\n\nFAIL\tdemo [build failed]\n\n# demo [demo.test]\n./keys_test.go:21:13: K (type float64) does not satisfy MapKey", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "# demo [demo.test]\n./keys_test.go:21:13: K (type float64) does not satisfy MapKey", + "stdout": "FAIL\tdemo [build failed]", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "test", + "-v" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/10-generics/src/constraints/floats", + "duration": "1.761518834s", + "err": "exit status 1", + "exit": 1, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go test -v\n\nFAIL\tdemo [build failed]\n\n# demo [demo.test]\n./keys_test.go:21:13: K (type float64) does not satisfy MapKey", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "# demo [demo.test]\n./keys_test.go:21:13: K (type float64) does not satisfy MapKey", + "stdout": "FAIL\tdemo [build failed]", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd data-go-version=\"go1.22.0\" exec=\"go test -v\" exit=\"-1\" src=\"src/constraints/floats\" test=\"-v\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.15:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "The ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Keys", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " function with a ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "float64", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " key.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 15, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-15\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "When defining constraints we can use the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "|", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " operator to create an intersection of constraints. For example, in ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-16" + }, + "filename": "module.md", + "html_node": { + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-16" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.16", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-16\"\u003e", + "type": "hype.Link", + "url": "#listing-1-16" + } + ], + "tag": "\u003cref id=\"listing-1-16\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": " we define a constraint that requires the key type to be either ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "int", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " or ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "float64", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": ".", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-16", + "type": "listing" + }, + "filename": "module.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "or.doc" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "args": [ + "go", + "doc", + "-cmd", + "-u", + "-src", + "-short", + "MapKey" + ], + "atom": "cmd", + "attributes": { + "exec": "go doc -cmd -u -src -short MapKey", + "hide-cmd": "", + "language": "go", + "src": "src/constraints/or", + "sym": "MapKey" + }, + "expected_exit": 0, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "exec", + "Val": "go doc -cmd -u -src -short MapKey" + }, + { + "Namespace": "", + "Key": "hide-cmd", + "Val": "" + }, + { + "Namespace": "", + "Key": "language", + "Val": "go" + }, + { + "Namespace": "", + "Key": "src", + "Val": "src/constraints/or" + }, + { + "Namespace": "", + "Key": "sym", + "Val": "MapKey" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "doc", + "-cmd", + "-u", + "-src", + "-short", + "MapKey" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/10-generics/src/constraints/or", + "duration": "1.562084667s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "text": "// MapKey is a set of a constraints\n// on types that can be used as map keys.\ntype MapKey interface {\n\tint | float64\n}", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "// MapKey is a set of a constraints\n// on types that can be used as map keys.\ntype MapKey interface {\n\tint | float64\n}", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "doc", + "-cmd", + "-u", + "-src", + "-short", + "MapKey" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/10-generics/src/constraints/or", + "duration": "1.562084667s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "text": "// MapKey is a set of a constraints\n// on types that can be used as map keys.\ntype MapKey interface {\n\tint | float64\n}", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "// MapKey is a set of a constraints\n// on types that can be used as map keys.\ntype MapKey interface {\n\tint | float64\n}", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd exec=\"go doc -cmd -u -src -short MapKey\" hide-cmd=\"\" language=\"go\" src=\"src/constraints/or\" sym=\"MapKey\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.16:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "A constraint that requires the key type to be either ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "int", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " or ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "float64", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": ".", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 16, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-16\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "With the change to the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "MapKey", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " constraint in ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-16" + }, + "filename": "module.md", + "html_node": { + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-16" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.16", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-16\"\u003e", + "type": "hype.Link", + "url": "#listing-1-16" + } + ], + "tag": "\u003cref id=\"listing-1-16\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ", we can use the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Keys", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " function with a map using a key type of ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "float64", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": ". The tests in ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-17" + }, + "filename": "module.md", + "html_node": { + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-17" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.17", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-17\"\u003e", + "type": "hype.Link", + "url": "#listing-1-17" + } + ], + "tag": "\u003cref id=\"listing-1-17\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": " now pass.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-17", + "type": "listing" + }, + "filename": "module.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "or.test" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "args": [ + "go", + "test", + "-v" + ], + "atom": "cmd", + "attributes": { + "data-go-version": "go1.22.0", + "exec": "go test -v", + "src": "src/constraints/or", + "test": "-v" + }, + "expected_exit": 0, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "data-go-version", + "Val": "go1.22.0" + }, + { + "Namespace": "", + "Key": "exec", + "Val": "go test -v" + }, + { + "Namespace": "", + "Key": "src", + "Val": "src/constraints/or" + }, + { + "Namespace": "", + "Key": "test", + "Val": "-v" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "test", + "-v" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/10-generics/src/constraints/or", + "duration": "2.878888208s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go test -v\n\n=== RUN Test_Keys\n=== PAUSE Test_Keys\n=== CONT Test_Keys\n--- PASS: Test_Keys (0.00s)\nPASS\nok \tdemo\t0.870s", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "=== RUN Test_Keys\n=== PAUSE Test_Keys\n=== CONT Test_Keys\n--- PASS: Test_Keys (0.00s)\nPASS\nok \tdemo\t0.870s", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "test", + "-v" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/10-generics/src/constraints/or", + "duration": "2.878888208s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go test -v\n\n=== RUN Test_Keys\n=== PAUSE Test_Keys\n=== CONT Test_Keys\n--- PASS: Test_Keys (0.00s)\nPASS\nok \tdemo\t0.870s", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "=== RUN Test_Keys\n=== PAUSE Test_Keys\n=== CONT Test_Keys\n--- PASS: Test_Keys (0.00s)\nPASS\nok \tdemo\t0.870s", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd data-go-version=\"go1.22.0\" exec=\"go test -v\" src=\"src/constraints/or\" test=\"-v\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.17:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "Tests now passing with the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "MapKey", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " constraint.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 17, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-17\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "h2", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "h2", + "data_atom": "h2", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "level": 2, + "nodes": [ + { + "text": "Underlying Type Constraints", + "type": "hype.Text" + } + ], + "tag": "\u003ch2\u003e", + "type": "hype.Heading" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "In Go, we are allowed to create new types based on other types. For example, we can create a new type, ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "MyInt", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": ", that is based on the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "int", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " type.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-18", + "type": "listing" + }, + "filename": "module.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "myint.doc" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "args": [ + "go", + "doc", + "-cmd", + "-u", + "-src", + "-short", + "MyInt" + ], + "atom": "cmd", + "attributes": { + "exec": "go doc -cmd -u -src -short MyInt", + "hide-cmd": "", + "language": "go", + "src": "src/constraints/underlying/broken", + "sym": "MyInt" + }, + "expected_exit": 0, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "exec", + "Val": "go doc -cmd -u -src -short MyInt" + }, + { + "Namespace": "", + "Key": "hide-cmd", + "Val": "" + }, + { + "Namespace": "", + "Key": "language", + "Val": "go" + }, + { + "Namespace": "", + "Key": "src", + "Val": "src/constraints/underlying/broken" + }, + { + "Namespace": "", + "Key": "sym", + "Val": "MyInt" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "doc", + "-cmd", + "-u", + "-src", + "-short", + "MyInt" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/10-generics/src/constraints/underlying/broken", + "duration": "1.761244667s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "text": "type MyInt int", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "type MyInt int", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "doc", + "-cmd", + "-u", + "-src", + "-short", + "MyInt" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/10-generics/src/constraints/underlying/broken", + "duration": "1.761244667s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "text": "type MyInt int", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "type MyInt int", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd exec=\"go doc -cmd -u -src -short MyInt\" hide-cmd=\"\" language=\"go\" src=\"src/constraints/underlying/broken\" sym=\"MyInt\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.18:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "A new type based on the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "int", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " type.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 18, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-18\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "However, when we try to use the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Keys", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " function with a map using a key type of ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "MyInt", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " we will get a compile error.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-19", + "type": "listing" + }, + "filename": "module.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "underlying.broken" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "src": "src/constraints/underlying/broken/keys_test.go#example" + }, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/constraints/underlying/broken/keys_test.go#example" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "content": "func Test_Keys(t *testing.T) {\n\tt.Parallel()\n\n\t// create a map with some values\n\tm := map[MyInt]string{\n\t\t1: \"one\",\n\t\t2: \"two\",\n\t\t3: \"three\",\n\t}\n\n\t// get the keys\n\tact := Keys(m)\n\n\t// sort the returned keys for comparison\n\tsort.Slice(act, func(i, j int) bool {\n\t\treturn act[i] \u003c act[j]\n\t})\n\n\t// set the expected values\n\texp := []MyInt{1, 2, 3}\n\n\t// assert the length of the actual and expected values\n\tif len(exp) != len(act) {\n\t\tt.Fatalf(\"expected len(%d), but got len(%d)\", len(exp), len(act))\n\t}\n\n\t// assert the types of the actual and expected values\n\tat := fmt.Sprintf(\"%T\", act)\n\tet := fmt.Sprintf(\"%T\", exp)\n\n\tif at != et {\n\t\tt.Fatalf(\"expected type %s, but got type %s\", et, at)\n\t}\n\n\t// loop through the expected values and\n\t// assert they are in the actual values\n\tfor i, v := range exp {\n\t\tif v != act[i] {\n\t\t\tt.Fatalf(\"expected %d, but got %d\", v, act[i])\n\t\t}\n\t}\n\n}", + "file": "src/constraints/underlying/broken/keys_test.go", + "lang": "go", + "name": "example", + "start": 9, + "end": 54 + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" src=\"src/constraints/underlying/broken/keys_test.go#example\"\u003e", + "type": "hype.SourceCode" + } + ] + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + }, + { + "atom": "hr", + "attributes": {}, + "filename": "", + "html_node": { + "data": "hr", + "data_atom": "hr", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [], + "tag": "\u003chr\u003e", + "type": "hype.Element" + }, + [ + { + "args": [ + "go", + "test", + "-v" + ], + "atom": "cmd", + "attributes": { + "data-go-version": "go1.22.0", + "exec": "go test -v", + "exit": "-1", + "src": "src/constraints/underlying/broken", + "test": "-v" + }, + "expected_exit": -1, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "data-go-version", + "Val": "go1.22.0" + }, + { + "Namespace": "", + "Key": "exec", + "Val": "go test -v" + }, + { + "Namespace": "", + "Key": "exit", + "Val": "-1" + }, + { + "Namespace": "", + "Key": "src", + "Val": "src/constraints/underlying/broken" + }, + { + "Namespace": "", + "Key": "test", + "Val": "-v" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "test", + "-v" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/10-generics/src/constraints/underlying/broken", + "duration": "1.70567375s", + "err": "exit status 1", + "exit": 1, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go test -v\n\nFAIL\tdemo [build failed]\n\n# demo [demo.test]\n./keys_test.go:21:13: MyInt does not satisfy MapKey (possibly missing ~ for int in MapKey)", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "# demo [demo.test]\n./keys_test.go:21:13: MyInt does not satisfy MapKey (possibly missing ~ for int in MapKey)", + "stdout": "FAIL\tdemo [build failed]", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "test", + "-v" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/10-generics/src/constraints/underlying/broken", + "duration": "1.70567375s", + "err": "exit status 1", + "exit": 1, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go test -v\n\nFAIL\tdemo [build failed]\n\n# demo [demo.test]\n./keys_test.go:21:13: MyInt does not satisfy MapKey (possibly missing ~ for int in MapKey)", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "# demo [demo.test]\n./keys_test.go:21:13: MyInt does not satisfy MapKey (possibly missing ~ for int in MapKey)", + "stdout": "FAIL\tdemo [build failed]", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd data-go-version=\"go1.22.0\" exec=\"go test -v\" exit=\"-1\" src=\"src/constraints/underlying/broken\" test=\"-v\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.19:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "The ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "MyInt", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " type does not meet the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "int", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " constraint.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 19, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-19\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "The reason for the compilation in ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-19" + }, + "filename": "module.md", + "html_node": { + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-19" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.19", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-19\"\u003e", + "type": "hype.Link", + "url": "#listing-1-19" + } + ], + "tag": "\u003cref id=\"listing-1-19\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ", is that the type ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "MyInt", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": ", while based on ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "int", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": ", does not satisfy the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "MapKey", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " constraint because it is ", + "type": "hype.Text" + }, + { + "atom": "strong", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "strong", + "data_atom": "strong", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "not", + "type": "hype.Text" + } + ], + "tag": "\u003cstrong\u003e", + "type": "hype.Element" + }, + { + "text": " an ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "int", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " itself. When writing constraints we, usually, are interested in the underlying type, not the type that is wrapped by the type. To express this in when defining a constraint we can use the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "~", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " operator.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-20", + "type": "listing" + }, + "filename": "module.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "underlying.fixed" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "args": [ + "go", + "doc", + "-cmd", + "-u", + "-src", + "-short", + "MapKey" + ], + "atom": "cmd", + "attributes": { + "exec": "go doc -cmd -u -src -short MapKey", + "hide-cmd": "", + "language": "go", + "src": "src/constraints/underlying/fixed", + "sym": "MapKey" + }, + "expected_exit": 0, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "exec", + "Val": "go doc -cmd -u -src -short MapKey" + }, + { + "Namespace": "", + "Key": "hide-cmd", + "Val": "" + }, + { + "Namespace": "", + "Key": "language", + "Val": "go" + }, + { + "Namespace": "", + "Key": "src", + "Val": "src/constraints/underlying/fixed" + }, + { + "Namespace": "", + "Key": "sym", + "Val": "MapKey" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "doc", + "-cmd", + "-u", + "-src", + "-short", + "MapKey" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/10-generics/src/constraints/underlying/fixed", + "duration": "1.886565917s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "text": "// MapKey is a set of a constraints\n// on types that can be used as map keys.\ntype MapKey interface {\n\t~int\n}", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "// MapKey is a set of a constraints\n// on types that can be used as map keys.\ntype MapKey interface {\n\t~int\n}", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "doc", + "-cmd", + "-u", + "-src", + "-short", + "MapKey" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/10-generics/src/constraints/underlying/fixed", + "duration": "1.886565917s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "text": "// MapKey is a set of a constraints\n// on types that can be used as map keys.\ntype MapKey interface {\n\t~int\n}", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "// MapKey is a set of a constraints\n// on types that can be used as map keys.\ntype MapKey interface {\n\t~int\n}", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd exec=\"go doc -cmd -u -src -short MapKey\" hide-cmd=\"\" language=\"go\" src=\"src/constraints/underlying/fixed\" sym=\"MapKey\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.20:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "Using the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "~", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " operator to allow for super-types.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 20, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-20\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "By updating the constraint to use the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "~", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " operator, the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Keys", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " function will accept any type based on ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "int", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": ". Because ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "MyInt", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " is based on ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "int", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": ", we can now use the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Keys", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " function with a map using a key type of ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "MyInt", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": ".", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-21", + "type": "listing" + }, + "filename": "module.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "underlying.fixed" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "args": [ + "go", + "test", + "-v" + ], + "atom": "cmd", + "attributes": { + "data-go-version": "go1.22.0", + "exec": "go test -v", + "src": "src/constraints/underlying/fixed", + "test": "-v" + }, + "expected_exit": 0, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "data-go-version", + "Val": "go1.22.0" + }, + { + "Namespace": "", + "Key": "exec", + "Val": "go test -v" + }, + { + "Namespace": "", + "Key": "src", + "Val": "src/constraints/underlying/fixed" + }, + { + "Namespace": "", + "Key": "test", + "Val": "-v" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "test", + "-v" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/10-generics/src/constraints/underlying/fixed", + "duration": "4.797030334s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go test -v\n\n=== RUN Test_Keys\n=== PAUSE Test_Keys\n=== CONT Test_Keys\n--- PASS: Test_Keys (0.00s)\nPASS\nok \tdemo\t2.626s", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "=== RUN Test_Keys\n=== PAUSE Test_Keys\n=== CONT Test_Keys\n--- PASS: Test_Keys (0.00s)\nPASS\nok \tdemo\t2.626s", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "test", + "-v" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/10-generics/src/constraints/underlying/fixed", + "duration": "4.797030334s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go test -v\n\n=== RUN Test_Keys\n=== PAUSE Test_Keys\n=== CONT Test_Keys\n--- PASS: Test_Keys (0.00s)\nPASS\nok \tdemo\t2.626s", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "=== RUN Test_Keys\n=== PAUSE Test_Keys\n=== CONT Test_Keys\n--- PASS: Test_Keys (0.00s)\nPASS\nok \tdemo\t2.626s", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd data-go-version=\"go1.22.0\" exec=\"go test -v\" src=\"src/constraints/underlying/fixed\" test=\"-v\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.21:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "Tests now passing with the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "~", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " constraint operator.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 21, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-21\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "h2", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "h2", + "data_atom": "h2", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "level": 2, + "nodes": [ + { + "text": "The Constraints Package", + "type": "hype.Text" + } + ], + "tag": "\u003ch2\u003e", + "type": "hype.Heading" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "When generics were released in Go 1.18, the Go team, decided to be cautious and not update the standard library immediately to use them. They wanted to see how generics were being used before deciding to update the standard library. As a result of this, the Go team have create a series of packages in the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "golang.org/x/exp", + "href": "https://pkg.go.dev/golang.org/x/exp", + "target": "_blank" + }, + "filename": "module.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "golang.org/x/exp", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"golang.org/x/exp\" href=\"https://pkg.go.dev/golang.org/x/exp\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/golang.org/x/exp" + } + ], + { + "text": " namespace to experiment with generics. One of these packages is the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "golang.org/x/exp/constraints", + "href": "https://pkg.go.dev/golang.org/x/exp/constraints", + "target": "_blank" + }, + "filename": "module.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "golang.org/x/exp/constraints", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"golang.org/x/exp/constraints\" href=\"https://pkg.go.dev/golang.org/x/exp/constraints\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/golang.org/x/exp/constraints" + } + ], + { + "text": " package, ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-22" + }, + "filename": "module.md", + "html_node": { + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-22" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.22", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-22\"\u003e", + "type": "hype.Link", + "url": "#listing-1-22" + } + ], + "tag": "\u003cref id=\"listing-1-22\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ". The ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "golang.org/x/exp/constraints", + "href": "https://pkg.go.dev/golang.org/x/exp/constraints", + "target": "_blank" + }, + "filename": "module.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "golang.org/x/exp/constraints", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"golang.org/x/exp/constraints\" href=\"https://pkg.go.dev/golang.org/x/exp/constraints\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/golang.org/x/exp/constraints" + } + ], + { + "text": " package defines a set of constraints for all of the numerical, and comparable types in the language.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-22", + "type": "listing" + }, + "filename": "module.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "constraints.doc" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "args": [ + "go", + "doc", + "golang.org/x/exp/constraints" + ], + "atom": "cmd", + "attributes": { + "data-go-version": "go1.22.0", + "doc": "golang.org/x/exp/constraints", + "exec": "go doc golang.org/x/exp/constraints", + "src": "src/constraints/pkg" + }, + "expected_exit": 0, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "data-go-version", + "Val": "go1.22.0" + }, + { + "Namespace": "", + "Key": "doc", + "Val": "golang.org/x/exp/constraints" + }, + { + "Namespace": "", + "Key": "exec", + "Val": "go doc golang.org/x/exp/constraints" + }, + { + "Namespace": "", + "Key": "src", + "Val": "src/constraints/pkg" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "doc", + "golang.org/x/exp/constraints" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/10-generics/src/constraints/pkg", + "duration": "1.999971084s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go doc golang.org/x/exp/constraints\n\npackage constraints // import \u0026#34;golang.org/x/exp/constraints\u0026#34;\n\nPackage constraints defines a set of useful constraints to be used with type\nparameters.\n\ntype Complex interface{ ... }\ntype Float interface{ ... }\ntype Integer interface{ ... }\ntype Ordered interface{ ... }\ntype Signed interface{ ... }\ntype Unsigned interface{ ... }", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "package constraints // import \"golang.org/x/exp/constraints\"\n\nPackage constraints defines a set of useful constraints to be used with type\nparameters.\n\ntype Complex interface{ ... }\ntype Float interface{ ... }\ntype Integer interface{ ... }\ntype Ordered interface{ ... }\ntype Signed interface{ ... }\ntype Unsigned interface{ ... }", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "doc", + "golang.org/x/exp/constraints" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/10-generics/src/constraints/pkg", + "duration": "1.999971084s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go doc golang.org/x/exp/constraints\n\npackage constraints // import \u0026#34;golang.org/x/exp/constraints\u0026#34;\n\nPackage constraints defines a set of useful constraints to be used with type\nparameters.\n\ntype Complex interface{ ... }\ntype Float interface{ ... }\ntype Integer interface{ ... }\ntype Ordered interface{ ... }\ntype Signed interface{ ... }\ntype Unsigned interface{ ... }", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "package constraints // import \"golang.org/x/exp/constraints\"\n\nPackage constraints defines a set of useful constraints to be used with type\nparameters.\n\ntype Complex interface{ ... }\ntype Float interface{ ... }\ntype Integer interface{ ... }\ntype Ordered interface{ ... }\ntype Signed interface{ ... }\ntype Unsigned interface{ ... }", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd data-go-version=\"go1.22.0\" doc=\"golang.org/x/exp/constraints\" exec=\"go doc golang.org/x/exp/constraints\" src=\"src/constraints/pkg\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.22:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "The ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "golang.org/x/exp/constraints", + "href": "https://pkg.go.dev/golang.org/x/exp/constraints", + "target": "_blank" + }, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "for", + "Val": "golang.org/x/exp/constraints" + }, + { + "Namespace": "", + "Key": "href", + "Val": "https://pkg.go.dev/golang.org/x/exp/constraints" + }, + { + "Namespace": "", + "Key": "target", + "Val": "_blank" + } + ], + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": {}, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "golang.org/x/exp/constraints", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ] + ], + "tag": "\u003ca for=\"golang.org/x/exp/constraints\" href=\"https://pkg.go.dev/golang.org/x/exp/constraints\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/golang.org/x/exp/constraints" + } + ], + { + "text": " package.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 22, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-22\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "For example, consider the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "golang.org/x/exp/constraints#Signed", + "href": "https://pkg.go.dev/golang.org/x/exp/constraints#Signed", + "target": "_blank" + }, + "filename": "module.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "constraints.Signed", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"golang.org/x/exp/constraints#Signed\" href=\"https://pkg.go.dev/golang.org/x/exp/constraints#Signed\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/golang.org/x/exp/constraints#Signed" + } + ], + { + "text": " constraint, ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-23" + }, + "filename": "module.md", + "html_node": { + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-23" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.23", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-23\"\u003e", + "type": "hype.Link", + "url": "#listing-1-23" + } + ], + "tag": "\u003cref id=\"listing-1-23\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ". This constraint requires that the type be any of the signed integer types, ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "+/-", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " defined in the Go language, such ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "int", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " and ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "int64", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": ", and any types based on those types.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-23", + "type": "listing" + }, + "filename": "module.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "signed.doc" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "args": [ + "go", + "doc", + "golang.org/x/exp/constraints.Signed" + ], + "atom": "cmd", + "attributes": { + "data-go-version": "go1.22.0", + "doc": "golang.org/x/exp/constraints.Signed", + "exec": "go doc golang.org/x/exp/constraints.Signed", + "src": "src/constraints/pkg" + }, + "expected_exit": 0, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "data-go-version", + "Val": "go1.22.0" + }, + { + "Namespace": "", + "Key": "doc", + "Val": "golang.org/x/exp/constraints.Signed" + }, + { + "Namespace": "", + "Key": "exec", + "Val": "go doc golang.org/x/exp/constraints.Signed" + }, + { + "Namespace": "", + "Key": "src", + "Val": "src/constraints/pkg" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "doc", + "golang.org/x/exp/constraints.Signed" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/10-generics/src/constraints/pkg", + "duration": "1.624230959s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go doc golang.org/x/exp/constraints.Signed\n\npackage constraints // import \u0026#34;golang.org/x/exp/constraints\u0026#34;\n\ntype Signed interface {\n\t~int | ~int8 | ~int16 | ~int32 | ~int64\n}\n Signed is a constraint that permits any signed integer type. If future\n releases of Go add new predeclared signed integer types, this constraint\n will be modified to include them.", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "package constraints // import \"golang.org/x/exp/constraints\"\n\ntype Signed interface {\n\t~int | ~int8 | ~int16 | ~int32 | ~int64\n}\n Signed is a constraint that permits any signed integer type. If future\n releases of Go add new predeclared signed integer types, this constraint\n will be modified to include them.", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "doc", + "golang.org/x/exp/constraints.Signed" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/10-generics/src/constraints/pkg", + "duration": "1.624230959s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go doc golang.org/x/exp/constraints.Signed\n\npackage constraints // import \u0026#34;golang.org/x/exp/constraints\u0026#34;\n\ntype Signed interface {\n\t~int | ~int8 | ~int16 | ~int32 | ~int64\n}\n Signed is a constraint that permits any signed integer type. If future\n releases of Go add new predeclared signed integer types, this constraint\n will be modified to include them.", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "package constraints // import \"golang.org/x/exp/constraints\"\n\ntype Signed interface {\n\t~int | ~int8 | ~int16 | ~int32 | ~int64\n}\n Signed is a constraint that permits any signed integer type. If future\n releases of Go add new predeclared signed integer types, this constraint\n will be modified to include them.", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd data-go-version=\"go1.22.0\" doc=\"golang.org/x/exp/constraints.Signed\" exec=\"go doc golang.org/x/exp/constraints.Signed\" src=\"src/constraints/pkg\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.23:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "The ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "golang.org/x/exp/constraints#Signed", + "href": "https://pkg.go.dev/golang.org/x/exp/constraints#Signed", + "target": "_blank" + }, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "for", + "Val": "golang.org/x/exp/constraints#Signed" + }, + { + "Namespace": "", + "Key": "href", + "Val": "https://pkg.go.dev/golang.org/x/exp/constraints#Signed" + }, + { + "Namespace": "", + "Key": "target", + "Val": "_blank" + } + ], + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": {}, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "constraints.Signed", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ] + ], + "tag": "\u003ca for=\"golang.org/x/exp/constraints#Signed\" href=\"https://pkg.go.dev/golang.org/x/exp/constraints#Signed\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/golang.org/x/exp/constraints#Signed" + } + ], + { + "text": " constraint.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 23, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-23\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "The ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "golang.org/x/exp/constraints#Integer", + "href": "https://pkg.go.dev/golang.org/x/exp/constraints#Integer", + "target": "_blank" + }, + "filename": "module.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "constraints.Integer", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"golang.org/x/exp/constraints#Integer\" href=\"https://pkg.go.dev/golang.org/x/exp/constraints#Integer\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/golang.org/x/exp/constraints#Integer" + } + ], + { + "text": " constraint, ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-24" + }, + "filename": "module.md", + "html_node": { + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-24" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.24", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-24\"\u003e", + "type": "hype.Link", + "url": "#listing-1-24" + } + ], + "tag": "\u003cref id=\"listing-1-24\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ", requires the type to be based on ", + "type": "hype.Text" + }, + { + "atom": "strong", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "strong", + "data_atom": "strong", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "any", + "type": "hype.Text" + } + ], + "tag": "\u003cstrong\u003e", + "type": "hype.Element" + }, + { + "text": " integer type, signed or unsigned, such as ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "int", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": ", ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "int64", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": ", ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "uint", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": ", ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "uint64", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": ", etc.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-24", + "type": "listing" + }, + "filename": "module.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "integer.doc" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "args": [ + "go", + "doc", + "golang.org/x/exp/constraints.Integer" + ], + "atom": "cmd", + "attributes": { + "data-go-version": "go1.22.0", + "doc": "golang.org/x/exp/constraints.Integer", + "exec": "go doc golang.org/x/exp/constraints.Integer", + "src": "src/constraints/pkg" + }, + "expected_exit": 0, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "data-go-version", + "Val": "go1.22.0" + }, + { + "Namespace": "", + "Key": "doc", + "Val": "golang.org/x/exp/constraints.Integer" + }, + { + "Namespace": "", + "Key": "exec", + "Val": "go doc golang.org/x/exp/constraints.Integer" + }, + { + "Namespace": "", + "Key": "src", + "Val": "src/constraints/pkg" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "doc", + "golang.org/x/exp/constraints.Integer" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/10-generics/src/constraints/pkg", + "duration": "1.618140042s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go doc golang.org/x/exp/constraints.Integer\n\npackage constraints // import \u0026#34;golang.org/x/exp/constraints\u0026#34;\n\ntype Integer interface {\n\tSigned | Unsigned\n}\n Integer is a constraint that permits any integer type. If future releases\n of Go add new predeclared integer types, this constraint will be modified to\n include them.", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "package constraints // import \"golang.org/x/exp/constraints\"\n\ntype Integer interface {\n\tSigned | Unsigned\n}\n Integer is a constraint that permits any integer type. If future releases\n of Go add new predeclared integer types, this constraint will be modified to\n include them.", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "doc", + "golang.org/x/exp/constraints.Integer" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/10-generics/src/constraints/pkg", + "duration": "1.618140042s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go doc golang.org/x/exp/constraints.Integer\n\npackage constraints // import \u0026#34;golang.org/x/exp/constraints\u0026#34;\n\ntype Integer interface {\n\tSigned | Unsigned\n}\n Integer is a constraint that permits any integer type. If future releases\n of Go add new predeclared integer types, this constraint will be modified to\n include them.", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "package constraints // import \"golang.org/x/exp/constraints\"\n\ntype Integer interface {\n\tSigned | Unsigned\n}\n Integer is a constraint that permits any integer type. If future releases\n of Go add new predeclared integer types, this constraint will be modified to\n include them.", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd data-go-version=\"go1.22.0\" doc=\"golang.org/x/exp/constraints.Integer\" exec=\"go doc golang.org/x/exp/constraints.Integer\" src=\"src/constraints/pkg\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.24:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "The ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "golang.org/x/exp/constraints#Integer", + "href": "https://pkg.go.dev/golang.org/x/exp/constraints#Integer", + "target": "_blank" + }, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "for", + "Val": "golang.org/x/exp/constraints#Integer" + }, + { + "Namespace": "", + "Key": "href", + "Val": "https://pkg.go.dev/golang.org/x/exp/constraints#Integer" + }, + { + "Namespace": "", + "Key": "target", + "Val": "_blank" + } + ], + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": {}, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "constraints.Integer", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ] + ], + "tag": "\u003ca for=\"golang.org/x/exp/constraints#Integer\" href=\"https://pkg.go.dev/golang.org/x/exp/constraints#Integer\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/golang.org/x/exp/constraints#Integer" + } + ], + { + "text": " constraint.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 24, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-24\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "h3", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "h3", + "data_atom": "h3", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "level": 3, + "nodes": [ + { + "text": "The Ordered Constraint", + "type": "hype.Text" + } + ], + "tag": "\u003ch3\u003e", + "type": "hype.Heading" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "One of the most useful constraints defined in the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "golang.org/x/exp/constraints", + "href": "https://pkg.go.dev/golang.org/x/exp/constraints", + "target": "_blank" + }, + "filename": "module.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "golang.org/x/exp/constraints", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"golang.org/x/exp/constraints\" href=\"https://pkg.go.dev/golang.org/x/exp/constraints\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/golang.org/x/exp/constraints" + } + ], + { + "text": " package is the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "golang.org/x/exp/constraints#Ordered", + "href": "https://pkg.go.dev/golang.org/x/exp/constraints#Ordered", + "target": "_blank" + }, + "filename": "module.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "constraints.Ordered", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"golang.org/x/exp/constraints#Ordered\" href=\"https://pkg.go.dev/golang.org/x/exp/constraints#Ordered\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/golang.org/x/exp/constraints#Ordered" + } + ], + { + "text": " constraint, ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-25" + }, + "filename": "module.md", + "html_node": { + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-25" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.25", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-25\"\u003e", + "type": "hype.Link", + "url": "#listing-1-25" + } + ], + "tag": "\u003cref id=\"listing-1-25\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ". This constraint list all of the comparable types in the language, and any types based on those types. The ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "golang.org/x/exp/constraints#Ordered", + "href": "https://pkg.go.dev/golang.org/x/exp/constraints#Ordered", + "target": "_blank" + }, + "filename": "module.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "constraints.Ordered", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"golang.org/x/exp/constraints#Ordered\" href=\"https://pkg.go.dev/golang.org/x/exp/constraints#Ordered\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/golang.org/x/exp/constraints#Ordered" + } + ], + { + "text": " constraint covers all numerical types and strings.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-25", + "type": "listing" + }, + "filename": "module.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "ordered.doc" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "args": [ + "go", + "doc", + "golang.org/x/exp/constraints.Ordered" + ], + "atom": "cmd", + "attributes": { + "data-go-version": "go1.22.0", + "doc": "golang.org/x/exp/constraints.Ordered", + "exec": "go doc golang.org/x/exp/constraints.Ordered", + "src": "src/constraints/pkg" + }, + "expected_exit": 0, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "data-go-version", + "Val": "go1.22.0" + }, + { + "Namespace": "", + "Key": "doc", + "Val": "golang.org/x/exp/constraints.Ordered" + }, + { + "Namespace": "", + "Key": "exec", + "Val": "go doc golang.org/x/exp/constraints.Ordered" + }, + { + "Namespace": "", + "Key": "src", + "Val": "src/constraints/pkg" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "doc", + "golang.org/x/exp/constraints.Ordered" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/10-generics/src/constraints/pkg", + "duration": "2.109997291s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go doc golang.org/x/exp/constraints.Ordered\n\npackage constraints // import \u0026#34;golang.org/x/exp/constraints\u0026#34;\n\ntype Ordered interface {\n\tInteger | Float | ~string\n}\n Ordered is a constraint that permits any ordered type: any type that\n supports the operators \u0026lt; \u0026lt;= \u0026gt;= \u0026gt;. If future releases of Go add new ordered\n types, this constraint will be modified to include them.", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "package constraints // import \"golang.org/x/exp/constraints\"\n\ntype Ordered interface {\n\tInteger | Float | ~string\n}\n Ordered is a constraint that permits any ordered type: any type that\n supports the operators \u003c \u003c= \u003e= \u003e. If future releases of Go add new ordered\n types, this constraint will be modified to include them.", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "doc", + "golang.org/x/exp/constraints.Ordered" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/10-generics/src/constraints/pkg", + "duration": "2.109997291s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go doc golang.org/x/exp/constraints.Ordered\n\npackage constraints // import \u0026#34;golang.org/x/exp/constraints\u0026#34;\n\ntype Ordered interface {\n\tInteger | Float | ~string\n}\n Ordered is a constraint that permits any ordered type: any type that\n supports the operators \u0026lt; \u0026lt;= \u0026gt;= \u0026gt;. If future releases of Go add new ordered\n types, this constraint will be modified to include them.", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "package constraints // import \"golang.org/x/exp/constraints\"\n\ntype Ordered interface {\n\tInteger | Float | ~string\n}\n Ordered is a constraint that permits any ordered type: any type that\n supports the operators \u003c \u003c= \u003e= \u003e. If future releases of Go add new ordered\n types, this constraint will be modified to include them.", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd data-go-version=\"go1.22.0\" doc=\"golang.org/x/exp/constraints.Ordered\" exec=\"go doc golang.org/x/exp/constraints.Ordered\" src=\"src/constraints/pkg\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.25:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "The ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "golang.org/x/exp/constraints#Ordered", + "href": "https://pkg.go.dev/golang.org/x/exp/constraints#Ordered", + "target": "_blank" + }, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "for", + "Val": "golang.org/x/exp/constraints#Ordered" + }, + { + "Namespace": "", + "Key": "href", + "Val": "https://pkg.go.dev/golang.org/x/exp/constraints#Ordered" + }, + { + "Namespace": "", + "Key": "target", + "Val": "_blank" + } + ], + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": {}, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "constraints.Ordered", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ] + ], + "tag": "\u003ca for=\"golang.org/x/exp/constraints#Ordered\" href=\"https://pkg.go.dev/golang.org/x/exp/constraints#Ordered\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/golang.org/x/exp/constraints#Ordered" + } + ], + { + "text": " constraint.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 25, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-25\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "The ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "golang.org/x/exp/constraints#Ordered", + "href": "https://pkg.go.dev/golang.org/x/exp/constraints#Ordered", + "target": "_blank" + }, + "filename": "module.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "constraints.Ordered", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"golang.org/x/exp/constraints#Ordered\" href=\"https://pkg.go.dev/golang.org/x/exp/constraints#Ordered\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/golang.org/x/exp/constraints#Ordered" + } + ], + { + "text": " constraint is perfect for map keys because all of the types defined in the constraint are comparable. In ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-26" + }, + "filename": "module.md", + "html_node": { + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-26" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.26", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-26\"\u003e", + "type": "hype.Link", + "url": "#listing-1-26" + } + ], + "tag": "\u003cref id=\"listing-1-26\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ", the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Keys", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " function has been updated to use the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "golang.org/x/exp/constraints#Ordered", + "href": "https://pkg.go.dev/golang.org/x/exp/constraints#Ordered", + "target": "_blank" + }, + "filename": "module.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "constraints.Ordered", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"golang.org/x/exp/constraints#Ordered\" href=\"https://pkg.go.dev/golang.org/x/exp/constraints#Ordered\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/golang.org/x/exp/constraints#Ordered" + } + ], + { + "text": " constraint. We can now use the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Keys", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " function with a map using a key type of ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "string", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": ", or any other type that is comparable.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-26", + "type": "listing" + }, + "filename": "module.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "pkg.def" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "args": [ + "go", + "doc", + "-cmd", + "-u", + "-src", + "-short", + "Keys" + ], + "atom": "cmd", + "attributes": { + "exec": "go doc -cmd -u -src -short Keys", + "hide-cmd": "", + "language": "go", + "src": "src/constraints/pkg", + "sym": "Keys" + }, + "expected_exit": 0, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "exec", + "Val": "go doc -cmd -u -src -short Keys" + }, + { + "Namespace": "", + "Key": "hide-cmd", + "Val": "" + }, + { + "Namespace": "", + "Key": "language", + "Val": "go" + }, + { + "Namespace": "", + "Key": "src", + "Val": "src/constraints/pkg" + }, + { + "Namespace": "", + "Key": "sym", + "Val": "Keys" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "doc", + "-cmd", + "-u", + "-src", + "-short", + "Keys" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/10-generics/src/constraints/pkg", + "duration": "1.6278935s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "text": "func Keys[K constraints.Ordered, V any](m map[K]V) []K {\n\n\t// make a slice of the keys\n\tkeys := make([]K, 0, len(m))\n\n\t// iterate over the map\n\tfor k := range m {\n\n\t\t// add the key to the slice\n\t\tkeys = append(keys, k)\n\t}\n\n\t// return the keys\n\treturn keys\n}", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "func Keys[K constraints.Ordered, V any](m map[K]V) []K {\n\n\t// make a slice of the keys\n\tkeys := make([]K, 0, len(m))\n\n\t// iterate over the map\n\tfor k := range m {\n\n\t\t// add the key to the slice\n\t\tkeys = append(keys, k)\n\t}\n\n\t// return the keys\n\treturn keys\n}", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "doc", + "-cmd", + "-u", + "-src", + "-short", + "Keys" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/10-generics/src/constraints/pkg", + "duration": "1.6278935s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "text": "func Keys[K constraints.Ordered, V any](m map[K]V) []K {\n\n\t// make a slice of the keys\n\tkeys := make([]K, 0, len(m))\n\n\t// iterate over the map\n\tfor k := range m {\n\n\t\t// add the key to the slice\n\t\tkeys = append(keys, k)\n\t}\n\n\t// return the keys\n\treturn keys\n}", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "func Keys[K constraints.Ordered, V any](m map[K]V) []K {\n\n\t// make a slice of the keys\n\tkeys := make([]K, 0, len(m))\n\n\t// iterate over the map\n\tfor k := range m {\n\n\t\t// add the key to the slice\n\t\tkeys = append(keys, k)\n\t}\n\n\t// return the keys\n\treturn keys\n}", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd exec=\"go doc -cmd -u -src -short Keys\" hide-cmd=\"\" language=\"go\" src=\"src/constraints/pkg\" sym=\"Keys\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.26:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "The ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Keys", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " function definition.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 26, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-26\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "h2", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "h2", + "data_atom": "h2", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "level": 2, + "nodes": [ + { + "text": "Type Assertions", + "type": "hype.Text" + } + ], + "tag": "\u003ch2\u003e", + "type": "hype.Heading" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "When using constraints that are based on types, and not on methods like interfaces, type assertions are not allowed. For example, in ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-27" + }, + "filename": "module.md", + "html_node": { + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-27" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.27", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-27\"\u003e", + "type": "hype.Link", + "url": "#listing-1-27" + } + ], + "tag": "\u003cref id=\"listing-1-27\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ", the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Keys", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " functions tries to print each map key out to the console, but only if it implements the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "fmt#Stringer", + "href": "https://pkg.go.dev/fmt#Stringer", + "target": "_blank" + }, + "filename": "module.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "fmt.Stringer", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"fmt#Stringer\" href=\"https://pkg.go.dev/fmt#Stringer\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/fmt#Stringer" + } + ], + { + "text": " interface.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-27", + "type": "listing" + }, + "filename": "module.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "assertions/broken/keys.doc" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "args": [ + "go", + "doc", + "-cmd", + "-u", + "-src", + "-short", + "Keys" + ], + "atom": "cmd", + "attributes": { + "exec": "go doc -cmd -u -src -short Keys", + "hide-cmd": "", + "language": "go", + "src": "src/assertions/broken", + "sym": "Keys" + }, + "expected_exit": 0, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "exec", + "Val": "go doc -cmd -u -src -short Keys" + }, + { + "Namespace": "", + "Key": "hide-cmd", + "Val": "" + }, + { + "Namespace": "", + "Key": "language", + "Val": "go" + }, + { + "Namespace": "", + "Key": "src", + "Val": "src/assertions/broken" + }, + { + "Namespace": "", + "Key": "sym", + "Val": "Keys" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "doc", + "-cmd", + "-u", + "-src", + "-short", + "Keys" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/10-generics/src/assertions/broken", + "duration": "819.16875ms", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "text": "func Keys[K constraints.Ordered, V any](m map[K]V) []K {\n\n\t// make a slice of the keys\n\tkeys := make([]K, 0, len(m))\n\n\t// iterate over the map\n\tfor k := range m {\n\n\t\t// if k implements fmt.Stringer,\n\t\t// print the string representation\n\t\tif st, ok := k.(fmt.Stringer); ok {\n\t\t\tfmt.Println(st.String())\n\t\t}\n\n\t\t// add the key to the slice\n\t\tkeys = append(keys, k)\n\t}\n\n\t// return the keys\n\treturn keys\n}", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "func Keys[K constraints.Ordered, V any](m map[K]V) []K {\n\n\t// make a slice of the keys\n\tkeys := make([]K, 0, len(m))\n\n\t// iterate over the map\n\tfor k := range m {\n\n\t\t// if k implements fmt.Stringer,\n\t\t// print the string representation\n\t\tif st, ok := k.(fmt.Stringer); ok {\n\t\t\tfmt.Println(st.String())\n\t\t}\n\n\t\t// add the key to the slice\n\t\tkeys = append(keys, k)\n\t}\n\n\t// return the keys\n\treturn keys\n}", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "doc", + "-cmd", + "-u", + "-src", + "-short", + "Keys" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/10-generics/src/assertions/broken", + "duration": "819.16875ms", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "text": "func Keys[K constraints.Ordered, V any](m map[K]V) []K {\n\n\t// make a slice of the keys\n\tkeys := make([]K, 0, len(m))\n\n\t// iterate over the map\n\tfor k := range m {\n\n\t\t// if k implements fmt.Stringer,\n\t\t// print the string representation\n\t\tif st, ok := k.(fmt.Stringer); ok {\n\t\t\tfmt.Println(st.String())\n\t\t}\n\n\t\t// add the key to the slice\n\t\tkeys = append(keys, k)\n\t}\n\n\t// return the keys\n\treturn keys\n}", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "func Keys[K constraints.Ordered, V any](m map[K]V) []K {\n\n\t// make a slice of the keys\n\tkeys := make([]K, 0, len(m))\n\n\t// iterate over the map\n\tfor k := range m {\n\n\t\t// if k implements fmt.Stringer,\n\t\t// print the string representation\n\t\tif st, ok := k.(fmt.Stringer); ok {\n\t\t\tfmt.Println(st.String())\n\t\t}\n\n\t\t// add the key to the slice\n\t\tkeys = append(keys, k)\n\t}\n\n\t// return the keys\n\treturn keys\n}", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd exec=\"go doc -cmd -u -src -short Keys\" hide-cmd=\"\" language=\"go\" src=\"src/assertions/broken\" sym=\"Keys\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.27:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "The ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Keys", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " function with type assertions.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 27, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-27\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "With method based interfaces this is possible, but with constraints we can't make this sort of assertion, ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-28" + }, + "filename": "module.md", + "html_node": { + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-28" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.28", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-28\"\u003e", + "type": "hype.Link", + "url": "#listing-1-28" + } + ], + "tag": "\u003cref id=\"listing-1-28\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ".", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-28", + "type": "listing" + }, + "filename": "module.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "assertions/broken.test" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "args": [ + "go", + "test", + "-v" + ], + "atom": "cmd", + "attributes": { + "data-go-version": "go1.22.0", + "exec": "go test -v", + "exit": "-1", + "src": "src/assertions/broken", + "test": "-v" + }, + "expected_exit": -1, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "data-go-version", + "Val": "go1.22.0" + }, + { + "Namespace": "", + "Key": "exec", + "Val": "go test -v" + }, + { + "Namespace": "", + "Key": "exit", + "Val": "-1" + }, + { + "Namespace": "", + "Key": "src", + "Val": "src/assertions/broken" + }, + { + "Namespace": "", + "Key": "test", + "Val": "-v" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "test", + "-v" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/10-generics/src/assertions/broken", + "duration": "2.097518125s", + "err": "exit status 1", + "exit": 1, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go test -v\n\nFAIL\tdemo [build failed]\n\n# demo [demo.test]\n./keys.go:19:16: invalid operation: cannot use type assertion on type parameter value k (variable of type K constrained by constraints.Ordered)", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "# demo [demo.test]\n./keys.go:19:16: invalid operation: cannot use type assertion on type parameter value k (variable of type K constrained by constraints.Ordered)", + "stdout": "FAIL\tdemo [build failed]", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "test", + "-v" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/10-generics/src/assertions/broken", + "duration": "2.097518125s", + "err": "exit status 1", + "exit": 1, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go test -v\n\nFAIL\tdemo [build failed]\n\n# demo [demo.test]\n./keys.go:19:16: invalid operation: cannot use type assertion on type parameter value k (variable of type K constrained by constraints.Ordered)", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "# demo [demo.test]\n./keys.go:19:16: invalid operation: cannot use type assertion on type parameter value k (variable of type K constrained by constraints.Ordered)", + "stdout": "FAIL\tdemo [build failed]", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd data-go-version=\"go1.22.0\" exec=\"go test -v\" exit=\"-1\" src=\"src/assertions/broken\" test=\"-v\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.28:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "Compilation error making assertions on a constraint.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 28, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-28\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "As mentioned previously, at compile time, generic function calls are replaced with their concrete types instead. The result is a ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Keys", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " function that takes a map of ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "string", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " to ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "int", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " and returns a ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "[]string", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": ", ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-29" + }, + "filename": "module.md", + "html_node": { + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-29" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.29", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-29\"\u003e", + "type": "hype.Link", + "url": "#listing-1-29" + } + ], + "tag": "\u003cref id=\"listing-1-29\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ".", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-29", + "type": "listing" + }, + "filename": "module.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "assertions/static.doc" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "args": [ + "go", + "doc", + "-cmd", + "-u", + "-src", + "-short", + "Keys" + ], + "atom": "cmd", + "attributes": { + "exec": "go doc -cmd -u -src -short Keys", + "hide-cmd": "", + "language": "go", + "src": "src/assertions/static", + "sym": "Keys" + }, + "expected_exit": 0, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "exec", + "Val": "go doc -cmd -u -src -short Keys" + }, + { + "Namespace": "", + "Key": "hide-cmd", + "Val": "" + }, + { + "Namespace": "", + "Key": "language", + "Val": "go" + }, + { + "Namespace": "", + "Key": "src", + "Val": "src/assertions/static" + }, + { + "Namespace": "", + "Key": "sym", + "Val": "Keys" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "doc", + "-cmd", + "-u", + "-src", + "-short", + "Keys" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/10-generics/src/assertions/static", + "duration": "1.615217667s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "text": "func Keys(m map[string]int) []string {\n\n\t// make a slice of the keys\n\tkeys := make([]string, 0, len(m))\n\n\t// iterate over the map\n\tfor k := range m {\n\n\t\t// if k implements fmt.Stringer,\n\t\t// print the string representation\n\t\tif st, ok := k.(fmt.Stringer); ok {\n\t\t\tfmt.Println(st.String())\n\t\t}\n\n\t\t// add the key to the slice\n\t\tkeys = append(keys, k)\n\t}\n\n\t// return the keys\n\treturn keys\n}", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "func Keys(m map[string]int) []string {\n\n\t// make a slice of the keys\n\tkeys := make([]string, 0, len(m))\n\n\t// iterate over the map\n\tfor k := range m {\n\n\t\t// if k implements fmt.Stringer,\n\t\t// print the string representation\n\t\tif st, ok := k.(fmt.Stringer); ok {\n\t\t\tfmt.Println(st.String())\n\t\t}\n\n\t\t// add the key to the slice\n\t\tkeys = append(keys, k)\n\t}\n\n\t// return the keys\n\treturn keys\n}", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "doc", + "-cmd", + "-u", + "-src", + "-short", + "Keys" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/10-generics/src/assertions/static", + "duration": "1.615217667s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "text": "func Keys(m map[string]int) []string {\n\n\t// make a slice of the keys\n\tkeys := make([]string, 0, len(m))\n\n\t// iterate over the map\n\tfor k := range m {\n\n\t\t// if k implements fmt.Stringer,\n\t\t// print the string representation\n\t\tif st, ok := k.(fmt.Stringer); ok {\n\t\t\tfmt.Println(st.String())\n\t\t}\n\n\t\t// add the key to the slice\n\t\tkeys = append(keys, k)\n\t}\n\n\t// return the keys\n\treturn keys\n}", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "func Keys(m map[string]int) []string {\n\n\t// make a slice of the keys\n\tkeys := make([]string, 0, len(m))\n\n\t// iterate over the map\n\tfor k := range m {\n\n\t\t// if k implements fmt.Stringer,\n\t\t// print the string representation\n\t\tif st, ok := k.(fmt.Stringer); ok {\n\t\t\tfmt.Println(st.String())\n\t\t}\n\n\t\t// add the key to the slice\n\t\tkeys = append(keys, k)\n\t}\n\n\t// return the keys\n\treturn keys\n}", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd exec=\"go doc -cmd -u -src -short Keys\" hide-cmd=\"\" language=\"go\" src=\"src/assertions/static\" sym=\"Keys\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.29:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "The compiled output of a generic function.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 29, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-29\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "When looking at the compilation error for \"concrete\" representation of the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Keys", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " function the error is a little more clear.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-30", + "type": "listing" + }, + "filename": "module.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "assertions/static.test" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "args": [ + "go", + "test", + "-v" + ], + "atom": "cmd", + "attributes": { + "data-go-version": "go1.22.0", + "exec": "go test -v", + "exit": "-1", + "src": "src/assertions/static", + "test": "-v" + }, + "expected_exit": -1, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "data-go-version", + "Val": "go1.22.0" + }, + { + "Namespace": "", + "Key": "exec", + "Val": "go test -v" + }, + { + "Namespace": "", + "Key": "exit", + "Val": "-1" + }, + { + "Namespace": "", + "Key": "src", + "Val": "src/assertions/static" + }, + { + "Namespace": "", + "Key": "test", + "Val": "-v" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "test", + "-v" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/10-generics/src/assertions/static", + "duration": "1.382746541s", + "err": "exit status 1", + "exit": 1, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go test -v\n\nFAIL\tdemo [build failed]\n\n# demo [demo.test]\n./keys.go:17:16: invalid operation: k (variable of type string) is not an interface", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "# demo [demo.test]\n./keys.go:17:16: invalid operation: k (variable of type string) is not an interface", + "stdout": "FAIL\tdemo [build failed]", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "test", + "-v" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/10-generics/src/assertions/static", + "duration": "1.382746541s", + "err": "exit status 1", + "exit": 1, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go test -v\n\nFAIL\tdemo [build failed]\n\n# demo [demo.test]\n./keys.go:17:16: invalid operation: k (variable of type string) is not an interface", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "# demo [demo.test]\n./keys.go:17:16: invalid operation: k (variable of type string) is not an interface", + "stdout": "FAIL\tdemo [build failed]", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd data-go-version=\"go1.22.0\" exec=\"go test -v\" exit=\"-1\" src=\"src/assertions/static\" test=\"-v\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.30:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "Compilation error type asserting on a concrete type.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 30, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-30\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "In Go type assertions, such as those in ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-29" + }, + "filename": "module.md", + "html_node": { + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-29" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.29", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-29\"\u003e", + "type": "hype.Link", + "url": "#listing-1-29" + } + ], + "tag": "\u003cref id=\"listing-1-29\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ", against concrete types is not allowed. This is no reason to assert if ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "string", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " or ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "User", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " or another types implements the interface, because the compiler already if it can be done.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "h2", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "h2", + "data_atom": "h2", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "level": 2, + "nodes": [ + { + "text": "Mixing Method and Type Constraints", + "type": "hype.Text" + } + ], + "tag": "\u003ch2\u003e", + "type": "hype.Heading" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "When defining constraints we have to choose between type based constraints and method based constraints. For example, in ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-31" + }, + "filename": "module.md", + "html_node": { + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-31" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.31", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-31\"\u003e", + "type": "hype.Link", + "url": "#listing-1-31" + } + ], + "tag": "\u003cref id=\"listing-1-31\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ", we can can't define a constraint that is either ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "golang.org/x/exp/constraints#Ordered", + "href": "https://pkg.go.dev/golang.org/x/exp/constraints#Ordered", + "target": "_blank" + }, + "filename": "module.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "constraints.Ordered", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"golang.org/x/exp/constraints#Ordered\" href=\"https://pkg.go.dev/golang.org/x/exp/constraints#Ordered\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/golang.org/x/exp/constraints#Ordered" + } + ], + { + "text": " or ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "fmt#Stringer", + "href": "https://pkg.go.dev/fmt#Stringer", + "target": "_blank" + }, + "filename": "module.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "fmt.Stringer", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"fmt#Stringer\" href=\"https://pkg.go.dev/fmt#Stringer\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/fmt#Stringer" + } + ], + { + "text": ".", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-31", + "type": "listing" + }, + "filename": "module.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "mixed" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "args": [ + "go", + "doc", + "-cmd", + "-u", + "-src", + "-short", + "MapKey" + ], + "atom": "cmd", + "attributes": { + "exec": "go doc -cmd -u -src -short MapKey", + "hide-cmd": "", + "language": "go", + "src": "src/assertions/mixed", + "sym": "MapKey" + }, + "expected_exit": 0, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "exec", + "Val": "go doc -cmd -u -src -short MapKey" + }, + { + "Namespace": "", + "Key": "hide-cmd", + "Val": "" + }, + { + "Namespace": "", + "Key": "language", + "Val": "go" + }, + { + "Namespace": "", + "Key": "src", + "Val": "src/assertions/mixed" + }, + { + "Namespace": "", + "Key": "sym", + "Val": "MapKey" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "doc", + "-cmd", + "-u", + "-src", + "-short", + "MapKey" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/10-generics/src/assertions/mixed", + "duration": "1.913364959s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "text": "type MapKey interface {\n\tconstraints.Ordered | fmt.Stringer\n}", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "type MapKey interface {\n\tconstraints.Ordered | fmt.Stringer\n}", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "doc", + "-cmd", + "-u", + "-src", + "-short", + "MapKey" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/10-generics/src/assertions/mixed", + "duration": "1.913364959s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "text": "type MapKey interface {\n\tconstraints.Ordered | fmt.Stringer\n}", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "type MapKey interface {\n\tconstraints.Ordered | fmt.Stringer\n}", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd exec=\"go doc -cmd -u -src -short MapKey\" hide-cmd=\"\" language=\"go\" src=\"src/assertions/mixed\" sym=\"MapKey\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "args": [ + "go", + "doc", + "-cmd", + "-u", + "-src", + "-short", + "Keys" + ], + "atom": "cmd", + "attributes": { + "exec": "go doc -cmd -u -src -short Keys", + "hide-cmd": "", + "language": "go", + "src": "src/assertions/mixed", + "sym": "Keys" + }, + "expected_exit": 0, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "exec", + "Val": "go doc -cmd -u -src -short Keys" + }, + { + "Namespace": "", + "Key": "hide-cmd", + "Val": "" + }, + { + "Namespace": "", + "Key": "language", + "Val": "go" + }, + { + "Namespace": "", + "Key": "src", + "Val": "src/assertions/mixed" + }, + { + "Namespace": "", + "Key": "sym", + "Val": "Keys" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "doc", + "-cmd", + "-u", + "-src", + "-short", + "Keys" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/10-generics/src/assertions/mixed", + "duration": "1.3992135s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "text": "func Keys[K MapKey, V any](m map[K]V) []K {\n\n\t// make a slice of the keys\n\tkeys := make([]K, 0, len(m))\n\n\t// iterate over the map\n\tfor k := range m {\n\n\t\t// add the key to the slice\n\t\tkeys = append(keys, k)\n\t}\n\n\t// return the keys\n\treturn keys\n}", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "func Keys[K MapKey, V any](m map[K]V) []K {\n\n\t// make a slice of the keys\n\tkeys := make([]K, 0, len(m))\n\n\t// iterate over the map\n\tfor k := range m {\n\n\t\t// add the key to the slice\n\t\tkeys = append(keys, k)\n\t}\n\n\t// return the keys\n\treturn keys\n}", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "doc", + "-cmd", + "-u", + "-src", + "-short", + "Keys" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/10-generics/src/assertions/mixed", + "duration": "1.3992135s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "text": "func Keys[K MapKey, V any](m map[K]V) []K {\n\n\t// make a slice of the keys\n\tkeys := make([]K, 0, len(m))\n\n\t// iterate over the map\n\tfor k := range m {\n\n\t\t// add the key to the slice\n\t\tkeys = append(keys, k)\n\t}\n\n\t// return the keys\n\treturn keys\n}", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "func Keys[K MapKey, V any](m map[K]V) []K {\n\n\t// make a slice of the keys\n\tkeys := make([]K, 0, len(m))\n\n\t// iterate over the map\n\tfor k := range m {\n\n\t\t// add the key to the slice\n\t\tkeys = append(keys, k)\n\t}\n\n\t// return the keys\n\treturn keys\n}", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd exec=\"go doc -cmd -u -src -short Keys\" hide-cmd=\"\" language=\"go\" src=\"src/assertions/mixed\" sym=\"Keys\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "args": [ + "go", + "test", + "-v" + ], + "atom": "cmd", + "attributes": { + "data-go-version": "go1.22.0", + "exec": "go test -v", + "exit": "-1", + "src": "src/assertions/mixed", + "test": "-v" + }, + "expected_exit": -1, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "data-go-version", + "Val": "go1.22.0" + }, + { + "Namespace": "", + "Key": "exec", + "Val": "go test -v" + }, + { + "Namespace": "", + "Key": "exit", + "Val": "-1" + }, + { + "Namespace": "", + "Key": "src", + "Val": "src/assertions/mixed" + }, + { + "Namespace": "", + "Key": "test", + "Val": "-v" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "test", + "-v" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/10-generics/src/assertions/mixed", + "duration": "2.093682083s", + "err": "exit status 1", + "exit": 1, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go test -v\n\nFAIL\tdemo [build failed]\n\n# demo [demo.test]\n./keys.go:10:24: cannot use fmt.Stringer in union (fmt.Stringer contains methods)\n./keys.go:13:34: invalid map key type K (missing comparable constraint)", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "# demo [demo.test]\n./keys.go:10:24: cannot use fmt.Stringer in union (fmt.Stringer contains methods)\n./keys.go:13:34: invalid map key type K (missing comparable constraint)", + "stdout": "FAIL\tdemo [build failed]", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "test", + "-v" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/10-generics/src/assertions/mixed", + "duration": "2.093682083s", + "err": "exit status 1", + "exit": 1, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go test -v\n\nFAIL\tdemo [build failed]\n\n# demo [demo.test]\n./keys.go:10:24: cannot use fmt.Stringer in union (fmt.Stringer contains methods)\n./keys.go:13:34: invalid map key type K (missing comparable constraint)", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "# demo [demo.test]\n./keys.go:10:24: cannot use fmt.Stringer in union (fmt.Stringer contains methods)\n./keys.go:13:34: invalid map key type K (missing comparable constraint)", + "stdout": "FAIL\tdemo [build failed]", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd data-go-version=\"go1.22.0\" exec=\"go test -v\" exit=\"-1\" src=\"src/assertions/mixed\" test=\"-v\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.31:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "Compilation error mixing method and type constraints.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 31, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-31\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "h2", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "h2", + "data_atom": "h2", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "level": 2, + "nodes": [ + { + "text": "Generic Types", + "type": "hype.Text" + } + ], + "tag": "\u003ch2\u003e", + "type": "hype.Heading" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "In addition to functions, types can also be generic. If we consider building a data store we might define a generic type to represent a \"model\". In ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-32" + }, + "filename": "module.md", + "html_node": { + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-32" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.32", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-32\"\u003e", + "type": "hype.Link", + "url": "#listing-1-32" + } + ], + "tag": "\u003cref id=\"listing-1-32\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": " we define a ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Model", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " interface that defines a constraint that all implementations of the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Model", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " interface must satisfy. The ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Model", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " interface has a type constraint, ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "[T constraints.Ordered]", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": ". This constraint is now available for use on the interface's methods.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-32", + "type": "listing" + }, + "filename": "module.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "store.model.doc" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "args": [ + "go", + "doc", + "-cmd", + "-u", + "-src", + "-short", + "Model" + ], + "atom": "cmd", + "attributes": { + "exec": "go doc -cmd -u -src -short Model", + "hide-cmd": "", + "language": "go", + "src": "src/store", + "sym": "Model" + }, + "expected_exit": 0, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "exec", + "Val": "go doc -cmd -u -src -short Model" + }, + { + "Namespace": "", + "Key": "hide-cmd", + "Val": "" + }, + { + "Namespace": "", + "Key": "language", + "Val": "go" + }, + { + "Namespace": "", + "Key": "src", + "Val": "src/store" + }, + { + "Namespace": "", + "Key": "sym", + "Val": "Model" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "doc", + "-cmd", + "-u", + "-src", + "-short", + "Model" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/10-generics/src/store", + "duration": "1.650523833s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "text": "type Model[T constraints.Ordered] interface {\n\tID() T\n}", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "type Model[T constraints.Ordered] interface {\n\tID() T\n}", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "doc", + "-cmd", + "-u", + "-src", + "-short", + "Model" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/10-generics/src/store", + "duration": "1.650523833s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "text": "type Model[T constraints.Ordered] interface {\n\tID() T\n}", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "type Model[T constraints.Ordered] interface {\n\tID() T\n}", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd exec=\"go doc -cmd -u -src -short Model\" hide-cmd=\"\" language=\"go\" src=\"src/store\" sym=\"Model\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.32:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "The ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Model", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " interface with generics.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 32, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-32\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Now, in order to implement the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Model", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " interface, in ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-32" + }, + "filename": "module.md", + "html_node": { + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-32" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.32", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-32\"\u003e", + "type": "hype.Link", + "url": "#listing-1-32" + } + ], + "tag": "\u003cref id=\"listing-1-32\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ", a type needs a ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "ID()", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " method that returns a type listed in the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "golang.org/x/exp/constraints#Ordered", + "href": "https://pkg.go.dev/golang.org/x/exp/constraints#Ordered", + "target": "_blank" + }, + "filename": "module.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "constraints.Ordered", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"golang.org/x/exp/constraints#Ordered\" href=\"https://pkg.go.dev/golang.org/x/exp/constraints#Ordered\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/golang.org/x/exp/constraints#Ordered" + } + ], + { + "text": " constraint.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-33", + "type": "listing" + }, + "filename": "module.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "store.user.doc" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "args": [ + "go", + "doc", + "-cmd", + "-u", + "-src", + "-short", + "User" + ], + "atom": "cmd", + "attributes": { + "exec": "go doc -cmd -u -src -short User", + "hide-cmd": "", + "language": "go", + "src": "src/store", + "sym": "User" + }, + "expected_exit": 0, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "exec", + "Val": "go doc -cmd -u -src -short User" + }, + { + "Namespace": "", + "Key": "hide-cmd", + "Val": "" + }, + { + "Namespace": "", + "Key": "language", + "Val": "go" + }, + { + "Namespace": "", + "Key": "src", + "Val": "src/store" + }, + { + "Namespace": "", + "Key": "sym", + "Val": "User" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "doc", + "-cmd", + "-u", + "-src", + "-short", + "User" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/10-generics/src/store", + "duration": "1.420244916s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "text": "type User struct {\n\tEmail string\n}\n\nfunc (u User) ID() string", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "type User struct {\n\tEmail string\n}\n\nfunc (u User) ID() string", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "doc", + "-cmd", + "-u", + "-src", + "-short", + "User" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/10-generics/src/store", + "duration": "1.420244916s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "text": "type User struct {\n\tEmail string\n}\n\nfunc (u User) ID() string", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "type User struct {\n\tEmail string\n}\n\nfunc (u User) ID() string", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd exec=\"go doc -cmd -u -src -short User\" hide-cmd=\"\" language=\"go\" src=\"src/store\" sym=\"User\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.33:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "A ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "User", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " type that implements ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-32" + }, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "store.model.doc" + } + ], + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-32" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.32", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-32\"\u003e", + "type": "hype.Link", + "url": "#listing-1-32" + } + ], + "tag": "\u003cref id=\"listing-1-32\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ".", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 33, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-33\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "In ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-34" + }, + "filename": "module.md", + "html_node": { + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-34" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.34", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-34\"\u003e", + "type": "hype.Link", + "url": "#listing-1-34" + } + ], + "tag": "\u003cref id=\"listing-1-34\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": " we define a ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Store", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " struct type that has two type constraints, ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "[K constraints.Ordered]", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " and ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "[M Model[K]]", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": ". In this example we are using the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "K", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " constraint defined on the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Store", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " type to define the constraint on the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Model", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " type.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-34", + "type": "listing" + }, + "filename": "module.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "store.store.doc" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "args": [ + "go", + "doc", + "-cmd", + "-u", + "-src", + "-short", + "Store" + ], + "atom": "cmd", + "attributes": { + "exec": "go doc -cmd -u -src -short Store", + "hide-cmd": "", + "language": "go", + "src": "src/store", + "sym": "Store" + }, + "expected_exit": 0, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "exec", + "Val": "go doc -cmd -u -src -short Store" + }, + { + "Namespace": "", + "Key": "hide-cmd", + "Val": "" + }, + { + "Namespace": "", + "Key": "language", + "Val": "go" + }, + { + "Namespace": "", + "Key": "src", + "Val": "src/store" + }, + { + "Namespace": "", + "Key": "sym", + "Val": "Store" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "doc", + "-cmd", + "-u", + "-src", + "-short", + "Store" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/10-generics/src/store", + "duration": "1.864147083s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "text": "// Store is a map of models where the map key is any\n// comparable type and the map value is any type that\n// implements the Model constraint.\ntype Store[K constraints.Ordered, M Model[K]] struct {\n\tdata map[K]M\n}\n\nfunc (s Store[K, M]) Find(id K) (M, error)\nfunc (s *Store[K, M]) Insert(m M) error", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "// Store is a map of models where the map key is any\n// comparable type and the map value is any type that\n// implements the Model constraint.\ntype Store[K constraints.Ordered, M Model[K]] struct {\n\tdata map[K]M\n}\n\nfunc (s Store[K, M]) Find(id K) (M, error)\nfunc (s *Store[K, M]) Insert(m M) error", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "doc", + "-cmd", + "-u", + "-src", + "-short", + "Store" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/10-generics/src/store", + "duration": "1.864147083s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "text": "// Store is a map of models where the map key is any\n// comparable type and the map value is any type that\n// implements the Model constraint.\ntype Store[K constraints.Ordered, M Model[K]] struct {\n\tdata map[K]M\n}\n\nfunc (s Store[K, M]) Find(id K) (M, error)\nfunc (s *Store[K, M]) Insert(m M) error", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "// Store is a map of models where the map key is any\n// comparable type and the map value is any type that\n// implements the Model constraint.\ntype Store[K constraints.Ordered, M Model[K]] struct {\n\tdata map[K]M\n}\n\nfunc (s Store[K, M]) Find(id K) (M, error)\nfunc (s *Store[K, M]) Insert(m M) error", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd exec=\"go doc -cmd -u -src -short Store\" hide-cmd=\"\" language=\"go\" src=\"src/store\" sym=\"Store\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.34:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "The ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Store", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " type with generics.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 34, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-34\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "When defining methods on types that use generics, the receiver of the method needs to be instantiated with the appropriate concrete type or types. Consider the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Find", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " method on the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Store", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " type in ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-35" + }, + "filename": "module.md", + "html_node": { + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-35" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.35", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-35\"\u003e", + "type": "hype.Link", + "url": "#listing-1-35" + } + ], + "tag": "\u003cref id=\"listing-1-35\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ".", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-35", + "type": "listing" + }, + "filename": "module.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "store.find.doc" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "args": [ + "go", + "doc", + "-cmd", + "-u", + "-src", + "-short", + "Store.Find" + ], + "atom": "cmd", + "attributes": { + "exec": "go doc -cmd -u -src -short Store.Find", + "hide-cmd": "", + "language": "go", + "src": "src/store", + "sym": "Store.Find" + }, + "expected_exit": 0, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "exec", + "Val": "go doc -cmd -u -src -short Store.Find" + }, + { + "Namespace": "", + "Key": "hide-cmd", + "Val": "" + }, + { + "Namespace": "", + "Key": "language", + "Val": "go" + }, + { + "Namespace": "", + "Key": "src", + "Val": "src/store" + }, + { + "Namespace": "", + "Key": "sym", + "Val": "Store.Find" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "doc", + "-cmd", + "-u", + "-src", + "-short", + "Store.Find" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/10-generics/src/store", + "duration": "2.026967708s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "text": "func (s Store[K, M]) Find(id K) (M, error) {\n\tm, ok := s.data[id]\n\tif !ok {\n\t\treturn m, fmt.Errorf(\u0026#34;key not found %v\u0026#34;, id)\n\t}\n\n\treturn m, nil\n}", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "func (s Store[K, M]) Find(id K) (M, error) {\n\tm, ok := s.data[id]\n\tif !ok {\n\t\treturn m, fmt.Errorf(\"key not found %v\", id)\n\t}\n\n\treturn m, nil\n}", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "doc", + "-cmd", + "-u", + "-src", + "-short", + "Store.Find" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/10-generics/src/store", + "duration": "2.026967708s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "text": "func (s Store[K, M]) Find(id K) (M, error) {\n\tm, ok := s.data[id]\n\tif !ok {\n\t\treturn m, fmt.Errorf(\u0026#34;key not found %v\u0026#34;, id)\n\t}\n\n\treturn m, nil\n}", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "func (s Store[K, M]) Find(id K) (M, error) {\n\tm, ok := s.data[id]\n\tif !ok {\n\t\treturn m, fmt.Errorf(\"key not found %v\", id)\n\t}\n\n\treturn m, nil\n}", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd exec=\"go doc -cmd -u -src -short Store.Find\" hide-cmd=\"\" language=\"go\" src=\"src/store\" sym=\"Store.Find\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.35:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "The ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Find", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " method on the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Store", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " type.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 35, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-35\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "The receiver, ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "(s Store[K, M])", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": ", is instantiated with the concrete types that the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Store", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " type was instantiated with. Those types can also be used to define arguments and return values for these methods. In ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-36" + }, + "filename": "module.md", + "html_node": { + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-36" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.36", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-36\"\u003e", + "type": "hype.Link", + "url": "#listing-1-36" + } + ], + "tag": "\u003cref id=\"listing-1-36\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ", we initialize a new ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Store", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " type with the constraints of ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "string", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " and ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "User", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": ". In the tests we are able to work with the original concrete types, instead of interfaces backed by unknown types.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-36", + "type": "listing" + }, + "filename": "module.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "store.find.test" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "src": "src/store/store_test.go#example" + }, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/store/store_test.go#example" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "content": "func Test_Store_Insert(t *testing.T) {\n\tt.Parallel()\n\n\t// create a store\n\ts := \u0026Store[string, User]{\n\t\tdata: map[string]User{},\n\t}\n\n\t// create a user\n\texp := User{Email: \"kurt@exampl.com\"}\n\n\t// insert the user\n\terr := s.Insert(exp)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\t// retreive the user\n\tact, err := s.Find(exp.Email)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\t// assert the returned user is the same as the inserted user\n\tif exp.Email != act.Email {\n\t\tt.Fatalf(\"expected %v, got %v\", exp, act)\n\t}\n\n}", + "file": "src/store/store_test.go", + "lang": "go", + "name": "example", + "start": 7, + "end": 38 + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" src=\"src/store/store_test.go#example\"\u003e", + "type": "hype.SourceCode" + } + ] + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + }, + { + "atom": "hr", + "attributes": {}, + "filename": "", + "html_node": { + "data": "hr", + "data_atom": "hr", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [], + "tag": "\u003chr\u003e", + "type": "hype.Element" + }, + [ + { + "args": [ + "go", + "test", + "-v" + ], + "atom": "cmd", + "attributes": { + "data-go-version": "go1.22.0", + "exec": "go test -v", + "src": "src/store", + "test": "-v" + }, + "expected_exit": 0, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "data-go-version", + "Val": "go1.22.0" + }, + { + "Namespace": "", + "Key": "exec", + "Val": "go test -v" + }, + { + "Namespace": "", + "Key": "src", + "Val": "src/store" + }, + { + "Namespace": "", + "Key": "test", + "Val": "-v" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "test", + "-v" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/10-generics/src/store", + "duration": "4.153532625s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go test -v\n\n=== RUN Test_Store_Insert\n=== PAUSE Test_Store_Insert\n=== CONT Test_Store_Insert\n--- PASS: Test_Store_Insert (0.00s)\nPASS\nok \tdemo\t2.002s", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "=== RUN Test_Store_Insert\n=== PAUSE Test_Store_Insert\n=== CONT Test_Store_Insert\n--- PASS: Test_Store_Insert (0.00s)\nPASS\nok \tdemo\t2.002s", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "test", + "-v" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/10-generics/src/store", + "duration": "4.153532625s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go test -v\n\n=== RUN Test_Store_Insert\n=== PAUSE Test_Store_Insert\n=== CONT Test_Store_Insert\n--- PASS: Test_Store_Insert (0.00s)\nPASS\nok \tdemo\t2.002s", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "=== RUN Test_Store_Insert\n=== PAUSE Test_Store_Insert\n=== CONT Test_Store_Insert\n--- PASS: Test_Store_Insert (0.00s)\nPASS\nok \tdemo\t2.002s", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd data-go-version=\"go1.22.0\" exec=\"go test -v\" src=\"src/store\" test=\"-v\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.36:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "Testing the a type with constraints.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 36, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-36\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "tag": "\u003cpage\u003e", + "title": "Generics", + "type": "hype.Page" + } + ], + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "atom": "page", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "page", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "atom": "h1", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "h1", + "data_atom": "h1", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "level": 1, + "nodes": [ + { + "text": "Summary", + "type": "hype.Text" + } + ], + "tag": "\u003ch1\u003e", + "type": "hype.Heading" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "In this ", + "type": "hype.Text" + }, + { + "atom": "binding", + "attributes": { + "part": "" + }, + "filename": "module.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "part", + "Val": "" + } + ], + "data": "binding", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [], + "tag": "\u003cbinding part=\"\"\u003e", + "type": "hype.Element" + }, + { + "text": " we covered the basics of generics in Go. We learned how to define constraints, how to use constraints on types, and how to use constraints on methods. Generics is still new to Go, but it is a powerful tool that can be used to make your code more expressive and maintainable.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "tag": "\u003cpage\u003e", + "title": "Summary", + "type": "hype.Page" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "tag": "\u003cbody\u003e", + "type": "hype.Body" + } + ] + ], + "tag": "\u003chtml\u003e", + "type": "hype.Element" + } + ], + "tag": "", + "type": "hype.Element" + } + ], + "parser": { + "type": "hype.Parser", + "root": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/10-generics", + "section": 1, + "contents": "# Generics\n\n[Generics](https://en.wikipedia.org/wiki/Generic_programming) were first introduced to Go with the release of [Go 1.18](https://go.dev/blog/intro-generics). Go 1.18 was release in March of 2022, during the writing of this \u003cbinding whole\u003e\u003c/binding\u003e. We, like the Go team, have tried our best to present the current idioms and thoughts on the how, what, when, where, and why questions about generics in Go.\n\n## What are Generics?\n\nGeneric programming is a programming paradigm that allows us to stub out the implementation of a function with a type that will be provided later. This has benefits for both writing, and using, generic functions. With generics we can write functions that can work with multiple types directly, without having to write the same function multiple times, once for each type. When using generic functions, we can continue use our types as concrete types, instead of interface representations.\n\n## The Problem with Interfaces\n\nInterfaces in Go are a powerful concept that allows developers to create flexible and reusable code. Interfaces allow us to define a set of methods that describe the behavior of a type. Any type that implements those methods, and behaviors, is considered to implement that interface.\n\nWe have already discussed the benefits and drawbacks of interfaces earlier in this \u003cbinding whole\u003e\u003c/binding\u003e so we don't have to re-iterate the benefits of interfaces, but let's discuss some problems with interfaces. For example, consider the function defined in \u003cref id=\"keys.any.doc\"\u003e\u003c/ref\u003e, and the problem of how to write a function that will return the keys for a given map.\n\n\u003cfigure id=\"keys.any.doc\" type=\"listing\"\u003e\n\n\u003cgo src=\"src/keys/any\" sym=\"Keys\"\u003e\u003c/go\u003e\n\n\u003cfigcaption\u003eA function that returns the keys of a map.\u003c/figcaption\u003e\n\n\u003c/figure\u003e\n\nGo is a statically typed language and so we have to specify the type of the map that we want to get the keys from. A map needs to have both its key and value types specified. We also need to specify the type of slice this function will be returning. In order for this function to support all map types we need to use the `any`, or empty interface, type which will match any type.\n\nWhile this means we can write a function that we return a list of keys from a map, it also means that this function is difficult to use. Consider a test, \u003cref id=\"keys.any.test\"\u003e\u003c/ref\u003e, that tries use a map that isn't of type `map[any]any`. This code fails to compile because the type of map in the test is not compatible with the type of map required by the function.\n\n\u003cfigure id=\"keys.any.test\" type=\"listing\"\u003e\n\n\u003cgo src=\"src/keys/any\" test=\"-v\" code=\"keys_test.go#example\" exit=\"-1\"\u003e\u003c/go\u003e\n\n\u003cfigcaption\u003eCompilation error caused by a type mismatch.\u003c/figcaption\u003e\n\n\u003c/figure\u003e\n\nIn \u003cref id=\"keys.fixed\"\u003e\u003c/ref\u003e is an attempt to solve this problem. First, we need to create a new, interstitial map of the correct type, and copy all of the keys from the original map into the new map. The same is true of trying to handle the results. We need to loop through the returned slice of keys, asserts the keys are of the correct type, and then copy those values into a new slice of the correct type.\n\n\u003cfigure id=\"keys.fixed\" type=\"listing\"\u003e\n\n\u003cgo src=\"src/keys/fixed\" test=\"-v\" code=\"keys_test.go#example\"\u003e\u003c/go\u003e\n\n\u003cfigcaption\u003eCopying maps to satisfy a type constraint.\u003c/figcaption\u003e\n\n\u003c/figure\u003e\n\nWhile \u003cref id=\"keys.fixed\"\u003e\u003c/ref\u003e fixes the tests, it is a very cumbersome way to work with a function such as this. Generics, were designed to help solve exactly this sort of problem.\n\n## Type Constraints\n\nGenerics in Go introduced a new concept to the language, called Type Constraints. Type Constraints allow us to specify that a type fits within a certain set of constraints. This is useful when we want to write a function that can work with multiple types, but we want to be able to specify that the function can only work with a specific type.\n\nFor example, so far have been using an `int` for the key type in a map, and `string` for the value type. This is fine, but we can use generics to make this more flexible. We may want to use an `int32` or a `float64` for the key type, and `any` value for the value type.\n\nGenerics allows us to specify those types as constraints when defining a function or a type. Constraints are added with `[]` after the name of the function or type, but before any parameters. \u003cref id=\"anatomy\"\u003e\u003c/ref\u003e lays out the anatomy of a generic function.\n\n\u003cfigure id=\"anatomy\" type=\"listing\"\u003e\n\n```go\nfunc Name[constraints](parameters) (returns) {\n\t// ...\n}\n```\n\n\u003cfigcaption\u003eAnatomy of a generic function.\u003c/figcaption\u003e\n\n\u003c/figure\u003e\n\nFor example, in \u003cref id=\"slicer.doc\"\u003e\u003c/ref\u003e, we define a `Slicer` function that defines a constraint, type `T`, which can be of `any` type. That new `T` type can then be used in the function signature. In \u003cref id=\"slicer.doc\"\u003e\u003c/ref\u003e, the `Slicer` function will return a slice of `T` values.\n\n\u003cfigure id=\"slicer.doc\" type=\"listing\"\u003e\n\n\u003cgo src=\"src/slicer\" sym=\"Slicer\"\u003e\u003c/go\u003e\n\n\u003cfigcaption\u003eA generic function that returns a slice of values.\u003c/figcaption\u003e\n\n\u003c/figure\u003e\n\nWhen calling the `Slicer` function, as seen in \u003cref id=\"slicer.example\"\u003e\u003c/ref\u003e we can pass any type, and it returns a slice of that same type back.\n\n\u003cfigure id=\"slicer.example\" type=\"listing\"\u003e\n\n\u003cgo src=\"src/slicer\" test=\"-v\" code=\"slicer_test.go#example\"\u003e\u003c/go\u003e\n\n\u003cfigcaption\u003eCalling a generic function.\u003c/figcaption\u003e\n\n\u003c/figure\u003e\n\nIn our tests we passed a `string` type to the `Slicer` function. At compile time, sees that we are calling the `Slicer` function with a `string` type and then inserts a function with the appropriate typed signature. For example, by passing a `string` type to the `Slicer` function, the compiler generates a function that looks like \u003cref id=\"static.slicer.out\"\u003e\u003c/ref\u003e.\n\n\u003cfigure id=\"static.slicer.out\" type=\"listing\"\u003e\n\n\u003cgo src=\"src/slicer-static\" sym=\"Slicer\"\u003e\u003c/go\u003e\n\n\u003cfigcaption\u003eA static function that returns a slice of strings.\u003c/figcaption\u003e\n\n\u003c/figure\u003e\n\n## Multiple Generic Types\n\nWith an understanding of the basics of generics, let's revisit the `Keys` function in \u003cref\u003efixed.keys.dey\u003c/ref\u003e, and update it to support generics.\n\n\u003cfigure id=\"fixed.keys.dey\" type=\"listing\"\u003e\n\n\u003cgo src=\"src/keys/fixed\" sym=\"Keys\"\u003e\u003c/go\u003e\n\n\u003cfigcaption\u003eThe `Keys` function before generics.\u003c/figcaption\u003e\n\n\u003c/figure\u003e\n\nA map has both a key and a value type. We can use generics to specify which types are allowed to be used for both. In \u003cref\u003egeneric.start.def\u003c/ref\u003e, we can specify that the key type, `K`, must of a type `int`, but the value type, `V`, can be of any type.\n\n\u003cfigure id=\"generic.start.def\" type=\"listing\"\u003e\n\n\u003cgo src=\"src/keys/generic/start\" sym=\"Keys\"\u003e\u003c/go\u003e\n\n\u003cfigcaption\u003eThe `Keys` function after generics.\u003c/figcaption\u003e\n\n\u003c/figure\u003e\n\nWith the changes in \u003cref\u003egeneric.start.def\u003c/ref\u003e we can pass a map of key type `int` and a value type of `string` to the `Keys` function and it will return a slice of `int` values.\n\n\u003cfigure id=\"generic.start.test\" type=\"listing\"\u003e\n\n\u003cgo src=\"src/keys/generic/start\" test=\"-v\" code=\"keys_test.go#example\"\u003e\u003c/go\u003e\n\n\u003cfigcaption\u003eTests now passing after using generics in \u003cref\u003egeneric.start.def\u003c/ref\u003e.\u003c/figcaption\u003e\n\n\u003c/figure\u003e\n\nAs \u003cref\u003egeneric.start.test\u003c/ref\u003e shows, This however, doesn't work if we want to use a map key of type `string` or `float64`. To do this we will need to specify a bigger set of constraints for the key type.\n\n## Instantiating Generic Functions\n\nWhen calling a generic function, or creating a new value of a generic type, the Go compiler needs to know which types are being provided for the generic parameters. So far, we have been letting the Go compiler infer the types of the generic parameters based on the types of the values passed in. In \u003cref\u003einstantiation.broken\u003c/ref\u003e, a variable, `fn`, is being declared and initialized with the `Keys` function from \u003cref\u003egeneric.start.def\u003c/ref\u003e. When the `fn` variable is called, the compiler is unable to infer the types of the generic parameters. The result is a compilation error.\n\n\u003cfigure id=\"instantiation.broken\" type=\"listing\"\u003e\n\n\u003cgo src=\"src/instantiation/broken\" test=\"-v\" code=\"keys_test.go#example\" exit=\"-1\"\u003e\u003c/go\u003e\n\n\u003cfigcaption\u003eThe `Keys` function before instantiation.\u003c/figcaption\u003e\n\n\u003c/figure\u003e\n\nIn these situations we need to provide the compiler with the types of the generic parameters. In \u003cref\u003einstantiation.fixed\u003c/ref\u003e The types, `int` and `string`, are being provided when grabbing a reference to the `Keys` function for the variable `fn`.\n\n\u003cfigure id=\"instantiation.fixed\" type=\"listing\"\u003e\n\n\u003cgo src=\"src/instantiation/fixed\" test=\"-v\" code=\"keys_test.go#example\"\u003e\u003c/go\u003e\n\n\u003cfigcaption\u003eThe `Keys` function after instantiation.\u003c/figcaption\u003e\n\n\u003c/figure\u003e\n\n## Defining Constraints\n\nSo far we have been using pretty simple types, such as `int` and `any` for the key and value types. But what if we wanted to use more types than just these? To specify which types can be used for a generic parameter, we can use constraints. Constraints are defined in a similar way to interfaces, but instead of specifying a set of methods, we specify a set of types.\n\nAs a start we can define a constraint, \u003cref\u003emapkey.doc\u003c/ref\u003e that requires the type to be an `int`.\n\n\u003cfigure id=\"mapkey.doc\" type=\"listing\"\u003e\n\n\u003cgo src=\"src/constraints/defining\" sym=\"MapKey\"\u003e\u003c/go\u003e\n\n\u003cfigcaption\u003eA constraint that requires the type to be an `int`.\u003c/figcaption\u003e\n\n\u003c/figure\u003e\n\nWith the `MapKey` constraint defined in \u003cref\u003emapkey.doc\u003c/ref\u003e, we can update the `Keys` function to use it instead of `int` in \u003cref\u003edefining.def\u003c/ref\u003e\n\n\u003cfigure id=\"defining.def\" type=\"listing\"\u003e\n\n\u003ccode src=\"src/constraints/defining/keys.go#def\"\u003e\u003c/code\u003e\n\n\u003cfigcaption\u003eThe `Keys` function using the `MapKey` constraint.\u003c/figcaption\u003e\n\n\u003c/figure\u003e\n\n## Multiple Type Constraints\n\nCurrently, the `MapKey` constraint only allows an `int` to be used for the key. In \u003cref\u003efloats\u003c/ref\u003ewe to try and use the `Keys` function with a map using a key type of `float64`. The result is a compilation error.\n\n\u003cfigure id=\"floats\" type=\"listing\"\u003e\n\n\u003cgo src=\"src/constraints/floats\" test=\"-v\" code=\"keys_test.go#example\" exit=\"-1\"\u003e\u003c/go\u003e\n\n\u003cfigcaption\u003eThe `Keys` function with a `float64` key.\u003c/figcaption\u003e\n\n\u003c/figure\u003e\n\nWhen defining constraints we can use the `|` operator to create an intersection of constraints. For example, in \u003cref\u003eor.doc\u003c/ref\u003e we define a constraint that requires the key type to be either `int` or `float64`.\n\n\u003cfigure id=\"or.doc\" type=\"listing\"\u003e\n\n\u003cgo src=\"src/constraints/or\" sym=\"MapKey\"\u003e\u003c/go\u003e\n\n\u003cfigcaption\u003eA constraint that requires the key type to be either `int` or `float64`.\u003c/figcaption\u003e\n\n\u003c/figure\u003e\n\nWith the change to the `MapKey` constraint in \u003cref\u003eor.doc\u003c/ref\u003e, we can use the `Keys` function with a map using a key type of `float64`. The tests in \u003cref\u003eor.test\u003c/ref\u003e now pass.\n\n\u003cfigure id=\"or.test\" type=\"listing\"\u003e\n\n\u003cgo src=\"src/constraints/or\" test=\"-v\"\u003e\u003c/go\u003e\n\n\u003cfigcaption\u003eTests now passing with the `MapKey` constraint.\u003c/figcaption\u003e\n\n\u003c/figure\u003e\n\n## Underlying Type Constraints\n\nIn Go, we are allowed to create new types based on other types. For example, we can create a new type, `MyInt`, that is based on the `int` type.\n\n\u003cfigure id=\"myint.doc\" type=\"listing\"\u003e\n\n\u003cgo src=\"src/constraints/underlying/broken\" sym=\"MyInt\"\u003e\u003c/go\u003e\n\n\u003cfigcaption\u003eA new type based on the `int` type.\u003c/figcaption\u003e\n\n\u003c/figure\u003e\n\nHowever, when we try to use the `Keys` function with a map using a key type of `MyInt` we will get a compile error.\n\n\u003cfigure id=\"underlying.broken\" type=\"listing\"\u003e\n\n\u003cgo src=\"src/constraints/underlying/broken\" test=\"-v\" code=\"keys_test.go#example\" exit=\"-1\"\u003e\u003c/go\u003e\n\n\u003cfigcaption\u003eThe `MyInt` type does not meet the `int` constraint.\u003c/figcaption\u003e\n\n\u003c/figure\u003e\n\nThe reason for the compilation in \u003cref\u003eunderlying.broken\u003c/ref\u003e, is that the type `MyInt`, while based on `int`, does not satisfy the `MapKey` constraint because it is **not** an `int` itself. When writing constraints we, usually, are interested in the underlying type, not the type that is wrapped by the type. To express this in when defining a constraint we can use the `~` operator.\n\n\u003cfigure id=\"underlying.fixed\" type=\"listing\"\u003e\n\n\u003cgo src=\"src/constraints/underlying/fixed\" sym=\"MapKey\"\u003e\u003c/go\u003e\n\n\u003cfigcaption\u003eUsing the `~` operator to allow for super-types.\u003c/figcaption\u003e\n\n\u003c/figure\u003e\n\nBy updating the constraint to use the `~` operator, the `Keys` function will accept any type based on `int`. Because `MyInt` is based on `int`, we can now use the `Keys` function with a map using a key type of `MyInt`.\n\n\u003cfigure id=\"underlying.fixed\" type=\"listing\"\u003e\n\n\u003cgo src=\"src/constraints/underlying/fixed\" test=\"-v\"\u003e\u003c/go\u003e\n\n\u003cfigcaption\u003eTests now passing with the `~` constraint operator.\u003c/figcaption\u003e\n\n\u003c/figure\u003e\n\n## The Constraints Package\n\nWhen generics were released in Go 1.18, the Go team, decided to be cautious and not update the standard library immediately to use them. They wanted to see how generics were being used before deciding to update the standard library. As a result of this, the Go team have create a series of packages in the \u003cgodoc\u003egolang.org/x/exp\u003c/godoc\u003e namespace to experiment with generics. One of these packages is the \u003cgodoc\u003egolang.org/x/exp/constraints\u003c/godoc\u003e package, \u003cref\u003econstraints.doc\u003c/ref\u003e. The \u003cgodoc\u003egolang.org/x/exp/constraints\u003c/godoc\u003e package defines a set of constraints for all of the numerical, and comparable types in the language.\n\n\u003cfigure id=\"constraints.doc\" type=\"listing\"\u003e\n\n\u003cgo src=\"src/constraints/pkg\" doc=\"golang.org/x/exp/constraints\"\u003e\u003c/go\u003e\n\n\u003cfigcaption\u003eThe \u003cgodoc\u003egolang.org/x/exp/constraints\u003c/godoc\u003e package.\u003c/figcaption\u003e\n\n\u003c/figure\u003e\n\nFor example, consider the \u003cgodoc\u003egolang.org/x/exp/constraints#Signed\u003c/godoc\u003e constraint, \u003cref\u003esigned.doc\u003c/ref\u003e. This constraint requires that the type be any of the signed integer types, `+/-` defined in the Go language, such `int` and `int64`, and any types based on those types.\n\n\u003cfigure id=\"signed.doc\" type=\"listing\"\u003e\n\n\u003cgo src=\"src/constraints/pkg\" doc=\"golang.org/x/exp/constraints.Signed\"\u003e\u003c/go\u003e\n\n\u003cfigcaption\u003eThe \u003cgodoc\u003egolang.org/x/exp/constraints#Signed\u003c/godoc\u003e constraint.\u003c/figcaption\u003e\n\n\u003c/figure\u003e\n\nThe \u003cgodoc\u003egolang.org/x/exp/constraints#Integer\u003c/godoc\u003e constraint, \u003cref\u003einteger.doc\u003c/ref\u003e, requires the type to be based on **any** integer type, signed or unsigned, such as `int`, `int64`, `uint`, `uint64`, etc.\n\n\u003cfigure id=\"integer.doc\" type=\"listing\"\u003e\n\n\u003cgo src=\"src/constraints/pkg\" doc=\"golang.org/x/exp/constraints.Integer\"\u003e\u003c/go\u003e\n\n\u003cfigcaption\u003eThe \u003cgodoc\u003egolang.org/x/exp/constraints#Integer\u003c/godoc\u003e constraint.\u003c/figcaption\u003e\n\n\u003c/figure\u003e\n\n### The Ordered Constraint\n\nOne of the most useful constraints defined in the \u003cgodoc\u003egolang.org/x/exp/constraints\u003c/godoc\u003e package is the \u003cgodoc\u003egolang.org/x/exp/constraints#Ordered\u003c/godoc\u003e constraint, \u003cref\u003eordered.doc\u003c/ref\u003e. This constraint list all of the comparable types in the language, and any types based on those types. The \u003cgodoc\u003egolang.org/x/exp/constraints#Ordered\u003c/godoc\u003e constraint covers all numerical types and strings.\n\n\u003cfigure id=\"ordered.doc\" type=\"listing\"\u003e\n\n\u003cgo src=\"src/constraints/pkg\" doc=\"golang.org/x/exp/constraints.Ordered\"\u003e\u003c/go\u003e\n\n\u003cfigcaption\u003eThe \u003cgodoc\u003egolang.org/x/exp/constraints#Ordered\u003c/godoc\u003e constraint.\u003c/figcaption\u003e\n\n\u003c/figure\u003e\n\nThe \u003cgodoc\u003egolang.org/x/exp/constraints#Ordered\u003c/godoc\u003e constraint is perfect for map keys because all of the types defined in the constraint are comparable. In \u003cref\u003epkg.def\u003c/ref\u003e, the `Keys` function has been updated to use the \u003cgodoc\u003egolang.org/x/exp/constraints#Ordered\u003c/godoc\u003e constraint. We can now use the `Keys` function with a map using a key type of `string`, or any other type that is comparable.\n\n\u003cfigure id=\"pkg.def\" type=\"listing\"\u003e\n\n\u003cgo src=\"src/constraints/pkg\" sym=\"Keys\"\u003e\u003c/go\u003e\n\n\u003cfigcaption\u003eThe `Keys` function definition.\u003c/figcaption\u003e\n\n\u003c/figure\u003e\n\n## Type Assertions\n\nWhen using constraints that are based on types, and not on methods like interfaces, type assertions are not allowed. For example, in \u003cref\u003eassertions/broken/keys.doc\u003c/ref\u003e, the `Keys` functions tries to print each map key out to the console, but only if it implements the \u003cgodoc\u003efmt#Stringer\u003c/godoc\u003e interface.\n\n\u003cfigure id=\"assertions/broken/keys.doc\" type=\"listing\"\u003e\n\n\u003cgo src=\"src/assertions/broken\" sym=\"Keys\"\u003e\u003c/go\u003e\n\n\u003cfigcaption\u003eThe `Keys` function with type assertions.\u003c/figcaption\u003e\n\n\u003c/figure\u003e\n\nWith method based interfaces this is possible, but with constraints we can't make this sort of assertion, \u003cref\u003eassertions/broken.test\u003c/ref\u003e.\n\n\u003cfigure id=\"assertions/broken.test\" type=\"listing\"\u003e\n\n\u003cgo src=\"src/assertions/broken\" test=\"-v\" exit=\"-1\"\u003e\u003c/go\u003e\n\n\u003cfigcaption\u003eCompilation error making assertions on a constraint.\u003c/figcaption\u003e\n\n\u003c/figure\u003e\n\nAs mentioned previously, at compile time, generic function calls are replaced with their concrete types instead. The result is a `Keys` function that takes a map of `string` to `int` and returns a `[]string`, \u003cref\u003eassertions/static.doc\u003c/ref\u003e.\n\n\u003cfigure id=\"assertions/static.doc\" type=\"listing\"\u003e\n\n\u003cgo src=\"src/assertions/static\" sym=\"Keys\"\u003e\u003c/go\u003e\n\n\u003cfigcaption\u003eThe compiled output of a generic function.\u003c/figcaption\u003e\n\n\u003c/figure\u003e\n\nWhen looking at the compilation error for \"concrete\" representation of the `Keys` function the error is a little more clear.\n\n\u003cfigure id=\"assertions/static.test\" type=\"listing\"\u003e\n\n\u003cgo src=\"src/assertions/static\" test=\"-v\" exit=\"-1\"\u003e\u003c/go\u003e\n\n\u003cfigcaption\u003eCompilation error type asserting on a concrete type.\u003c/figcaption\u003e\n\n\u003c/figure\u003e\n\nIn Go type assertions, such as those in \u003cref\u003eassertions/static.doc\u003c/ref\u003e, against concrete types is not allowed. This is no reason to assert if `string` or `User` or another types implements the interface, because the compiler already if it can be done.\n\n## Mixing Method and Type Constraints\n\nWhen defining constraints we have to choose between type based constraints and method based constraints. For example, in \u003cref\u003emixed\u003c/ref\u003e, we can can't define a constraint that is either \u003cgodoc\u003egolang.org/x/exp/constraints#Ordered\u003c/godoc\u003e or \u003cgodoc\u003efmt#Stringer\u003c/godoc\u003e.\n\n\u003cfigure id=\"mixed\" type=\"listing\"\u003e\n\n\u003cgo src=\"src/assertions/mixed\" sym=\"MapKey\"\u003e\u003c/go\u003e\n\n\u003cgo src=\"src/assertions/mixed\" sym=\"Keys\"\u003e\u003c/go\u003e\n\n\u003cgo src=\"src/assertions/mixed\" test=\"-v\" exit=\"-1\"\u003e\u003c/go\u003e\n\n\u003cfigcaption\u003eCompilation error mixing method and type constraints.\u003c/figcaption\u003e\n\n\u003c/figure\u003e\n\n## Generic Types\n\nIn addition to functions, types can also be generic. If we consider building a data store we might define a generic type to represent a \"model\". In \u003cref\u003estore.model.doc\u003c/ref\u003e we define a `Model` interface that defines a constraint that all implementations of the `Model` interface must satisfy. The `Model` interface has a type constraint, `[T constraints.Ordered]`. This constraint is now available for use on the interface's methods.\n\n\u003cfigure id=\"store.model.doc\" type=\"listing\"\u003e\n\n\u003cgo src=\"src/store\" sym=\"Model\"\u003e\u003c/go\u003e\n\n\u003cfigcaption\u003eThe `Model` interface with generics.\u003c/figcaption\u003e\n\n\u003c/figure\u003e\n\nNow, in order to implement the `Model` interface, in \u003cref\u003estore.model.doc\u003c/ref\u003e, a type needs a `ID()` method that returns a type listed in the \u003cgodoc\u003egolang.org/x/exp/constraints#Ordered\u003c/godoc\u003e constraint.\n\n\u003cfigure id=\"store.user.doc\" type=\"listing\"\u003e\n\n\u003cgo src=\"src/store\" sym=\"User\"\u003e\u003c/go\u003e\n\n\u003cfigcaption\u003eA `User` type that implements \u003cref\u003estore.model.doc\u003c/ref\u003e.\u003c/figcaption\u003e\n\n\u003c/figure\u003e\n\nIn \u003cref\u003estore.store.doc\u003c/ref\u003e we define a `Store` struct type that has two type constraints, `[K constraints.Ordered]` and `[M Model[K]]`. In this example we are using the `K` constraint defined on the `Store` type to define the constraint on the `Model` type.\n\n\u003cfigure id=\"store.store.doc\" type=\"listing\"\u003e\n\n\u003cgo src=\"src/store\" sym=\"Store\"\u003e\u003c/go\u003e\n\n\u003cfigcaption\u003eThe `Store` type with generics.\u003c/figcaption\u003e\n\n\u003c/figure\u003e\n\nWhen defining methods on types that use generics, the receiver of the method needs to be instantiated with the appropriate concrete type or types. Consider the `Find` method on the `Store` type in \u003cref\u003estore.find.doc\u003c/ref\u003e.\n\n\u003cfigure id=\"store.find.doc\" type=\"listing\"\u003e\n\n\u003cgo src=\"src/store\" sym=\"Store.Find\"\u003e\u003c/go\u003e\n\n\u003cfigcaption\u003eThe `Find` method on the `Store` type.\u003c/figcaption\u003e\n\n\u003c/figure\u003e\n\nThe receiver, `(s Store[K, M])`, is instantiated with the concrete types that the `Store` type was instantiated with. Those types can also be used to define arguments and return values for these methods. In \u003cref\u003estore.find.test\u003c/ref\u003e, we initialize a new `Store` type with the constraints of `string` and `User`. In the tests we are able to work with the original concrete types, instead of interfaces backed by unknown types.\n\n\u003cfigure id=\"store.find.test\" type=\"listing\"\u003e\n\n\u003cgo src=\"src/store\" test=\"-v\" code=\"store_test.go#example\"\u003e\u003c/go\u003e\n\n\u003cfigcaption\u003eTesting the a type with constraints.\u003c/figcaption\u003e\n\n\u003c/figure\u003e\n\n---\n\n# Summary\n\nIn this \u003cbinding part\u003e\u003c/binding\u003e we covered the basics of generics in Go. We learned how to define constraints, how to use constraints on types, and how to use constraints on methods. Generics is still new to Go, but it is a powerful tool that can be used to make your code more expressive and maintainable.\n" + }, + "root": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/10-generics", + "section_id": 1, + "snippets": { + "rules": { + ".go": "// %s", + ".html": "\u003c!-- %s --\u003e", + ".js": "// %s", + ".md": "\u003c!-- %s --\u003e", + ".rb": "# %s", + ".ts": "// %s" + }, + "snippets": { + "src/constraints/defining/keys.go": { + "def": { + "content": "func Keys[K MapKey, V any](m map[K]V) []K {\n\n\t// make a slice of the keys\n\tkeys := make([]K, 0, len(m))\n\n\t// iterate over the map\n\tfor k := range m {\n\n\t\t// add the key to the slice\n\t\tkeys = append(keys, k)\n\t}\n\n\t// return the keys\n\treturn keys\n}", + "file": "src/constraints/defining/keys.go", + "lang": "go", + "name": "def", + "start": 9, + "end": 26 + } + }, + "src/constraints/floats/keys_test.go": { + "example": { + "content": "// create a map with some values\nm := map[float64]string{\n\t1.1: \"one\",\n\t2.2: \"two\",\n\t3.3: \"three\",\n}\n\n// get the keys\nact := Keys(m)\n\n// sort the returned keys for comparison\nsort.Slice(act, func(i, j int) bool {\n\treturn act[i] \u003c act[j]\n})\n\n// set the expected values\nexp := []float64{1.1, 2.2, 3.3}\n\n// assert the length of the actual and expected values\nif len(exp) != len(act) {\n\tt.Fatalf(\"expected len(%d), but got len(%d)\", len(exp), len(act))\n}\n\n// assert the types of the actual and expected values\nat := fmt.Sprintf(\"%T\", act)\net := fmt.Sprintf(\"%T\", exp)\n\nif at != et {\n\tt.Fatalf(\"expected type %s, but got type %s\", et, at)\n}\n\n// loop through the expected values and\n// assert they are in the actual values\nfor i, v := range exp {\n\tif v != act[i] {\n\t\tt.Fatalf(\"expected %d, but got %d\", v, act[i])\n\t}\n}", + "file": "src/constraints/floats/keys_test.go", + "lang": "go", + "name": "example", + "start": 12, + "end": 51 + } + }, + "src/constraints/underlying/broken/keys_test.go": { + "example": { + "content": "func Test_Keys(t *testing.T) {\n\tt.Parallel()\n\n\t// create a map with some values\n\tm := map[MyInt]string{\n\t\t1: \"one\",\n\t\t2: \"two\",\n\t\t3: \"three\",\n\t}\n\n\t// get the keys\n\tact := Keys(m)\n\n\t// sort the returned keys for comparison\n\tsort.Slice(act, func(i, j int) bool {\n\t\treturn act[i] \u003c act[j]\n\t})\n\n\t// set the expected values\n\texp := []MyInt{1, 2, 3}\n\n\t// assert the length of the actual and expected values\n\tif len(exp) != len(act) {\n\t\tt.Fatalf(\"expected len(%d), but got len(%d)\", len(exp), len(act))\n\t}\n\n\t// assert the types of the actual and expected values\n\tat := fmt.Sprintf(\"%T\", act)\n\tet := fmt.Sprintf(\"%T\", exp)\n\n\tif at != et {\n\t\tt.Fatalf(\"expected type %s, but got type %s\", et, at)\n\t}\n\n\t// loop through the expected values and\n\t// assert they are in the actual values\n\tfor i, v := range exp {\n\t\tif v != act[i] {\n\t\t\tt.Fatalf(\"expected %d, but got %d\", v, act[i])\n\t\t}\n\t}\n\n}", + "file": "src/constraints/underlying/broken/keys_test.go", + "lang": "go", + "name": "example", + "start": 9, + "end": 54 + } + }, + "src/instantiation/broken/keys_test.go": { + "example": { + "content": "// create a function variable pointing\n// to the Keys function\nfn := Keys\n\n// get the keys\nact := fn(m)", + "file": "src/instantiation/broken/keys_test.go", + "lang": "go", + "name": "example", + "start": 19, + "end": 26 + } + }, + "src/instantiation/fixed/keys_test.go": { + "example": { + "content": "// create a function variable pointing\n// to the Keys function\nfn := Keys[int, string]\n\n// get the keys\nact := fn(m)", + "file": "src/instantiation/fixed/keys_test.go", + "lang": "go", + "name": "example", + "start": 19, + "end": 26 + } + }, + "src/keys/any/keys_test.go": { + "example": { + "content": "func Test_Keys(t *testing.T) {\n\tt.Parallel()\n\n\t// create a map with some values\n\tm := map[int]string{\n\t\t1: \"one\",\n\t\t2: \"two\",\n\t\t3: \"three\",\n\t}\n\n\t// get the keys\n\tact := Keys(m)\n\n\t// sort the returned keys for comparison\n\tsort.Slice(act, func(i, j int) bool {\n\t\treturn act[i] \u003c act[j]\n\t})\n\n\t// set the expected values\n\texp := []int{1, 2, 3}\n\n\t// assert the length of the actual and expected values\n\tal := len(act)\n\tel := len(exp)\n\tif al != el {\n\t\tt.Fatalf(\"expected %d, but got %d\", el, al)\n\t}\n\n\t// loop through the expected values and\n\t// assert they are in the actual values\n\tfor i, v := range exp {\n\t\tif v != act[i] {\n\t\t\tt.Fatalf(\"expected %d, but got %d\", v, act[i])\n\t\t}\n\t}\n\n}", + "file": "src/keys/any/keys_test.go", + "lang": "go", + "name": "example", + "start": 8, + "end": 47 + } + }, + "src/keys/fixed/keys_test.go": { + "example": { + "content": "func Test_Keys(t *testing.T) {\n\tt.Parallel()\n\n\t// create a map with some values\n\tm := map[int]string{\n\t\t1: \"one\",\n\t\t2: \"two\",\n\t\t3: \"three\",\n\t}\n\n\t// create an interstitial map to pass to the function\n\tim := map[any]any{}\n\n\t// copy the map into the interstitial map\n\tfor k, v := range m {\n\t\tim[k] = v\n\t}\n\n\t// get the keys\n\tkeys := Keys(im)\n\n\t// create a slice to hold the keys as\n\t// integers for comparison\n\tact := make([]int, 0, len(keys))\n\n\t// copy the keys into the integer slice\n\tfor _, k := range keys {\n\t\t// assert that the key is an int\n\t\ti, ok := k.(int)\n\t\tif !ok {\n\t\t\tt.Fatalf(\"expected type int, got %T\", k)\n\t\t}\n\n\t\tact = append(act, i)\n\t}\n\n\t// sort the returned keys for comparison\n\tsort.Slice(act, func(i, j int) bool {\n\t\treturn act[i] \u003c act[j]\n\t})\n\n\t// set the expected values\n\texp := []int{1, 2, 3}\n\n\t// assert the length of the actual and expected values\n\tal := len(act)\n\tel := len(exp)\n\tif al != el {\n\t\tt.Fatalf(\"expected %d, but got %d\", el, al)\n\t}\n\n\t// loop through the expected values and\n\t// assert they are in the actual values\n\tfor i, v := range exp {\n\t\tif v != act[i] {\n\t\t\tt.Fatalf(\"expected %d, but got %d\", v, act[i])\n\t\t}\n\t}\n\n}", + "file": "src/keys/fixed/keys_test.go", + "lang": "go", + "name": "example", + "start": 8, + "end": 70 + } + }, + "src/keys/generic/start/keys_test.go": { + "example": { + "content": "func Test_Keys(t *testing.T) {\n\tt.Parallel()\n\n\t// create a map with some values\n\tm := map[int]string{\n\t\t1: \"one\",\n\t\t2: \"two\",\n\t\t3: \"three\",\n\t}\n\n\t// get the keys\n\tact := Keys(m)\n\n\t// sort the returned keys for comparison\n\tsort.Slice(act, func(i, j int) bool {\n\t\treturn act[i] \u003c act[j]\n\t})\n\n\t// set the expected values\n\texp := []int{1, 2, 3}\n\n\t// assert the length of the actual and expected values\n\tif len(exp) != len(act) {\n\t\tt.Fatalf(\"expected len(%d), but got len(%d)\", len(exp), len(act))\n\t}\n\n\t// assert the types of the actual and expected values\n\tat := fmt.Sprintf(\"%T\", act)\n\tet := fmt.Sprintf(\"%T\", exp)\n\n\tif at != et {\n\t\tt.Fatalf(\"expected type %s, but got type %s\", et, at)\n\t}\n\n\t// loop through the expected values and\n\t// assert they are in the actual values\n\tfor i, v := range exp {\n\t\tif v != act[i] {\n\t\t\tt.Fatalf(\"expected %d, but got %d\", v, act[i])\n\t\t}\n\t}\n\n}", + "file": "src/keys/generic/start/keys_test.go", + "lang": "go", + "name": "example", + "start": 9, + "end": 54 + } + }, + "src/slicer/slicer_test.go": { + "example": { + "content": "func Test_Slicer(t *testing.T) {\n\tt.Parallel()\n\n\t// create input string\n\tinput := \"Hello World\"\n\n\t// capture output []string\n\tact := Slicer(input)\n\n\texp := []string{input}\n\n\tif len(act) != len(exp) {\n\t\tt.Fatalf(\"expected %v, got %v\", exp, act)\n\t}\n\n\tfor i, v := range exp {\n\t\tif act[i] != v {\n\t\t\tt.Fatalf(\"expected %v, got %v\", exp, act)\n\t\t}\n\t}\n\n}", + "file": "src/slicer/slicer_test.go", + "lang": "go", + "name": "example", + "start": 7, + "end": 31 + } + }, + "src/store/store_test.go": { + "example": { + "content": "func Test_Store_Insert(t *testing.T) {\n\tt.Parallel()\n\n\t// create a store\n\ts := \u0026Store[string, User]{\n\t\tdata: map[string]User{},\n\t}\n\n\t// create a user\n\texp := User{Email: \"kurt@exampl.com\"}\n\n\t// insert the user\n\terr := s.Insert(exp)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\t// retreive the user\n\tact, err := s.Find(exp.Email)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\t// assert the returned user is the same as the inserted user\n\tif exp.Email != act.Email {\n\t\tt.Fatalf(\"expected %v, got %v\", exp, act)\n\t}\n\n}", + "file": "src/store/store_test.go", + "lang": "go", + "name": "example", + "start": 7, + "end": 38 + } + } + } + }, + "title": "Generics", + "type": "hype.Document" +} diff --git a/src/testdata/12-context.json b/src/testdata/12-context.json new file mode 100644 index 0000000..efdcfdf --- /dev/null +++ b/src/testdata/12-context.json @@ -0,0 +1,33121 @@ +{ + "filename": "module.md", + "id": "e5517a50-7fac-4c18-a260-b140f442d87c", + "nodes": [ + { + "atom": "", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "", + "data_atom": "", + "namespace": "", + "node_type": "html.DocumentNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "html", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "html", + "data_atom": "html", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "head", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "head", + "data_atom": "head", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [], + "tag": "\u003chead\u003e", + "type": "hype.Element" + }, + [ + { + "atom": "body", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "body", + "data_atom": "body", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "page", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "page", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "atom": "h1", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "h1", + "data_atom": "h1", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "level": 1, + "nodes": [ + { + "text": "Context", + "type": "hype.Text" + } + ], + "tag": "\u003ch1\u003e", + "type": "hype.Heading" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Introduced in Go 1.7, the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context", + "href": "https://pkg.go.dev/context", + "target": "_blank" + }, + "filename": "module.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context\" href=\"https://pkg.go.dev/context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context" + } + ], + { + "text": " package was introduced to provide a cleaner way, than the use of channels, of managing cancellation and timeouts across goroutines.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "While the scope, and API footprint of the package is pretty small, it was a welcome addition to the language when introduced.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "The ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context", + "href": "https://pkg.go.dev/context", + "target": "_blank" + }, + "filename": "module.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context\" href=\"https://pkg.go.dev/context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context" + } + ], + { + "text": " package, ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-1" + }, + "filename": "module.md", + "html_node": { + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-1" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.1", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-1\"\u003e", + "type": "hype.Link", + "url": "#listing-1-1" + } + ], + "tag": "\u003cref id=\"listing-1-1\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ", defines the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "module.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": " type, which carries deadlines, cancellation signals, and other request-scoped values across API boundaries and between processes.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Context is, mostly, used for controlling concurrent subsystems in your application. This week we will cover the different kinds of behavior with contexts including canceling, timeouts, and values. We'll also see how we can clean up a lot of code involving channels by using contexts.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-1", + "type": "listing" + }, + "filename": "module.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "context" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "args": [ + "go", + "doc", + "-short", + "context" + ], + "atom": "cmd", + "attributes": { + "data-go-version": "go1.22.0", + "doc": "-short context", + "exec": "go doc -short context" + }, + "expected_exit": 0, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "data-go-version", + "Val": "go1.22.0" + }, + { + "Namespace": "", + "Key": "doc", + "Val": "-short context" + }, + { + "Namespace": "", + "Key": "exec", + "Val": "go doc -short context" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "doc", + "-short", + "context" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypejs", + "duration": "1.515445584s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go doc -short context\n\nvar Canceled = errors.New(\u0026#34;context canceled\u0026#34;)\nvar DeadlineExceeded error = deadlineExceededError{}\nfunc AfterFunc(ctx Context, f func()) (stop func() bool)\nfunc Cause(c Context) error\nfunc WithCancel(parent Context) (ctx Context, cancel CancelFunc)\nfunc WithCancelCause(parent Context) (ctx Context, cancel CancelCauseFunc)\nfunc WithDeadline(parent Context, d time.Time) (Context, CancelFunc)\nfunc WithDeadlineCause(parent Context, d time.Time, cause error) (Context, CancelFunc)\nfunc WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc)\nfunc WithTimeoutCause(parent Context, timeout time.Duration, cause error) (Context, CancelFunc)\ntype CancelCauseFunc func(cause error)\ntype CancelFunc func()\ntype Context interface{ ... }\n func Background() Context\n func TODO() Context\n func WithValue(parent Context, key, val any) Context\n func WithoutCancel(parent Context) Context", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "var Canceled = errors.New(\"context canceled\")\nvar DeadlineExceeded error = deadlineExceededError{}\nfunc AfterFunc(ctx Context, f func()) (stop func() bool)\nfunc Cause(c Context) error\nfunc WithCancel(parent Context) (ctx Context, cancel CancelFunc)\nfunc WithCancelCause(parent Context) (ctx Context, cancel CancelCauseFunc)\nfunc WithDeadline(parent Context, d time.Time) (Context, CancelFunc)\nfunc WithDeadlineCause(parent Context, d time.Time, cause error) (Context, CancelFunc)\nfunc WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc)\nfunc WithTimeoutCause(parent Context, timeout time.Duration, cause error) (Context, CancelFunc)\ntype CancelCauseFunc func(cause error)\ntype CancelFunc func()\ntype Context interface{ ... }\n func Background() Context\n func TODO() Context\n func WithValue(parent Context, key, val any) Context\n func WithoutCancel(parent Context) Context", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "doc", + "-short", + "context" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypejs", + "duration": "1.515445584s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go doc -short context\n\nvar Canceled = errors.New(\u0026#34;context canceled\u0026#34;)\nvar DeadlineExceeded error = deadlineExceededError{}\nfunc AfterFunc(ctx Context, f func()) (stop func() bool)\nfunc Cause(c Context) error\nfunc WithCancel(parent Context) (ctx Context, cancel CancelFunc)\nfunc WithCancelCause(parent Context) (ctx Context, cancel CancelCauseFunc)\nfunc WithDeadline(parent Context, d time.Time) (Context, CancelFunc)\nfunc WithDeadlineCause(parent Context, d time.Time, cause error) (Context, CancelFunc)\nfunc WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc)\nfunc WithTimeoutCause(parent Context, timeout time.Duration, cause error) (Context, CancelFunc)\ntype CancelCauseFunc func(cause error)\ntype CancelFunc func()\ntype Context interface{ ... }\n func Background() Context\n func TODO() Context\n func WithValue(parent Context, key, val any) Context\n func WithoutCancel(parent Context) Context", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "var Canceled = errors.New(\"context canceled\")\nvar DeadlineExceeded error = deadlineExceededError{}\nfunc AfterFunc(ctx Context, f func()) (stop func() bool)\nfunc Cause(c Context) error\nfunc WithCancel(parent Context) (ctx Context, cancel CancelFunc)\nfunc WithCancelCause(parent Context) (ctx Context, cancel CancelCauseFunc)\nfunc WithDeadline(parent Context, d time.Time) (Context, CancelFunc)\nfunc WithDeadlineCause(parent Context, d time.Time, cause error) (Context, CancelFunc)\nfunc WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc)\nfunc WithTimeoutCause(parent Context, timeout time.Duration, cause error) (Context, CancelFunc)\ntype CancelCauseFunc func(cause error)\ntype CancelFunc func()\ntype Context interface{ ... }\n func Background() Context\n func TODO() Context\n func WithValue(parent Context, key, val any) Context\n func WithoutCancel(parent Context) Context", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd data-go-version=\"go1.22.0\" doc=\"-short context\" exec=\"go doc -short context\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.1:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "The ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context", + "href": "https://pkg.go.dev/context", + "target": "_blank" + }, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "for", + "Val": "context" + }, + { + "Namespace": "", + "Key": "href", + "Val": "https://pkg.go.dev/context" + }, + { + "Namespace": "", + "Key": "target", + "Val": "_blank" + } + ], + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": {}, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ] + ], + "tag": "\u003ca for=\"context\" href=\"https://pkg.go.dev/context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context" + } + ], + { + "text": " package.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 1, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-1\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "tag": "\u003cpage\u003e", + "title": "Context", + "type": "hype.Page" + } + ], + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "atom": "include", + "attributes": { + "src": "basics/basics.md" + }, + "dir": "basics", + "filename": "module.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "basics/basics.md" + } + ], + "data": "include", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "page", + "attributes": {}, + "filename": "basics.md", + "html_node": { + "data": "page", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "atom": "h1", + "attributes": {}, + "filename": "basics.md", + "html_node": { + "data": "h1", + "data_atom": "h1", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "level": 1, + "nodes": [ + { + "text": "The Context Interface", + "type": "hype.Text" + } + ], + "tag": "\u003ch1\u003e", + "type": "hype.Heading" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "basics.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "The ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "basics.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "basics.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": " interface, ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-2" + }, + "filename": "basics.md", + "html_node": { + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-2" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.2", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-2\"\u003e", + "type": "hype.Link", + "url": "#listing-1-2" + } + ], + "tag": "\u003cref id=\"listing-1-2\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ", consists of four methods. These methods provide us the ability to listen for cancellation and timeout events, retrieve values from the context hierarchy, and finally, a way to check what ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "basics.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "error", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": ", if any, caused the context to be canceled.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-2", + "type": "listing" + }, + "filename": "basics.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "context.doc" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + { + "atom": "pre", + "attributes": {}, + "filename": "basics", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": { + "class": "language-godoc", + "language": "godoc" + }, + "filename": "basics", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "class", + "Val": "language-godoc" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "godoc", + "nodes": [ + { + "text": "type Context interface {\n Deadline() (deadline time.Time, ok bool)\n Done() \u0026lt;-chan struct{}\n Err() error\n Value(key interface{}) interface{}\n}\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-godoc\" language=\"godoc\"\u003e", + "type": "hype.FencedCode" + } + ] + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + }, + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "basics", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.2:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "The ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "basics", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "for", + "Val": "context#Context" + }, + { + "Namespace": "", + "Key": "href", + "Val": "https://pkg.go.dev/context#Context" + }, + { + "Namespace": "", + "Key": "target", + "Val": "_blank" + } + ], + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": {}, + "filename": "basics", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ] + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": " interface.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 2, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-2\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "basics.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "We can see, in ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-2" + }, + "filename": "basics.md", + "html_node": { + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-2" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.2", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-2\"\u003e", + "type": "hype.Link", + "url": "#listing-1-2" + } + ], + "tag": "\u003cref id=\"listing-1-2\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ", that the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "basics.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "basics.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": " interface implements several of the channel patterns we have already seen, such as have a ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "basics.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Done", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " channel that can be listened to for cancellation.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "basics.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "We will cover each of these methods in more detail later. For now, let's briefly look at each one of them.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "h2", + "attributes": {}, + "filename": "basics.md", + "html_node": { + "data": "h2", + "data_atom": "h2", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "level": 2, + "nodes": [ + { + "text": "Context#Deadline", + "type": "hype.Text" + } + ], + "tag": "\u003ch2\u003e", + "type": "hype.Heading" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "basics.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "The ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context.Deadline", + "href": "https://pkg.go.dev/context#Context.Deadline", + "target": "_blank" + }, + "filename": "basics.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "basics.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context.Deadline", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context.Deadline\" href=\"https://pkg.go.dev/context#Context.Deadline\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context.Deadline" + } + ], + { + "text": " method, ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-3" + }, + "filename": "basics.md", + "html_node": { + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-3" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.3", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-3\"\u003e", + "type": "hype.Link", + "url": "#listing-1-3" + } + ], + "tag": "\u003cref id=\"listing-1-3\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ", can be used to check if a context has a cancellation deadline set, and if so, what that deadline is.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-3", + "type": "listing" + }, + "filename": "basics.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "deadline.doc" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "args": [ + "go", + "doc", + "context.Context.Deadline" + ], + "atom": "cmd", + "attributes": { + "data-go-version": "go1.22.0", + "doc": "context.Context.Deadline", + "exec": "go doc context.Context.Deadline" + }, + "expected_exit": 0, + "filename": "basics", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "data-go-version", + "Val": "go1.22.0" + }, + { + "Namespace": "", + "Key": "doc", + "Val": "context.Context.Deadline" + }, + { + "Namespace": "", + "Key": "exec", + "Val": "go doc context.Context.Deadline" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "doc", + "context.Context.Deadline" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypejs", + "duration": "1.136447292s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go doc context.Context.Deadline\n\npackage context // import \u0026#34;context\u0026#34;\n\ntype Context interface {\n\t// Deadline returns the time when work done on behalf of this context\n\t// should be canceled. Deadline returns ok==false when no deadline is\n\t// set. Successive calls to Deadline return the same results.\n\tDeadline() (deadline time.Time, ok bool)\n}", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "package context // import \"context\"\n\ntype Context interface {\n\t// Deadline returns the time when work done on behalf of this context\n\t// should be canceled. Deadline returns ok==false when no deadline is\n\t// set. Successive calls to Deadline return the same results.\n\tDeadline() (deadline time.Time, ok bool)\n}", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "doc", + "context.Context.Deadline" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypejs", + "duration": "1.136447292s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go doc context.Context.Deadline\n\npackage context // import \u0026#34;context\u0026#34;\n\ntype Context interface {\n\t// Deadline returns the time when work done on behalf of this context\n\t// should be canceled. Deadline returns ok==false when no deadline is\n\t// set. Successive calls to Deadline return the same results.\n\tDeadline() (deadline time.Time, ok bool)\n}", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "package context // import \"context\"\n\ntype Context interface {\n\t// Deadline returns the time when work done on behalf of this context\n\t// should be canceled. Deadline returns ok==false when no deadline is\n\t// set. Successive calls to Deadline return the same results.\n\tDeadline() (deadline time.Time, ok bool)\n}", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd data-go-version=\"go1.22.0\" doc=\"context.Context.Deadline\" exec=\"go doc context.Context.Deadline\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "basics", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.3:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "The ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context.Deadline", + "href": "https://pkg.go.dev/context#Context.Deadline", + "target": "_blank" + }, + "filename": "basics", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "for", + "Val": "context#Context.Deadline" + }, + { + "Namespace": "", + "Key": "href", + "Val": "https://pkg.go.dev/context#Context.Deadline" + }, + { + "Namespace": "", + "Key": "target", + "Val": "_blank" + } + ], + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": {}, + "filename": "basics", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context.Deadline", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ] + ], + "tag": "\u003ca for=\"context#Context.Deadline\" href=\"https://pkg.go.dev/context#Context.Deadline\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context.Deadline" + } + ], + { + "text": " method.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 3, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-3\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "h2", + "attributes": {}, + "filename": "basics.md", + "html_node": { + "data": "h2", + "data_atom": "h2", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "level": 2, + "nodes": [ + { + "text": "Context#Done", + "type": "hype.Text" + } + ], + "tag": "\u003ch2\u003e", + "type": "hype.Heading" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "basics.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "The ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context.Done", + "href": "https://pkg.go.dev/context#Context.Done", + "target": "_blank" + }, + "filename": "basics.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "basics.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context.Done", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context.Done\" href=\"https://pkg.go.dev/context#Context.Done\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context.Done" + } + ], + { + "text": " method, ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-4" + }, + "filename": "basics.md", + "html_node": { + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-4" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.4", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-4\"\u003e", + "type": "hype.Link", + "url": "#listing-1-4" + } + ], + "tag": "\u003cref id=\"listing-1-4\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ", can be used to listen for cancellation events. This is similar to how we can listen for a channel being closed, but it is more flexible.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-4", + "type": "listing" + }, + "filename": "basics.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "done.doc" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "args": [ + "go", + "doc", + "context.Context.Done" + ], + "atom": "cmd", + "attributes": { + "data-go-version": "go1.22.0", + "doc": "context.Context.Done", + "exec": "go doc context.Context.Done" + }, + "expected_exit": 0, + "filename": "basics", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "data-go-version", + "Val": "go1.22.0" + }, + { + "Namespace": "", + "Key": "doc", + "Val": "context.Context.Done" + }, + { + "Namespace": "", + "Key": "exec", + "Val": "go doc context.Context.Done" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "doc", + "context.Context.Done" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypejs", + "duration": "1.29644225s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go doc context.Context.Done\n\npackage context // import \u0026#34;context\u0026#34;\n\ntype Context interface {\n\n\t// Done returns a channel that\u0026#39;s closed when work done on behalf of this\n\t// context should be canceled. Done may return nil if this context can\n\t// never be canceled. Successive calls to Done return the same value.\n\t// The close of the Done channel may happen asynchronously,\n\t// after the cancel function returns.\n\t//\n\t// WithCancel arranges for Done to be closed when cancel is called;\n\t// WithDeadline arranges for Done to be closed when the deadline\n\t// expires; WithTimeout arranges for Done to be closed when the timeout\n\t// elapses.\n\t//\n\t// Done is provided for use in select statements:\n\t//\n\t// // Stream generates values with DoSomething and sends them to out\n\t// // until DoSomething returns an error or ctx.Done is closed.\n\t// func Stream(ctx context.Context, out chan\u0026lt;- Value) error {\n\t// \tfor {\n\t// \t\tv, err := DoSomething(ctx)\n\t// \t\tif err != nil {\n\t// \t\t\treturn err\n\t// \t\t}\n\t// \t\tselect {\n\t// \t\tcase \u0026lt;-ctx.Done():\n\t// \t\t\treturn ctx.Err()\n\t// \t\tcase out \u0026lt;- v:\n\t// \t\t}\n\t// \t}\n\t// }\n\t//\n\t// See https://blog.golang.org/pipelines for more examples of how to use\n\t// a Done channel for cancellation.\n\tDone() \u0026lt;-chan struct{}\n}", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "package context // import \"context\"\n\ntype Context interface {\n\n\t// Done returns a channel that's closed when work done on behalf of this\n\t// context should be canceled. Done may return nil if this context can\n\t// never be canceled. Successive calls to Done return the same value.\n\t// The close of the Done channel may happen asynchronously,\n\t// after the cancel function returns.\n\t//\n\t// WithCancel arranges for Done to be closed when cancel is called;\n\t// WithDeadline arranges for Done to be closed when the deadline\n\t// expires; WithTimeout arranges for Done to be closed when the timeout\n\t// elapses.\n\t//\n\t// Done is provided for use in select statements:\n\t//\n\t// // Stream generates values with DoSomething and sends them to out\n\t// // until DoSomething returns an error or ctx.Done is closed.\n\t// func Stream(ctx context.Context, out chan\u003c- Value) error {\n\t// \tfor {\n\t// \t\tv, err := DoSomething(ctx)\n\t// \t\tif err != nil {\n\t// \t\t\treturn err\n\t// \t\t}\n\t// \t\tselect {\n\t// \t\tcase \u003c-ctx.Done():\n\t// \t\t\treturn ctx.Err()\n\t// \t\tcase out \u003c- v:\n\t// \t\t}\n\t// \t}\n\t// }\n\t//\n\t// See https://blog.golang.org/pipelines for more examples of how to use\n\t// a Done channel for cancellation.\n\tDone() \u003c-chan struct{}\n}", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "doc", + "context.Context.Done" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypejs", + "duration": "1.29644225s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go doc context.Context.Done\n\npackage context // import \u0026#34;context\u0026#34;\n\ntype Context interface {\n\n\t// Done returns a channel that\u0026#39;s closed when work done on behalf of this\n\t// context should be canceled. Done may return nil if this context can\n\t// never be canceled. Successive calls to Done return the same value.\n\t// The close of the Done channel may happen asynchronously,\n\t// after the cancel function returns.\n\t//\n\t// WithCancel arranges for Done to be closed when cancel is called;\n\t// WithDeadline arranges for Done to be closed when the deadline\n\t// expires; WithTimeout arranges for Done to be closed when the timeout\n\t// elapses.\n\t//\n\t// Done is provided for use in select statements:\n\t//\n\t// // Stream generates values with DoSomething and sends them to out\n\t// // until DoSomething returns an error or ctx.Done is closed.\n\t// func Stream(ctx context.Context, out chan\u0026lt;- Value) error {\n\t// \tfor {\n\t// \t\tv, err := DoSomething(ctx)\n\t// \t\tif err != nil {\n\t// \t\t\treturn err\n\t// \t\t}\n\t// \t\tselect {\n\t// \t\tcase \u0026lt;-ctx.Done():\n\t// \t\t\treturn ctx.Err()\n\t// \t\tcase out \u0026lt;- v:\n\t// \t\t}\n\t// \t}\n\t// }\n\t//\n\t// See https://blog.golang.org/pipelines for more examples of how to use\n\t// a Done channel for cancellation.\n\tDone() \u0026lt;-chan struct{}\n}", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "package context // import \"context\"\n\ntype Context interface {\n\n\t// Done returns a channel that's closed when work done on behalf of this\n\t// context should be canceled. Done may return nil if this context can\n\t// never be canceled. Successive calls to Done return the same value.\n\t// The close of the Done channel may happen asynchronously,\n\t// after the cancel function returns.\n\t//\n\t// WithCancel arranges for Done to be closed when cancel is called;\n\t// WithDeadline arranges for Done to be closed when the deadline\n\t// expires; WithTimeout arranges for Done to be closed when the timeout\n\t// elapses.\n\t//\n\t// Done is provided for use in select statements:\n\t//\n\t// // Stream generates values with DoSomething and sends them to out\n\t// // until DoSomething returns an error or ctx.Done is closed.\n\t// func Stream(ctx context.Context, out chan\u003c- Value) error {\n\t// \tfor {\n\t// \t\tv, err := DoSomething(ctx)\n\t// \t\tif err != nil {\n\t// \t\t\treturn err\n\t// \t\t}\n\t// \t\tselect {\n\t// \t\tcase \u003c-ctx.Done():\n\t// \t\t\treturn ctx.Err()\n\t// \t\tcase out \u003c- v:\n\t// \t\t}\n\t// \t}\n\t// }\n\t//\n\t// See https://blog.golang.org/pipelines for more examples of how to use\n\t// a Done channel for cancellation.\n\tDone() \u003c-chan struct{}\n}", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd data-go-version=\"go1.22.0\" doc=\"context.Context.Done\" exec=\"go doc context.Context.Done\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "basics", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.4:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "The ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context.Done", + "href": "https://pkg.go.dev/context#Context.Done", + "target": "_blank" + }, + "filename": "basics", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "for", + "Val": "context#Context.Done" + }, + { + "Namespace": "", + "Key": "href", + "Val": "https://pkg.go.dev/context#Context.Done" + }, + { + "Namespace": "", + "Key": "target", + "Val": "_blank" + } + ], + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": {}, + "filename": "basics", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context.Done", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ] + ], + "tag": "\u003ca for=\"context#Context.Done\" href=\"https://pkg.go.dev/context#Context.Done\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context.Done" + } + ], + { + "text": " method.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 4, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-4\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "h2", + "attributes": {}, + "filename": "basics.md", + "html_node": { + "data": "h2", + "data_atom": "h2", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "level": 2, + "nodes": [ + { + "text": "Context#Err", + "type": "hype.Text" + } + ], + "tag": "\u003ch2\u003e", + "type": "hype.Heading" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "basics.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "The ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context.Err", + "href": "https://pkg.go.dev/context#Context.Err", + "target": "_blank" + }, + "filename": "basics.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "basics.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context.Err", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context.Err\" href=\"https://pkg.go.dev/context#Context.Err\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context.Err" + } + ], + { + "text": " method, ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-5" + }, + "filename": "basics.md", + "html_node": { + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-5" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.5", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-5\"\u003e", + "type": "hype.Link", + "url": "#listing-1-5" + } + ], + "tag": "\u003cref id=\"listing-1-5\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ", can be used to check if a context has been canceled.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-5", + "type": "listing" + }, + "filename": "basics.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "err.doc" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "args": [ + "go", + "doc", + "context.Context.Err" + ], + "atom": "cmd", + "attributes": { + "data-go-version": "go1.22.0", + "doc": "context.Context.Err", + "exec": "go doc context.Context.Err" + }, + "expected_exit": 0, + "filename": "basics", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "data-go-version", + "Val": "go1.22.0" + }, + { + "Namespace": "", + "Key": "doc", + "Val": "context.Context.Err" + }, + { + "Namespace": "", + "Key": "exec", + "Val": "go doc context.Context.Err" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "doc", + "context.Context.Err" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypejs", + "duration": "1.928899125s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go doc context.Context.Err\n\npackage context // import \u0026#34;context\u0026#34;\n\ntype Context interface {\n\n\t// If Done is not yet closed, Err returns nil.\n\t// If Done is closed, Err returns a non-nil error explaining why:\n\t// Canceled if the context was canceled\n\t// or DeadlineExceeded if the context\u0026#39;s deadline passed.\n\t// After Err returns a non-nil error, successive calls to Err return the same error.\n\tErr() error\n}", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "package context // import \"context\"\n\ntype Context interface {\n\n\t// If Done is not yet closed, Err returns nil.\n\t// If Done is closed, Err returns a non-nil error explaining why:\n\t// Canceled if the context was canceled\n\t// or DeadlineExceeded if the context's deadline passed.\n\t// After Err returns a non-nil error, successive calls to Err return the same error.\n\tErr() error\n}", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "doc", + "context.Context.Err" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypejs", + "duration": "1.928899125s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go doc context.Context.Err\n\npackage context // import \u0026#34;context\u0026#34;\n\ntype Context interface {\n\n\t// If Done is not yet closed, Err returns nil.\n\t// If Done is closed, Err returns a non-nil error explaining why:\n\t// Canceled if the context was canceled\n\t// or DeadlineExceeded if the context\u0026#39;s deadline passed.\n\t// After Err returns a non-nil error, successive calls to Err return the same error.\n\tErr() error\n}", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "package context // import \"context\"\n\ntype Context interface {\n\n\t// If Done is not yet closed, Err returns nil.\n\t// If Done is closed, Err returns a non-nil error explaining why:\n\t// Canceled if the context was canceled\n\t// or DeadlineExceeded if the context's deadline passed.\n\t// After Err returns a non-nil error, successive calls to Err return the same error.\n\tErr() error\n}", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd data-go-version=\"go1.22.0\" doc=\"context.Context.Err\" exec=\"go doc context.Context.Err\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "basics", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.5:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "The ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context.Err", + "href": "https://pkg.go.dev/context#Context.Err", + "target": "_blank" + }, + "filename": "basics", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "for", + "Val": "context#Context.Err" + }, + { + "Namespace": "", + "Key": "href", + "Val": "https://pkg.go.dev/context#Context.Err" + }, + { + "Namespace": "", + "Key": "target", + "Val": "_blank" + } + ], + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": {}, + "filename": "basics", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context.Err", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ] + ], + "tag": "\u003ca for=\"context#Context.Err\" href=\"https://pkg.go.dev/context#Context.Err\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context.Err" + } + ], + { + "text": " method.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 5, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-5\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "h2", + "attributes": {}, + "filename": "basics.md", + "html_node": { + "data": "h2", + "data_atom": "h2", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "level": 2, + "nodes": [ + { + "text": "Context#Value", + "type": "hype.Text" + } + ], + "tag": "\u003ch2\u003e", + "type": "hype.Heading" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "basics.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "The ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context.Value", + "href": "https://pkg.go.dev/context#Context.Value", + "target": "_blank" + }, + "filename": "basics.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "basics.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context.Value", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context.Value\" href=\"https://pkg.go.dev/context#Context.Value\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context.Value" + } + ], + { + "text": " method, ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-6" + }, + "filename": "basics.md", + "html_node": { + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-6" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.6", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-6\"\u003e", + "type": "hype.Link", + "url": "#listing-1-6" + } + ], + "tag": "\u003cref id=\"listing-1-6\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ", can be used to retrieve values from the context hierarchy.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-6", + "type": "listing" + }, + "filename": "basics.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "value.doc" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "args": [ + "go", + "doc", + "context.Context.Value" + ], + "atom": "cmd", + "attributes": { + "data-go-version": "go1.22.0", + "doc": "context.Context.Value", + "exec": "go doc context.Context.Value" + }, + "expected_exit": 0, + "filename": "basics", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "data-go-version", + "Val": "go1.22.0" + }, + { + "Namespace": "", + "Key": "doc", + "Val": "context.Context.Value" + }, + { + "Namespace": "", + "Key": "exec", + "Val": "go doc context.Context.Value" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "doc", + "context.Context.Value" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypejs", + "duration": "2.067509667s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go doc context.Context.Value\n\npackage context // import \u0026#34;context\u0026#34;\n\ntype Context interface {\n\n\t// Value returns the value associated with this context for key, or nil\n\t// if no value is associated with key. Successive calls to Value with\n\t// the same key returns the same result.\n\t//\n\t// Use context values only for request-scoped data that transits\n\t// processes and API boundaries, not for passing optional parameters to\n\t// functions.\n\t//\n\t// A key identifies a specific value in a Context. Functions that wish\n\t// to store values in Context typically allocate a key in a global\n\t// variable then use that key as the argument to context.WithValue and\n\t// Context.Value. A key can be any type that supports equality;\n\t// packages should define keys as an unexported type to avoid\n\t// collisions.\n\t//\n\t// Packages that define a Context key should provide type-safe accessors\n\t// for the values stored using that key:\n\t//\n\t// \t// Package user defines a User type that\u0026#39;s stored in Contexts.\n\t// \tpackage user\n\t//\n\t// \timport \u0026#34;context\u0026#34;\n\t//\n\t// \t// User is the type of value stored in the Contexts.\n\t// \ttype User struct {...}\n\t//\n\t// \t// key is an unexported type for keys defined in this package.\n\t// \t// This prevents collisions with keys defined in other packages.\n\t// \ttype key int\n\t//\n\t// \t// userKey is the key for user.User values in Contexts. It is\n\t// \t// unexported; clients use user.NewContext and user.FromContext\n\t// \t// instead of using this key directly.\n\t// \tvar userKey key\n\t//\n\t// \t// NewContext returns a new Context that carries value u.\n\t// \tfunc NewContext(ctx context.Context, u *User) context.Context {\n\t// \t\treturn context.WithValue(ctx, userKey, u)\n\t// \t}\n\t//\n\t// \t// FromContext returns the User value stored in ctx, if any.\n\t// \tfunc FromContext(ctx context.Context) (*User, bool) {\n\t// \t\tu, ok := ctx.Value(userKey).(*User)\n\t// \t\treturn u, ok\n\t// \t}\n\tValue(key any) any\n}", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "package context // import \"context\"\n\ntype Context interface {\n\n\t// Value returns the value associated with this context for key, or nil\n\t// if no value is associated with key. Successive calls to Value with\n\t// the same key returns the same result.\n\t//\n\t// Use context values only for request-scoped data that transits\n\t// processes and API boundaries, not for passing optional parameters to\n\t// functions.\n\t//\n\t// A key identifies a specific value in a Context. Functions that wish\n\t// to store values in Context typically allocate a key in a global\n\t// variable then use that key as the argument to context.WithValue and\n\t// Context.Value. A key can be any type that supports equality;\n\t// packages should define keys as an unexported type to avoid\n\t// collisions.\n\t//\n\t// Packages that define a Context key should provide type-safe accessors\n\t// for the values stored using that key:\n\t//\n\t// \t// Package user defines a User type that's stored in Contexts.\n\t// \tpackage user\n\t//\n\t// \timport \"context\"\n\t//\n\t// \t// User is the type of value stored in the Contexts.\n\t// \ttype User struct {...}\n\t//\n\t// \t// key is an unexported type for keys defined in this package.\n\t// \t// This prevents collisions with keys defined in other packages.\n\t// \ttype key int\n\t//\n\t// \t// userKey is the key for user.User values in Contexts. It is\n\t// \t// unexported; clients use user.NewContext and user.FromContext\n\t// \t// instead of using this key directly.\n\t// \tvar userKey key\n\t//\n\t// \t// NewContext returns a new Context that carries value u.\n\t// \tfunc NewContext(ctx context.Context, u *User) context.Context {\n\t// \t\treturn context.WithValue(ctx, userKey, u)\n\t// \t}\n\t//\n\t// \t// FromContext returns the User value stored in ctx, if any.\n\t// \tfunc FromContext(ctx context.Context) (*User, bool) {\n\t// \t\tu, ok := ctx.Value(userKey).(*User)\n\t// \t\treturn u, ok\n\t// \t}\n\tValue(key any) any\n}", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "doc", + "context.Context.Value" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypejs", + "duration": "2.067509667s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go doc context.Context.Value\n\npackage context // import \u0026#34;context\u0026#34;\n\ntype Context interface {\n\n\t// Value returns the value associated with this context for key, or nil\n\t// if no value is associated with key. Successive calls to Value with\n\t// the same key returns the same result.\n\t//\n\t// Use context values only for request-scoped data that transits\n\t// processes and API boundaries, not for passing optional parameters to\n\t// functions.\n\t//\n\t// A key identifies a specific value in a Context. Functions that wish\n\t// to store values in Context typically allocate a key in a global\n\t// variable then use that key as the argument to context.WithValue and\n\t// Context.Value. A key can be any type that supports equality;\n\t// packages should define keys as an unexported type to avoid\n\t// collisions.\n\t//\n\t// Packages that define a Context key should provide type-safe accessors\n\t// for the values stored using that key:\n\t//\n\t// \t// Package user defines a User type that\u0026#39;s stored in Contexts.\n\t// \tpackage user\n\t//\n\t// \timport \u0026#34;context\u0026#34;\n\t//\n\t// \t// User is the type of value stored in the Contexts.\n\t// \ttype User struct {...}\n\t//\n\t// \t// key is an unexported type for keys defined in this package.\n\t// \t// This prevents collisions with keys defined in other packages.\n\t// \ttype key int\n\t//\n\t// \t// userKey is the key for user.User values in Contexts. It is\n\t// \t// unexported; clients use user.NewContext and user.FromContext\n\t// \t// instead of using this key directly.\n\t// \tvar userKey key\n\t//\n\t// \t// NewContext returns a new Context that carries value u.\n\t// \tfunc NewContext(ctx context.Context, u *User) context.Context {\n\t// \t\treturn context.WithValue(ctx, userKey, u)\n\t// \t}\n\t//\n\t// \t// FromContext returns the User value stored in ctx, if any.\n\t// \tfunc FromContext(ctx context.Context) (*User, bool) {\n\t// \t\tu, ok := ctx.Value(userKey).(*User)\n\t// \t\treturn u, ok\n\t// \t}\n\tValue(key any) any\n}", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "package context // import \"context\"\n\ntype Context interface {\n\n\t// Value returns the value associated with this context for key, or nil\n\t// if no value is associated with key. Successive calls to Value with\n\t// the same key returns the same result.\n\t//\n\t// Use context values only for request-scoped data that transits\n\t// processes and API boundaries, not for passing optional parameters to\n\t// functions.\n\t//\n\t// A key identifies a specific value in a Context. Functions that wish\n\t// to store values in Context typically allocate a key in a global\n\t// variable then use that key as the argument to context.WithValue and\n\t// Context.Value. A key can be any type that supports equality;\n\t// packages should define keys as an unexported type to avoid\n\t// collisions.\n\t//\n\t// Packages that define a Context key should provide type-safe accessors\n\t// for the values stored using that key:\n\t//\n\t// \t// Package user defines a User type that's stored in Contexts.\n\t// \tpackage user\n\t//\n\t// \timport \"context\"\n\t//\n\t// \t// User is the type of value stored in the Contexts.\n\t// \ttype User struct {...}\n\t//\n\t// \t// key is an unexported type for keys defined in this package.\n\t// \t// This prevents collisions with keys defined in other packages.\n\t// \ttype key int\n\t//\n\t// \t// userKey is the key for user.User values in Contexts. It is\n\t// \t// unexported; clients use user.NewContext and user.FromContext\n\t// \t// instead of using this key directly.\n\t// \tvar userKey key\n\t//\n\t// \t// NewContext returns a new Context that carries value u.\n\t// \tfunc NewContext(ctx context.Context, u *User) context.Context {\n\t// \t\treturn context.WithValue(ctx, userKey, u)\n\t// \t}\n\t//\n\t// \t// FromContext returns the User value stored in ctx, if any.\n\t// \tfunc FromContext(ctx context.Context) (*User, bool) {\n\t// \t\tu, ok := ctx.Value(userKey).(*User)\n\t// \t\treturn u, ok\n\t// \t}\n\tValue(key any) any\n}", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd data-go-version=\"go1.22.0\" doc=\"context.Context.Value\" exec=\"go doc context.Context.Value\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "basics", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.6:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "The ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context.Value", + "href": "https://pkg.go.dev/context#Context.Value", + "target": "_blank" + }, + "filename": "basics", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "for", + "Val": "context#Context.Value" + }, + { + "Namespace": "", + "Key": "href", + "Val": "https://pkg.go.dev/context#Context.Value" + }, + { + "Namespace": "", + "Key": "target", + "Val": "_blank" + } + ], + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": {}, + "filename": "basics", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context.Value", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ] + ], + "tag": "\u003ca for=\"context#Context.Value\" href=\"https://pkg.go.dev/context#Context.Value\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context.Value" + } + ], + { + "text": " method.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 6, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-6\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "h2", + "attributes": {}, + "filename": "basics.md", + "html_node": { + "data": "h2", + "data_atom": "h2", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "level": 2, + "nodes": [ + { + "text": "Helper Functions", + "type": "hype.Text" + } + ], + "tag": "\u003ch2\u003e", + "type": "hype.Heading" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "basics.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "As we will see the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context", + "href": "https://pkg.go.dev/context", + "target": "_blank" + }, + "filename": "basics.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "basics.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context\" href=\"https://pkg.go.dev/context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context" + } + ], + { + "text": " package provides a number of useful helper functions for wrapping a ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "basics.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "basics.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": " making the need for custom implementations of the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "basics.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "basics.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": " interface less common.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-7", + "type": "listing" + }, + "filename": "basics.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "helper.doc" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "args": [ + "go", + "doc", + "-short", + "context" + ], + "atom": "cmd", + "attributes": { + "data-go-version": "go1.22.0", + "doc": "-short context", + "exec": "go doc -short context" + }, + "expected_exit": 0, + "filename": "basics", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "data-go-version", + "Val": "go1.22.0" + }, + { + "Namespace": "", + "Key": "doc", + "Val": "-short context" + }, + { + "Namespace": "", + "Key": "exec", + "Val": "go doc -short context" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "doc", + "-short", + "context" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypejs", + "duration": "959.792209ms", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go doc -short context\n\nvar Canceled = errors.New(\u0026#34;context canceled\u0026#34;)\nvar DeadlineExceeded error = deadlineExceededError{}\nfunc AfterFunc(ctx Context, f func()) (stop func() bool)\nfunc Cause(c Context) error\nfunc WithCancel(parent Context) (ctx Context, cancel CancelFunc)\nfunc WithCancelCause(parent Context) (ctx Context, cancel CancelCauseFunc)\nfunc WithDeadline(parent Context, d time.Time) (Context, CancelFunc)\nfunc WithDeadlineCause(parent Context, d time.Time, cause error) (Context, CancelFunc)\nfunc WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc)\nfunc WithTimeoutCause(parent Context, timeout time.Duration, cause error) (Context, CancelFunc)\ntype CancelCauseFunc func(cause error)\ntype CancelFunc func()\ntype Context interface{ ... }\n func Background() Context\n func TODO() Context\n func WithValue(parent Context, key, val any) Context\n func WithoutCancel(parent Context) Context", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "var Canceled = errors.New(\"context canceled\")\nvar DeadlineExceeded error = deadlineExceededError{}\nfunc AfterFunc(ctx Context, f func()) (stop func() bool)\nfunc Cause(c Context) error\nfunc WithCancel(parent Context) (ctx Context, cancel CancelFunc)\nfunc WithCancelCause(parent Context) (ctx Context, cancel CancelCauseFunc)\nfunc WithDeadline(parent Context, d time.Time) (Context, CancelFunc)\nfunc WithDeadlineCause(parent Context, d time.Time, cause error) (Context, CancelFunc)\nfunc WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc)\nfunc WithTimeoutCause(parent Context, timeout time.Duration, cause error) (Context, CancelFunc)\ntype CancelCauseFunc func(cause error)\ntype CancelFunc func()\ntype Context interface{ ... }\n func Background() Context\n func TODO() Context\n func WithValue(parent Context, key, val any) Context\n func WithoutCancel(parent Context) Context", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "doc", + "-short", + "context" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypejs", + "duration": "959.792209ms", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go doc -short context\n\nvar Canceled = errors.New(\u0026#34;context canceled\u0026#34;)\nvar DeadlineExceeded error = deadlineExceededError{}\nfunc AfterFunc(ctx Context, f func()) (stop func() bool)\nfunc Cause(c Context) error\nfunc WithCancel(parent Context) (ctx Context, cancel CancelFunc)\nfunc WithCancelCause(parent Context) (ctx Context, cancel CancelCauseFunc)\nfunc WithDeadline(parent Context, d time.Time) (Context, CancelFunc)\nfunc WithDeadlineCause(parent Context, d time.Time, cause error) (Context, CancelFunc)\nfunc WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc)\nfunc WithTimeoutCause(parent Context, timeout time.Duration, cause error) (Context, CancelFunc)\ntype CancelCauseFunc func(cause error)\ntype CancelFunc func()\ntype Context interface{ ... }\n func Background() Context\n func TODO() Context\n func WithValue(parent Context, key, val any) Context\n func WithoutCancel(parent Context) Context", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "var Canceled = errors.New(\"context canceled\")\nvar DeadlineExceeded error = deadlineExceededError{}\nfunc AfterFunc(ctx Context, f func()) (stop func() bool)\nfunc Cause(c Context) error\nfunc WithCancel(parent Context) (ctx Context, cancel CancelFunc)\nfunc WithCancelCause(parent Context) (ctx Context, cancel CancelCauseFunc)\nfunc WithDeadline(parent Context, d time.Time) (Context, CancelFunc)\nfunc WithDeadlineCause(parent Context, d time.Time, cause error) (Context, CancelFunc)\nfunc WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc)\nfunc WithTimeoutCause(parent Context, timeout time.Duration, cause error) (Context, CancelFunc)\ntype CancelCauseFunc func(cause error)\ntype CancelFunc func()\ntype Context interface{ ... }\n func Background() Context\n func TODO() Context\n func WithValue(parent Context, key, val any) Context\n func WithoutCancel(parent Context) Context", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd data-go-version=\"go1.22.0\" doc=\"-short context\" exec=\"go doc -short context\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "basics", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.7:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "The ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context", + "href": "https://pkg.go.dev/context", + "target": "_blank" + }, + "filename": "basics", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "for", + "Val": "context" + }, + { + "Namespace": "", + "Key": "href", + "Val": "https://pkg.go.dev/context" + }, + { + "Namespace": "", + "Key": "target", + "Val": "_blank" + } + ], + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": {}, + "filename": "basics", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ] + ], + "tag": "\u003ca for=\"context\" href=\"https://pkg.go.dev/context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context" + } + ], + { + "text": " package.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 7, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-7\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "h2", + "attributes": {}, + "filename": "basics.md", + "html_node": { + "data": "h2", + "data_atom": "h2", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "level": 2, + "nodes": [ + { + "text": "The Background Context", + "type": "hype.Text" + } + ], + "tag": "\u003ch2\u003e", + "type": "hype.Heading" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "basics.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "While often we might be given a ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "basics.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "basics.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": ", we might also be the one start a ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "basics.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "basics.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": ". The most common way to provide a quick and easy way to start a ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "basics.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "basics.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": " is to use the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Background", + "href": "https://pkg.go.dev/context#Background", + "target": "_blank" + }, + "filename": "basics.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "basics.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Background", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Background\" href=\"https://pkg.go.dev/context#Background\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Background" + } + ], + { + "text": " function, ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-8" + }, + "filename": "basics.md", + "html_node": { + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-8" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.8", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-8\"\u003e", + "type": "hype.Link", + "url": "#listing-1-8" + } + ], + "tag": "\u003cref id=\"listing-1-8\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ".", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-8", + "type": "listing" + }, + "filename": "basics.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "background.doc" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "args": [ + "go", + "doc", + "context.Background" + ], + "atom": "cmd", + "attributes": { + "data-go-version": "go1.22.0", + "doc": "context.Background", + "exec": "go doc context.Background" + }, + "expected_exit": 0, + "filename": "basics", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "data-go-version", + "Val": "go1.22.0" + }, + { + "Namespace": "", + "Key": "doc", + "Val": "context.Background" + }, + { + "Namespace": "", + "Key": "exec", + "Val": "go doc context.Background" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "doc", + "context.Background" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypejs", + "duration": "2.023419583s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go doc context.Background\n\npackage context // import \u0026#34;context\u0026#34;\n\nfunc Background() Context\n Background returns a non-nil, empty Context. It is never canceled, has no\n values, and has no deadline. It is typically used by the main function,\n initialization, and tests, and as the top-level Context for incoming\n requests.", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "package context // import \"context\"\n\nfunc Background() Context\n Background returns a non-nil, empty Context. It is never canceled, has no\n values, and has no deadline. It is typically used by the main function,\n initialization, and tests, and as the top-level Context for incoming\n requests.", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "doc", + "context.Background" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypejs", + "duration": "2.023419583s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go doc context.Background\n\npackage context // import \u0026#34;context\u0026#34;\n\nfunc Background() Context\n Background returns a non-nil, empty Context. It is never canceled, has no\n values, and has no deadline. It is typically used by the main function,\n initialization, and tests, and as the top-level Context for incoming\n requests.", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "package context // import \"context\"\n\nfunc Background() Context\n Background returns a non-nil, empty Context. It is never canceled, has no\n values, and has no deadline. It is typically used by the main function,\n initialization, and tests, and as the top-level Context for incoming\n requests.", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd data-go-version=\"go1.22.0\" doc=\"context.Background\" exec=\"go doc context.Background\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "basics", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.8:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "The ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Background", + "href": "https://pkg.go.dev/context#Background", + "target": "_blank" + }, + "filename": "basics", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "for", + "Val": "context#Background" + }, + { + "Namespace": "", + "Key": "href", + "Val": "https://pkg.go.dev/context#Background" + }, + { + "Namespace": "", + "Key": "target", + "Val": "_blank" + } + ], + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": {}, + "filename": "basics", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Background", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ] + ], + "tag": "\u003ca for=\"context#Background\" href=\"https://pkg.go.dev/context#Background\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Background" + } + ], + { + "text": " function.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 8, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-8\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "basics.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "In, ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-9" + }, + "filename": "basics.md", + "html_node": { + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-9" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.9", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-9\"\u003e", + "type": "hype.Link", + "url": "#listing-1-9" + } + ], + "tag": "\u003cref id=\"listing-1-9\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ", we print the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "basics.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "basics.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": " returned by ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Background", + "href": "https://pkg.go.dev/context#Background", + "target": "_blank" + }, + "filename": "basics.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "basics.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Background", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Background\" href=\"https://pkg.go.dev/context#Background\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Background" + } + ], + { + "text": ". As we can see from the output, the context is empty.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-9", + "type": "listing" + }, + "filename": "basics.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "empty" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + { + "atom": "pre", + "attributes": {}, + "filename": "basics", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "src": "basics/src/background/empty/main.go#example" + }, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/background/empty/main.go#example" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "content": "func main() {\n\tctx := context.Background()\n\n\t// print the current value\n\t// of the context\n\tfmt.Printf(\"%v\\n\", ctx)\n\n\t// print Go-syntax representation of the value\n\tfmt.Printf(\"\\t%#v\\n\", ctx)\n}", + "file": "basics/src/background/empty/main.go", + "lang": "go", + "name": "example", + "start": 8, + "end": 20 + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" src=\"basics/src/background/empty/main.go#example\"\u003e", + "type": "hype.SourceCode" + } + ] + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + }, + { + "atom": "hr", + "attributes": {}, + "filename": "basics", + "html_node": { + "data": "hr", + "data_atom": "hr", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [], + "tag": "\u003chr\u003e", + "type": "hype.Element" + }, + [ + { + "args": [ + "go", + "run", + "main.go" + ], + "atom": "cmd", + "attributes": { + "data-go-version": "go1.22.0", + "exec": "go run main.go", + "run": "main.go", + "src": "basics/src/background/empty" + }, + "expected_exit": 0, + "filename": "basics", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "data-go-version", + "Val": "go1.22.0" + }, + { + "Namespace": "", + "Key": "exec", + "Val": "go run main.go" + }, + { + "Namespace": "", + "Key": "run", + "Val": "main.go" + }, + { + "Namespace": "", + "Key": "src", + "Val": "src/background/empty" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "run", + "main.go" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/12-context/basics/src/background/empty", + "duration": "4.437636834s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go run main.go\n\ncontext.Background\n\tcontext.backgroundCtx{emptyCtx:context.emptyCtx{}}", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "context.Background\n\tcontext.backgroundCtx{emptyCtx:context.emptyCtx{}}", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "run", + "main.go" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/12-context/basics/src/background/empty", + "duration": "4.437636834s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go run main.go\n\ncontext.Background\n\tcontext.backgroundCtx{emptyCtx:context.emptyCtx{}}", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "context.Background\n\tcontext.backgroundCtx{emptyCtx:context.emptyCtx{}}", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd data-go-version=\"go1.22.0\" exec=\"go run main.go\" run=\"main.go\" src=\"basics/src/background/empty\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "basics", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.9:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "The ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Background", + "href": "https://pkg.go.dev/context#Background", + "target": "_blank" + }, + "filename": "basics", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "for", + "Val": "context#Background" + }, + { + "Namespace": "", + "Key": "href", + "Val": "https://pkg.go.dev/context#Background" + }, + { + "Namespace": "", + "Key": "target", + "Val": "_blank" + } + ], + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": {}, + "filename": "basics", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Background", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ] + ], + "tag": "\u003ca for=\"context#Background\" href=\"https://pkg.go.dev/context#Background\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Background" + } + ], + { + "text": " function.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 9, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-9\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "h2", + "attributes": {}, + "filename": "basics.md", + "html_node": { + "data": "h2", + "data_atom": "h2", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "level": 2, + "nodes": [ + { + "text": "Default Implementations", + "type": "hype.Text" + } + ], + "tag": "\u003ch2\u003e", + "type": "hype.Heading" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "basics.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "The ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Background", + "href": "https://pkg.go.dev/context#Background", + "target": "_blank" + }, + "filename": "basics.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "basics.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Background", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Background\" href=\"https://pkg.go.dev/context#Background\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Background" + } + ], + { + "text": " interface, while empty, does provide default implementations of the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "basics.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "basics.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": " interface. Because of this the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Background", + "href": "https://pkg.go.dev/context#Background", + "target": "_blank" + }, + "filename": "basics.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "basics.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Background", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Background\" href=\"https://pkg.go.dev/context#Background\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Background" + } + ], + { + "text": " context is almost always used as the base of a new ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "basics.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "basics.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": " hierarchy.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-10", + "type": "listing" + }, + "filename": "basics.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "implementation" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + { + "atom": "pre", + "attributes": {}, + "filename": "basics", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "src": "basics/src/background/implementation/main.go#example" + }, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/background/implementation/main.go#example" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "content": "func main() {\n\tctx := context.Background()\n\n\t// print the current value\n\t// of the context\n\tfmt.Printf(\"%v\\n\", ctx)\n\n\t// print Go-syntax representation of the value\n\tfmt.Printf(\"\\t%#v\\n\", ctx)\n\n\t// print the value of the Done channel\n\t// does not block because we are not\n\t// trying to read/write to the channel\n\tfmt.Printf(\"\\tDone:\\t%#v\\n\", ctx.Done())\n\n\t// print the value of the Err\n\tfmt.Printf(\"\\tErr:\\t%#v\\n\", ctx.Err())\n\n\t// print the value of \"KEY\"\n\tfmt.Printf(\"\\tValue:\\t%#v\\n\", ctx.Value(\"KEY\"))\n\n\t// print the deadline time\n\t// and true/false if there is no deadline\n\tdeadline, ok := ctx.Deadline()\n\tfmt.Printf(\"\\tDeadline:\\t%s (%t)\\n\", deadline, ok)\n}", + "file": "basics/src/background/implementation/main.go", + "lang": "go", + "name": "example", + "start": 8, + "end": 36 + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" src=\"basics/src/background/implementation/main.go#example\"\u003e", + "type": "hype.SourceCode" + } + ] + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + }, + { + "atom": "hr", + "attributes": {}, + "filename": "basics", + "html_node": { + "data": "hr", + "data_atom": "hr", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [], + "tag": "\u003chr\u003e", + "type": "hype.Element" + }, + [ + { + "args": [ + "go", + "run", + "main.go" + ], + "atom": "cmd", + "attributes": { + "data-go-version": "go1.22.0", + "exec": "go run main.go", + "run": "main.go", + "src": "basics/src/background/implementation" + }, + "expected_exit": 0, + "filename": "basics", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "data-go-version", + "Val": "go1.22.0" + }, + { + "Namespace": "", + "Key": "exec", + "Val": "go run main.go" + }, + { + "Namespace": "", + "Key": "run", + "Val": "main.go" + }, + { + "Namespace": "", + "Key": "src", + "Val": "src/background/implementation" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "run", + "main.go" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/12-context/basics/src/background/implementation", + "duration": "5.010966s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go run main.go\n\ncontext.Background\n\tcontext.backgroundCtx{emptyCtx:context.emptyCtx{}}\n\tDone:\t(\u0026lt;-chan struct {})(nil)\n\tErr:\t\u0026lt;nil\u0026gt;\n\tValue:\t\u0026lt;nil\u0026gt;\n\tDeadline:\t0001-01-01 00:00:00 +0000 UTC (false)", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "context.Background\n\tcontext.backgroundCtx{emptyCtx:context.emptyCtx{}}\n\tDone:\t(\u003c-chan struct {})(nil)\n\tErr:\t\u003cnil\u003e\n\tValue:\t\u003cnil\u003e\n\tDeadline:\t0001-01-01 00:00:00 +0000 UTC (false)", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "run", + "main.go" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/12-context/basics/src/background/implementation", + "duration": "5.010966s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go run main.go\n\ncontext.Background\n\tcontext.backgroundCtx{emptyCtx:context.emptyCtx{}}\n\tDone:\t(\u0026lt;-chan struct {})(nil)\n\tErr:\t\u0026lt;nil\u0026gt;\n\tValue:\t\u0026lt;nil\u0026gt;\n\tDeadline:\t0001-01-01 00:00:00 +0000 UTC (false)", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "context.Background\n\tcontext.backgroundCtx{emptyCtx:context.emptyCtx{}}\n\tDone:\t(\u003c-chan struct {})(nil)\n\tErr:\t\u003cnil\u003e\n\tValue:\t\u003cnil\u003e\n\tDeadline:\t0001-01-01 00:00:00 +0000 UTC (false)", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd data-go-version=\"go1.22.0\" exec=\"go run main.go\" run=\"main.go\" src=\"basics/src/background/implementation\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "basics", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.10:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "The ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Background", + "href": "https://pkg.go.dev/context#Background", + "target": "_blank" + }, + "filename": "basics", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "for", + "Val": "context#Background" + }, + { + "Namespace": "", + "Key": "href", + "Val": "https://pkg.go.dev/context#Background" + }, + { + "Namespace": "", + "Key": "target", + "Val": "_blank" + } + ], + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": {}, + "filename": "basics", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Background", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ] + ], + "tag": "\u003ca for=\"context#Background\" href=\"https://pkg.go.dev/context#Background\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Background" + } + ], + { + "text": " function provides default implementation of the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "basics", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "for", + "Val": "context#Context" + }, + { + "Namespace": "", + "Key": "href", + "Val": "https://pkg.go.dev/context#Context" + }, + { + "Namespace": "", + "Key": "target", + "Val": "_blank" + } + ], + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": {}, + "filename": "basics", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ] + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": " interface.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 10, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-10\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "tag": "\u003cpage\u003e", + "title": "The Context Interface", + "type": "hype.Page" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "tag": "\u003cinclude src=\"basics/basics.md\"\u003e", + "type": "hype.Include" + } + ], + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "atom": "include", + "attributes": { + "src": "rules/rules.md" + }, + "dir": "rules", + "filename": "module.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "rules/rules.md" + } + ], + "data": "include", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "page", + "attributes": {}, + "filename": "rules.md", + "html_node": { + "data": "page", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "atom": "h1", + "attributes": {}, + "filename": "rules.md", + "html_node": { + "data": "h1", + "data_atom": "h1", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "level": 1, + "nodes": [ + { + "text": "Context Rules", + "type": "hype.Text" + } + ], + "tag": "\u003ch1\u003e", + "type": "hype.Heading" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "rules.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "According the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context", + "href": "https://pkg.go.dev/context", + "target": "_blank" + }, + "filename": "rules.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "rules.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context\" href=\"https://pkg.go.dev/context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context" + } + ], + { + "text": " documentation there are rules that must be followed when using the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context", + "href": "https://pkg.go.dev/context", + "target": "_blank" + }, + "filename": "rules.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "rules.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context\" href=\"https://pkg.go.dev/context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context" + } + ], + { + "text": " package, ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-11" + }, + "filename": "rules.md", + "html_node": { + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-11" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.11", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-11\"\u003e", + "type": "hype.Link", + "url": "#listing-1-11" + } + ], + "tag": "\u003cref id=\"listing-1-11\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ".", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-11", + "type": "listing" + }, + "filename": "rules.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "doc" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "atom": "ul", + "attributes": {}, + "filename": "rules", + "html_node": { + "data": "ul", + "data_atom": "ul", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "atom": "li", + "attributes": {}, + "filename": "rules", + "html_node": { + "data": "li", + "data_atom": "li", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "list-type": "ul", + "nodes": [ + { + "text": "Programs that use Contexts should follow these rules to keep interfaces consistent across packages and enable static analysis tools to check context propagation.", + "type": "hype.Text" + } + ], + "tag": "\u003cli\u003e", + "type": "hype.LI" + } + ], + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "atom": "li", + "attributes": {}, + "filename": "rules", + "html_node": { + "data": "li", + "data_atom": "li", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "list-type": "ul", + "nodes": [ + { + "text": "Do not store Contexts inside a struct type; instead, pass a Context explicitly to each function that needs it. The Context should be the first parameter, typically named ctx.", + "type": "hype.Text" + } + ], + "tag": "\u003cli\u003e", + "type": "hype.LI" + } + ], + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "atom": "li", + "attributes": {}, + "filename": "rules", + "html_node": { + "data": "li", + "data_atom": "li", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "list-type": "ul", + "nodes": [ + { + "text": "Do not pass a ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "rules", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "nil", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " Context, even if a function permits it. Pass ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#TODO", + "href": "https://pkg.go.dev/context#TODO", + "target": "_blank" + }, + "filename": "rules", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "for", + "Val": "context#TODO" + }, + { + "Namespace": "", + "Key": "href", + "Val": "https://pkg.go.dev/context#TODO" + }, + { + "Namespace": "", + "Key": "target", + "Val": "_blank" + } + ], + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": {}, + "filename": "rules", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.TODO", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ] + ], + "tag": "\u003ca for=\"context#TODO\" href=\"https://pkg.go.dev/context#TODO\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#TODO" + } + ], + { + "text": " if you are unsure about which Context to use.", + "type": "hype.Text" + } + ], + "tag": "\u003cli\u003e", + "type": "hype.LI" + } + ], + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "atom": "li", + "attributes": {}, + "filename": "rules", + "html_node": { + "data": "li", + "data_atom": "li", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "list-type": "ul", + "nodes": [ + { + "text": "Use context Values only for request-scoped data that transits processes and APIs, not for passing optional parameters to functions.", + "type": "hype.Text" + } + ], + "tag": "\u003cli\u003e", + "type": "hype.LI" + } + ], + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "atom": "li", + "attributes": {}, + "filename": "rules", + "html_node": { + "data": "li", + "data_atom": "li", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "list-type": "ul", + "nodes": [ + { + "text": "The same Context may be passed to functions running in different goroutines; Contexts are safe for simultaneous use by multiple goroutines.", + "type": "hype.Text" + } + ], + "tag": "\u003cli\u003e", + "type": "hype.LI" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "tag": "\u003cul\u003e", + "type": "hype.UL" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "rules", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.11:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "Rules for using contexts.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 11, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-11\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "tag": "\u003cpage\u003e", + "title": "Context Rules", + "type": "hype.Page" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "tag": "\u003cinclude src=\"rules/rules.md\"\u003e", + "type": "hype.Include" + } + ], + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "atom": "include", + "attributes": { + "src": "nodes/nodes.md" + }, + "dir": "nodes", + "filename": "module.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "nodes/nodes.md" + } + ], + "data": "include", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "page", + "attributes": {}, + "filename": "nodes.md", + "html_node": { + "data": "page", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "atom": "h1", + "attributes": {}, + "filename": "nodes.md", + "html_node": { + "data": "h1", + "data_atom": "h1", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "level": 1, + "nodes": [ + { + "text": "Context Nodal Hierarchy", + "type": "hype.Text" + } + ], + "tag": "\u003ch1\u003e", + "type": "hype.Heading" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "nodes.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "As the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context", + "href": "https://pkg.go.dev/context", + "target": "_blank" + }, + "filename": "nodes.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "nodes.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context\" href=\"https://pkg.go.dev/context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context" + } + ], + { + "text": " documentation states, a ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "nodes.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "nodes.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": " is not meant to be stored and held onto, but should be passed at \"runtime\".", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "nodes.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Consider an HTTP request. An HTTP request is a ", + "type": "hype.Text" + }, + { + "atom": "strong", + "attributes": {}, + "filename": "nodes.md", + "html_node": { + "data": "strong", + "data_atom": "strong", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "runtime", + "type": "hype.Text" + } + ], + "tag": "\u003cstrong\u003e", + "type": "hype.Element" + }, + { + "text": " value that gets passed along through the application until eventually the response is returned. We would not want to store, or hold on to, the request for future use as it would be of no benefit once the response is returned.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "nodes.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Using ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "nodes.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "nodes.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": " in our code behaves like the HTTP request. We pass a ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "nodes.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "nodes.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": " through the application where they can be listened to for cancellation, or for other purposes, at \"runtime\".", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "nodes.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "As a ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "nodes.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "nodes.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": " is passed through the application, a receiving method may wrap the context with their cancellation functionality or with ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#WithValue", + "href": "https://pkg.go.dev/context#WithValue", + "target": "_blank" + }, + "filename": "nodes.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "nodes.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.WithValue", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#WithValue\" href=\"https://pkg.go.dev/context#WithValue\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#WithValue" + } + ], + { + "text": " to add a value, such as a \"request id\", before passing the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "nodes.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "nodes.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": " along to any functions, or methods, that it may call.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "nodes.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "The result is a nodal hierarchy of ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "nodes.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "nodes.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": " values that starts at the beginning of the request, or the start of the application, and spiders out throughout the application.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "h2", + "attributes": {}, + "filename": "nodes.md", + "html_node": { + "data": "h2", + "data_atom": "h2", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "level": 2, + "nodes": [ + { + "text": "Understanding the Nodal Hierarchy", + "type": "hype.Text" + } + ], + "tag": "\u003ch2\u003e", + "type": "hype.Heading" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "nodes.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Consider ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-12" + }, + "filename": "nodes.md", + "html_node": { + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-12" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.12", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-12\"\u003e", + "type": "hype.Link", + "url": "#listing-1-12" + } + ], + "tag": "\u003cref id=\"listing-1-12\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ". We start with a ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Background", + "href": "https://pkg.go.dev/context#Background", + "target": "_blank" + }, + "filename": "nodes.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "nodes.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Background", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Background\" href=\"https://pkg.go.dev/context#Background\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Background" + } + ], + { + "text": " context and pass it the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "nodes.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "A", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " and ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "nodes.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "B", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " functions. Each function wraps the given ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "nodes.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "nodes.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": ", prints that new ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "nodes.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "nodes.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": " with a new one before either passing it along to the next function or returning.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-12", + "type": "listing" + }, + "filename": "nodes.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "tree" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + { + "atom": "pre", + "attributes": {}, + "filename": "nodes", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "src": "nodes/src/node-tree/main.go#main" + }, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/node-tree/main.go#main" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "content": "func main() {\n\t// create a background context\n\tbg := context.Background()\n\n\t// pass the background context to the A function\n\tA(bg)\n\n\t// pass the background context to the B function\n\tB(bg)\n}", + "file": "nodes/src/node-tree/main.go", + "lang": "go", + "name": "main", + "start": 16, + "end": 28 + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" src=\"nodes/src/node-tree/main.go#main\"\u003e", + "type": "hype.SourceCode" + } + ] + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + }, + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "nodes", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.12:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "Wrapping contexts creates nodal hierarchies.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 12, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-12\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "h2", + "attributes": {}, + "filename": "nodes.md", + "html_node": { + "data": "h2", + "data_atom": "h2", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "level": 2, + "nodes": [ + { + "text": "Wrapping with Context Values", + "type": "hype.Text" + } + ], + "tag": "\u003ch2\u003e", + "type": "hype.Heading" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "nodes.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "To wrap the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "nodes.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "nodes.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": " with a new one, we will use ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#WithValue", + "href": "https://pkg.go.dev/context#WithValue", + "target": "_blank" + }, + "filename": "nodes.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "nodes.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.WithValue", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#WithValue\" href=\"https://pkg.go.dev/context#WithValue\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#WithValue" + } + ], + { + "text": ". The ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#WithValue", + "href": "https://pkg.go.dev/context#WithValue", + "target": "_blank" + }, + "filename": "nodes.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "nodes.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.WithValue", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#WithValue\" href=\"https://pkg.go.dev/context#WithValue\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#WithValue" + } + ], + { + "text": " function takes a ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "nodes.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "nodes.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": " and a key and value, and returns a new ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "nodes.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "nodes.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": " with the given key and value that wraps the original ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "nodes.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "nodes.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": ". We will learn more about ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#WithValue", + "href": "https://pkg.go.dev/context#WithValue", + "target": "_blank" + }, + "filename": "nodes.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "nodes.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.WithValue", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#WithValue\" href=\"https://pkg.go.dev/context#WithValue\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#WithValue" + } + ], + { + "text": " later.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "h2", + "attributes": {}, + "filename": "nodes.md", + "html_node": { + "data": "h2", + "data_atom": "h2", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "level": 2, + "nodes": [ + { + "text": "Following the Context Nodes", + "type": "hype.Text" + } + ], + "tag": "\u003ch2\u003e", + "type": "hype.Heading" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "nodes.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "In ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-13" + }, + "filename": "nodes.md", + "html_node": { + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-13" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.13", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-13\"\u003e", + "type": "hype.Link", + "url": "#listing-1-13" + } + ], + "tag": "\u003cref id=\"listing-1-13\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ", we define the functions used in ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-12" + }, + "filename": "nodes.md", + "html_node": { + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-12" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.12", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-12\"\u003e", + "type": "hype.Link", + "url": "#listing-1-12" + } + ], + "tag": "\u003cref id=\"listing-1-12\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ". Each of these functions takes a ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "nodes.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "nodes.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": " as an argument. They then wrap the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "nodes.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "nodes.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": " with a new one, print the new ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "nodes.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "nodes.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": " with a new one, and pass it along to the next function.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-13", + "type": "listing" + }, + "filename": "nodes.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "example" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + { + "atom": "pre", + "attributes": {}, + "filename": "nodes", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "src": "nodes/src/node-tree/main.go#example" + }, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/node-tree/main.go#example" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "content": "func A(ctx context.Context) {\n\t// wrap ctx with a new context\n\t// with the ID set to \"A\"\n\tA := context.WithValue(ctx, ID, \"A\")\n\tprint(\"A\", A)\n\n\t// pass the A context to the A1 function\n\tA1(A)\n}\n\nfunc A1(ctx context.Context) {\n\tA1 := context.WithValue(ctx, ID, \"A1\")\n\tprint(\"A1\", A1)\n}\n\nfunc B(ctx context.Context) {\n\t// wrap ctx with a new context\n\t// with the ID set to \"B\"\n\tB := context.WithValue(ctx, ID, \"B\")\n\tprint(\"B\", B)\n\n\t// pass the B context to the B1 function\n\tB1(B)\n}\n\nfunc B1(ctx context.Context) {\n\t// wrap ctx with a new context\n\t// with the ID set to \"B1\"\n\tB1 := context.WithValue(ctx, ID, \"B1\")\n\tprint(\"B1\", B1)\n\n\t// pass the B1 context to the B1a function\n\tB1a(B1)\n}\n\nfunc B1a(ctx context.Context) {\n\t// wrap ctx with a new context\n\t// with the ID set to \"B1a\"\n\tB1a := context.WithValue(ctx, ID, \"B1a\")\n\tprint(\"B1a\", B1a)\n}", + "file": "nodes/src/node-tree/main.go", + "lang": "go", + "name": "example", + "start": 30, + "end": 73 + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" src=\"nodes/src/node-tree/main.go#example\"\u003e", + "type": "hype.SourceCode" + } + ] + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + }, + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "nodes", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.13:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "The example application.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 13, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-13\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "nodes.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "When we look at the output of the program, ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-14" + }, + "filename": "nodes.md", + "html_node": { + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-14" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.14", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-14\"\u003e", + "type": "hype.Link", + "url": "#listing-1-14" + } + ], + "tag": "\u003cref id=\"listing-1-14\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ", we can see that when we print out any given ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "nodes.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "nodes.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": " we see that is at the bottom of the node tree and the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Background", + "href": "https://pkg.go.dev/context#Background", + "target": "_blank" + }, + "filename": "nodes.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "nodes.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Background", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Background\" href=\"https://pkg.go.dev/context#Background\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Background" + } + ], + { + "text": " context is at the top of the node tree hierarchy.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-14", + "type": "listing" + }, + "filename": "nodes.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "out" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "args": [ + "go", + "run", + "main.go" + ], + "atom": "cmd", + "attributes": { + "data-go-version": "go1.22.0", + "exec": "go run main.go", + "run": "main.go", + "src": "nodes/src/node-tree" + }, + "expected_exit": 0, + "filename": "nodes", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "data-go-version", + "Val": "go1.22.0" + }, + { + "Namespace": "", + "Key": "exec", + "Val": "go run main.go" + }, + { + "Namespace": "", + "Key": "run", + "Val": "main.go" + }, + { + "Namespace": "", + "Key": "src", + "Val": "src/node-tree" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "run", + "main.go" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/12-context/nodes/src/node-tree", + "duration": "1.745072417s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go run main.go\n\nA.WithValue(key: ctx_id, value: A)\n\t--\u0026gt; context.backgroundCtx\n\nA1.WithValue(key: ctx_id, value: A1)\n\t--\u0026gt; WithValue(key: ctx_id, value: A)\n\t\t--\u0026gt; context.backgroundCtx\n\nB.WithValue(key: ctx_id, value: B)\n\t--\u0026gt; context.backgroundCtx\n\nB1.WithValue(key: ctx_id, value: B1)\n\t--\u0026gt; WithValue(key: ctx_id, value: B)\n\t\t--\u0026gt; context.backgroundCtx\n\nB1a.WithValue(key: ctx_id, value: B1a)\n\t--\u0026gt; WithValue(key: ctx_id, value: B1)\n\t\t--\u0026gt; WithValue(key: ctx_id, value: B)\n\t\t\t--\u0026gt; context.backgroundCtx", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "A.WithValue(key: ctx_id, value: A)\n\t--\u003e context.backgroundCtx\n\nA1.WithValue(key: ctx_id, value: A1)\n\t--\u003e WithValue(key: ctx_id, value: A)\n\t\t--\u003e context.backgroundCtx\n\nB.WithValue(key: ctx_id, value: B)\n\t--\u003e context.backgroundCtx\n\nB1.WithValue(key: ctx_id, value: B1)\n\t--\u003e WithValue(key: ctx_id, value: B)\n\t\t--\u003e context.backgroundCtx\n\nB1a.WithValue(key: ctx_id, value: B1a)\n\t--\u003e WithValue(key: ctx_id, value: B1)\n\t\t--\u003e WithValue(key: ctx_id, value: B)\n\t\t\t--\u003e context.backgroundCtx", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "run", + "main.go" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/12-context/nodes/src/node-tree", + "duration": "1.745072417s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go run main.go\n\nA.WithValue(key: ctx_id, value: A)\n\t--\u0026gt; context.backgroundCtx\n\nA1.WithValue(key: ctx_id, value: A1)\n\t--\u0026gt; WithValue(key: ctx_id, value: A)\n\t\t--\u0026gt; context.backgroundCtx\n\nB.WithValue(key: ctx_id, value: B)\n\t--\u0026gt; context.backgroundCtx\n\nB1.WithValue(key: ctx_id, value: B1)\n\t--\u0026gt; WithValue(key: ctx_id, value: B)\n\t\t--\u0026gt; context.backgroundCtx\n\nB1a.WithValue(key: ctx_id, value: B1a)\n\t--\u0026gt; WithValue(key: ctx_id, value: B1)\n\t\t--\u0026gt; WithValue(key: ctx_id, value: B)\n\t\t\t--\u0026gt; context.backgroundCtx", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "A.WithValue(key: ctx_id, value: A)\n\t--\u003e context.backgroundCtx\n\nA1.WithValue(key: ctx_id, value: A1)\n\t--\u003e WithValue(key: ctx_id, value: A)\n\t\t--\u003e context.backgroundCtx\n\nB.WithValue(key: ctx_id, value: B)\n\t--\u003e context.backgroundCtx\n\nB1.WithValue(key: ctx_id, value: B1)\n\t--\u003e WithValue(key: ctx_id, value: B)\n\t\t--\u003e context.backgroundCtx\n\nB1a.WithValue(key: ctx_id, value: B1a)\n\t--\u003e WithValue(key: ctx_id, value: B1)\n\t\t--\u003e WithValue(key: ctx_id, value: B)\n\t\t\t--\u003e context.backgroundCtx", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd data-go-version=\"go1.22.0\" exec=\"go run main.go\" run=\"main.go\" src=\"nodes/src/node-tree\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "nodes", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.14:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "Printing the node tree.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 14, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-14\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "nodes.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "In ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-15" + }, + "filename": "nodes.md", + "html_node": { + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-15" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.15", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-15\"\u003e", + "type": "hype.Link", + "url": "#listing-1-15" + } + ], + "tag": "\u003cref id=\"listing-1-15\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ", we see that the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "nodes.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "B1a", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "nodes.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "nodes.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": " is a child of the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "nodes.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "B1", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "nodes.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "nodes.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": " and the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "nodes.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "B1", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "nodes.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "nodes.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": " is a child of the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "nodes.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "B", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "nodes.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "nodes.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": " and the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "nodes.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "B", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "nodes.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "nodes.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": " is a child of the original background ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "nodes.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "nodes.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": ".", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-15", + "type": "listing" + }, + "filename": "nodes.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "example-tree" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "atom": "img", + "attributes": { + "src": "nodes/assets/nodes.svg" + }, + "filename": "nodes", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "assets/nodes.svg" + } + ], + "data": "img", + "data_atom": "img", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [], + "tag": "\u003cimg src=\"nodes/assets/nodes.svg\"\u003e", + "type": "hype.Image" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "nodes", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.15:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "Visualizing the node tree.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 15, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-15\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "tag": "\u003cpage\u003e", + "title": "Context Nodal Hierarchy", + "type": "hype.Page" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "tag": "\u003cinclude src=\"nodes/nodes.md\"\u003e", + "type": "hype.Include" + } + ], + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "atom": "include", + "attributes": { + "src": "values/values.md" + }, + "dir": "values", + "filename": "module.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "values/values.md" + } + ], + "data": "include", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "page", + "attributes": {}, + "filename": "values.md", + "html_node": { + "data": "page", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "atom": "h1", + "attributes": {}, + "filename": "values.md", + "html_node": { + "data": "h1", + "data_atom": "h1", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "level": 1, + "nodes": [ + { + "text": "Context Values", + "type": "hype.Text" + } + ], + "tag": "\u003ch1\u003e", + "type": "hype.Heading" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "values.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "As we have seen one feature of the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context", + "href": "https://pkg.go.dev/context", + "target": "_blank" + }, + "filename": "values.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "values.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context\" href=\"https://pkg.go.dev/context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context" + } + ], + { + "text": " package is that it allows you to pass request specific values to the next function in the chain.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "values.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "This provide a lot of useful benefits, such as passing request or session specific values, such as the request id, user id of the requestor, etc. to the next function in the chain.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "values.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Using values, however, has its disadvantages, as we will see shortly.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "h2", + "attributes": {}, + "filename": "values.md", + "html_node": { + "data": "h2", + "data_atom": "h2", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "level": 2, + "nodes": [ + { + "text": "Understanding Context Values", + "type": "hype.Text" + } + ], + "tag": "\u003ch2\u003e", + "type": "hype.Heading" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "values.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "The ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#WithValue", + "href": "https://pkg.go.dev/context#WithValue", + "target": "_blank" + }, + "filename": "values.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "values.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.WithValue", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#WithValue\" href=\"https://pkg.go.dev/context#WithValue\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#WithValue" + } + ], + { + "text": " function can be used to wrap a given ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "values.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "values.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": " with a new ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "values.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "values.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": " that contains the given key/value pair.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "args": [ + "go", + "doc", + "context.WithValue" + ], + "atom": "cmd", + "attributes": { + "data-go-version": "go1.22.0", + "doc": "context.WithValue", + "exec": "go doc context.WithValue" + }, + "expected_exit": 0, + "filename": "values.md", + "html_node": { + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "doc", + "context.WithValue" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypejs", + "duration": "1.56529775s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go doc context.WithValue\n\npackage context // import \u0026#34;context\u0026#34;\n\nfunc WithValue(parent Context, key, val any) Context\n WithValue returns a copy of parent in which the value associated with key is\n val.\n\n Use context Values only for request-scoped data that transits processes and\n APIs, not for passing optional parameters to functions.\n\n The provided key must be comparable and should not be of type string or any\n other built-in type to avoid collisions between packages using context.\n Users of WithValue should define their own types for keys. To avoid\n allocating when assigning to an interface{}, context keys often have\n concrete type struct{}. Alternatively, exported context key variables\u0026#39;\n static type should be a pointer or interface.", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "package context // import \"context\"\n\nfunc WithValue(parent Context, key, val any) Context\n WithValue returns a copy of parent in which the value associated with key is\n val.\n\n Use context Values only for request-scoped data that transits processes and\n APIs, not for passing optional parameters to functions.\n\n The provided key must be comparable and should not be of type string or any\n other built-in type to avoid collisions between packages using context.\n Users of WithValue should define their own types for keys. To avoid\n allocating when assigning to an interface{}, context keys often have\n concrete type struct{}. Alternatively, exported context key variables'\n static type should be a pointer or interface.", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "doc", + "context.WithValue" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypejs", + "duration": "1.56529775s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go doc context.WithValue\n\npackage context // import \u0026#34;context\u0026#34;\n\nfunc WithValue(parent Context, key, val any) Context\n WithValue returns a copy of parent in which the value associated with key is\n val.\n\n Use context Values only for request-scoped data that transits processes and\n APIs, not for passing optional parameters to functions.\n\n The provided key must be comparable and should not be of type string or any\n other built-in type to avoid collisions between packages using context.\n Users of WithValue should define their own types for keys. To avoid\n allocating when assigning to an interface{}, context keys often have\n concrete type struct{}. Alternatively, exported context key variables\u0026#39;\n static type should be a pointer or interface.", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "package context // import \"context\"\n\nfunc WithValue(parent Context, key, val any) Context\n WithValue returns a copy of parent in which the value associated with key is\n val.\n\n Use context Values only for request-scoped data that transits processes and\n APIs, not for passing optional parameters to functions.\n\n The provided key must be comparable and should not be of type string or any\n other built-in type to avoid collisions between packages using context.\n Users of WithValue should define their own types for keys. To avoid\n allocating when assigning to an interface{}, context keys often have\n concrete type struct{}. Alternatively, exported context key variables'\n static type should be a pointer or interface.", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd data-go-version=\"go1.22.0\" doc=\"context.WithValue\" exec=\"go doc context.WithValue\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "values.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "The ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#WithValue", + "href": "https://pkg.go.dev/context#WithValue", + "target": "_blank" + }, + "filename": "values.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "values.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.WithValue", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#WithValue\" href=\"https://pkg.go.dev/context#WithValue\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#WithValue" + } + ], + { + "text": " function takes a ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "values.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "values.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": " as its first argument, and a key and a value as its second and third arguments.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "values.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Both the key and value are ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "values.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "any", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " values. While this may seem like you can use any type for the key, this is not the case. Like maps, keys must be comparable, so complex types like maps or functions are not allowed.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "pre", + "attributes": {}, + "filename": "values.md", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "src": "values/src/keys/main.go#example" + }, + "filename": "values.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "content": "ctx := context.Background()\n\n// strings shouldn't be used as keys\n// because they can easily collide\n// with other functions, libraries, etc.\n// that set that same key.\n// instead strings should wrapped in their\n// own type.\nctx = context.WithValue(ctx, \"key\", \"value\")\n\n// keys must be comparable.\n// maps, and other complex types,\n// are not comparable and can't be used\n// used as keys.\nctx = context.WithValue(ctx, map[string]int{}, \"another value\")", + "file": "values/src/keys/main.go", + "lang": "go", + "name": "example", + "start": 9, + "end": 25 + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" src=\"values/src/keys/main.go#example\"\u003e", + "type": "hype.SourceCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + }, + { + "atom": "hr", + "attributes": {}, + "filename": "values", + "html_node": { + "data": "hr", + "data_atom": "hr", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [], + "tag": "\u003chr\u003e", + "type": "hype.Element" + }, + { + "args": [ + "go", + "run", + "main.go" + ], + "atom": "cmd", + "attributes": { + "data-go-version": "go1.22.0", + "exec": "go run main.go", + "exit": "-1", + "run": "main.go", + "src": "values/src/keys" + }, + "expected_exit": -1, + "filename": "values.md", + "html_node": { + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "run", + "main.go" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/12-context/values/src/keys", + "duration": "2.930940625s", + "err": "exit status 1", + "exit": 1, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go run main.go\n\npanic: key is not comparable\n\ngoroutine 1 [running]:\ncontext.WithValue({0x10466ae80, 0x140000b2000}, {0x10465fe00, 0x140000b2030}, {0x10465d800, 0x10466ac80})\n\t/usr/local/go/src/context/context.go:721 +0x118\nmain.main()\n\t/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/12-context/values/src/keys/main.go:24 +0x7c\nexit status 2", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "panic: key is not comparable\n\ngoroutine 1 [running]:\ncontext.WithValue({0x10466ae80, 0x140000b2000}, {0x10465fe00, 0x140000b2030}, {0x10465d800, 0x10466ac80})\n\t/usr/local/go/src/context/context.go:721 +0x118\nmain.main()\n\t/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/12-context/values/src/keys/main.go:24 +0x7c\nexit status 2", + "stdout": "", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "run", + "main.go" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/12-context/values/src/keys", + "duration": "2.930940625s", + "err": "exit status 1", + "exit": 1, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go run main.go\n\npanic: key is not comparable\n\ngoroutine 1 [running]:\ncontext.WithValue({0x10466ae80, 0x140000b2000}, {0x10465fe00, 0x140000b2030}, {0x10465d800, 0x10466ac80})\n\t/usr/local/go/src/context/context.go:721 +0x118\nmain.main()\n\t/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/12-context/values/src/keys/main.go:24 +0x7c\nexit status 2", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "panic: key is not comparable\n\ngoroutine 1 [running]:\ncontext.WithValue({0x10466ae80, 0x140000b2000}, {0x10465fe00, 0x140000b2030}, {0x10465d800, 0x10466ac80})\n\t/usr/local/go/src/context/context.go:721 +0x118\nmain.main()\n\t/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/12-context/values/src/keys/main.go:24 +0x7c\nexit status 2", + "stdout": "", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd data-go-version=\"go1.22.0\" exec=\"go run main.go\" exit=\"-1\" run=\"main.go\" src=\"values/src/keys\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "h2", + "attributes": {}, + "filename": "values.md", + "html_node": { + "data": "h2", + "data_atom": "h2", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "level": 2, + "nodes": [ + { + "text": "Key Resolution", + "type": "hype.Text" + } + ], + "tag": "\u003ch2\u003e", + "type": "hype.Heading" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "values.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "When we ask for a key through the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context.Value", + "href": "https://pkg.go.dev/context#Context.Value", + "target": "_blank" + }, + "filename": "values.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "values.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context.Value", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context.Value\" href=\"https://pkg.go.dev/context#Context.Value\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context.Value" + } + ], + { + "text": " function, the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "values.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "values.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": " will first check if the key is present in the current ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "values.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "values.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": ". If the key is present, the value is returned. If the key is not present, the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "values.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "values.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": " will then check if the key is present in the parent ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "values.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "values.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": ". If the key is present, the value is returned. If the key is not present, the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "values.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "values.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": " will then check if the key is present in the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "values.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "values.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": "'s parent's parent, and so on.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "values.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Consider the following example. We wrap a ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "values.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "values.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": " multiple times with different key/values.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "pre", + "attributes": {}, + "filename": "values.md", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "src": "values/src/resolution/main.go#example" + }, + "filename": "values.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/resolution/main.go#example" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "content": "func main() {\n\n\t// create a new background context\n\tctx := context.Background()\n\n\t// wrap the context with a new context\n\t// that has the key \"A\" and the value \"a\",\n\tctx = context.WithValue(ctx, CtxKey(\"A\"), \"a\")\n\n\t// wrap the context with a new context\n\t// that has the key \"B\" and the value \"b\",\n\tctx = context.WithValue(ctx, CtxKey(\"B\"), \"b\")\n\n\t// wrap the context with a new context\n\t// that has the key \"C\" and the value \"c\",\n\tctx = context.WithValue(ctx, CtxKey(\"C\"), \"c\")\n\n\t// print the final context\n\tprint(\"ctx\", ctx)\n\n\t// retreive and print the value\n\t// for the key \"A\"\n\ta := ctx.Value(CtxKey(\"A\"))\n\tfmt.Println(\"A:\", a)\n\n\t// retreive and print the value\n\t// for the key \"B\"\n\tb := ctx.Value(CtxKey(\"B\"))\n\tfmt.Println(\"B:\", b)\n\n\t// retreive and print the value\n\t// for the key \"C\"\n\tc := ctx.Value(CtxKey(\"C\"))\n\tfmt.Println(\"C:\", c)\n\n}", + "file": "values/src/resolution/main.go", + "lang": "go", + "name": "example", + "start": 15, + "end": 53 + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" src=\"values/src/resolution/main.go#example\"\u003e", + "type": "hype.SourceCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "values.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "From the output we see that the final ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "values.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "values.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": " has a parentage that includes all of the values added with ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#WithValue", + "href": "https://pkg.go.dev/context#WithValue", + "target": "_blank" + }, + "filename": "values.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "values.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.WithValue", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#WithValue\" href=\"https://pkg.go.dev/context#WithValue\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#WithValue" + } + ], + { + "text": ". We can also see that we are able to find all of the keys, including the very first one that we set.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "args": [ + "go", + "run", + "main.go" + ], + "atom": "cmd", + "attributes": { + "data-go-version": "go1.22.0", + "exec": "go run main.go", + "run": "main.go", + "src": "values/src/resolution" + }, + "expected_exit": 0, + "filename": "values.md", + "html_node": { + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "run", + "main.go" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/12-context/values/src/resolution", + "duration": "3.115498625s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go run main.go\n\nctx.WithValue(key: C, value: c)\n\t--\u0026gt; WithValue(key: B, value: b)\n\t\t--\u0026gt; WithValue(key: A, value: a)\n\t\t\t--\u0026gt; context.backgroundCtx\n\nA: a\nB: b\nC: c", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "ctx.WithValue(key: C, value: c)\n\t--\u003e WithValue(key: B, value: b)\n\t\t--\u003e WithValue(key: A, value: a)\n\t\t\t--\u003e context.backgroundCtx\n\nA: a\nB: b\nC: c", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "run", + "main.go" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/12-context/values/src/resolution", + "duration": "3.115498625s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go run main.go\n\nctx.WithValue(key: C, value: c)\n\t--\u0026gt; WithValue(key: B, value: b)\n\t\t--\u0026gt; WithValue(key: A, value: a)\n\t\t\t--\u0026gt; context.backgroundCtx\n\nA: a\nB: b\nC: c", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "ctx.WithValue(key: C, value: c)\n\t--\u003e WithValue(key: B, value: b)\n\t\t--\u003e WithValue(key: A, value: a)\n\t\t\t--\u003e context.backgroundCtx\n\nA: a\nB: b\nC: c", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd data-go-version=\"go1.22.0\" exec=\"go run main.go\" run=\"main.go\" src=\"values/src/resolution\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "tag": "\u003cpage\u003e", + "title": "Context Values", + "type": "hype.Page" + } + ], + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "atom": "include", + "attributes": { + "src": "values/_strings.md" + }, + "dir": ".", + "filename": "values.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "_strings.md" + } + ], + "data": "include", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "page", + "attributes": {}, + "filename": "values/_strings.md", + "html_node": { + "data": "page", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "atom": "h1", + "attributes": {}, + "filename": "values/_strings.md", + "html_node": { + "data": "h1", + "data_atom": "h1", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "level": 1, + "nodes": [ + { + "text": "Problems with String Keys", + "type": "hype.Text" + } + ], + "tag": "\u003ch1\u003e", + "type": "hype.Heading" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "values/_strings.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "As is mentioned in the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context", + "href": "https://pkg.go.dev/context", + "target": "_blank" + }, + "filename": "values/_strings.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "values/_strings.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context\" href=\"https://pkg.go.dev/context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context" + } + ], + { + "text": " documentation using string keys is not recommended. As we just saw when ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context.Value", + "href": "https://pkg.go.dev/context#Context.Value", + "target": "_blank" + }, + "filename": "values/_strings.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "values/_strings.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context.Value", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context.Value\" href=\"https://pkg.go.dev/context#Context.Value\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context.Value" + } + ], + { + "text": " tries to resolve a key it finds the first, if any, ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "values/_strings.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "values/_strings.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": " that contains the key and returns that value.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-16", + "type": "listing" + }, + "filename": "values/_strings.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "context.doc" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "args": [ + "go", + "doc", + "context.WithValue" + ], + "atom": "cmd", + "attributes": { + "data-go-version": "go1.22.0", + "doc": "context.WithValue", + "exec": "go doc context.WithValue" + }, + "expected_exit": 0, + "filename": "values", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "data-go-version", + "Val": "go1.22.0" + }, + { + "Namespace": "", + "Key": "doc", + "Val": "context.WithValue" + }, + { + "Namespace": "", + "Key": "exec", + "Val": "go doc context.WithValue" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "doc", + "context.WithValue" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypejs", + "duration": "1.601791667s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go doc context.WithValue\n\npackage context // import \u0026#34;context\u0026#34;\n\nfunc WithValue(parent Context, key, val any) Context\n WithValue returns a copy of parent in which the value associated with key is\n val.\n\n Use context Values only for request-scoped data that transits processes and\n APIs, not for passing optional parameters to functions.\n\n The provided key must be comparable and should not be of type string or any\n other built-in type to avoid collisions between packages using context.\n Users of WithValue should define their own types for keys. To avoid\n allocating when assigning to an interface{}, context keys often have\n concrete type struct{}. Alternatively, exported context key variables\u0026#39;\n static type should be a pointer or interface.", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "package context // import \"context\"\n\nfunc WithValue(parent Context, key, val any) Context\n WithValue returns a copy of parent in which the value associated with key is\n val.\n\n Use context Values only for request-scoped data that transits processes and\n APIs, not for passing optional parameters to functions.\n\n The provided key must be comparable and should not be of type string or any\n other built-in type to avoid collisions between packages using context.\n Users of WithValue should define their own types for keys. To avoid\n allocating when assigning to an interface{}, context keys often have\n concrete type struct{}. Alternatively, exported context key variables'\n static type should be a pointer or interface.", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "doc", + "context.WithValue" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypejs", + "duration": "1.601791667s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go doc context.WithValue\n\npackage context // import \u0026#34;context\u0026#34;\n\nfunc WithValue(parent Context, key, val any) Context\n WithValue returns a copy of parent in which the value associated with key is\n val.\n\n Use context Values only for request-scoped data that transits processes and\n APIs, not for passing optional parameters to functions.\n\n The provided key must be comparable and should not be of type string or any\n other built-in type to avoid collisions between packages using context.\n Users of WithValue should define their own types for keys. To avoid\n allocating when assigning to an interface{}, context keys often have\n concrete type struct{}. Alternatively, exported context key variables\u0026#39;\n static type should be a pointer or interface.", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "package context // import \"context\"\n\nfunc WithValue(parent Context, key, val any) Context\n WithValue returns a copy of parent in which the value associated with key is\n val.\n\n Use context Values only for request-scoped data that transits processes and\n APIs, not for passing optional parameters to functions.\n\n The provided key must be comparable and should not be of type string or any\n other built-in type to avoid collisions between packages using context.\n Users of WithValue should define their own types for keys. To avoid\n allocating when assigning to an interface{}, context keys often have\n concrete type struct{}. Alternatively, exported context key variables'\n static type should be a pointer or interface.", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd data-go-version=\"go1.22.0\" doc=\"context.WithValue\" exec=\"go doc context.WithValue\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "values", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.16:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "Using strings as context keys is not recommended per the documentation.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 16, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-16\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "values/_strings.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "When we use the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context.Value", + "href": "https://pkg.go.dev/context#Context.Value", + "target": "_blank" + }, + "filename": "values/_strings.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "values/_strings.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context.Value", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context.Value\" href=\"https://pkg.go.dev/context#Context.Value\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context.Value" + } + ], + { + "text": " function, we get the last value that was set for the given key. Each time we use ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#WithValue", + "href": "https://pkg.go.dev/context#WithValue", + "target": "_blank" + }, + "filename": "values/_strings.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "values/_strings.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.WithValue", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#WithValue\" href=\"https://pkg.go.dev/context#WithValue\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#WithValue" + } + ], + { + "text": " to wrap a ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "values/_strings.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "values/_strings.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": " with a new ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "values/_strings.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "values/_strings.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": ", the new ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "values/_strings.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "values/_strings.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": " will have, essentially, replaced the previous value for the given key.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "img", + "attributes": { + "alt": "string-keys", + "src": "values/assets/string-keys.svg" + }, + "filename": "values/_strings.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "assets/string-keys.svg" + }, + { + "Namespace": "", + "Key": "alt", + "Val": "string-keys" + } + ], + "data": "img", + "data_atom": "img", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [], + "tag": "\u003cimg alt=\"string-keys\" src=\"values/assets/string-keys.svg\"\u003e", + "type": "hype.Image" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "h2", + "attributes": {}, + "filename": "values/_strings.md", + "html_node": { + "data": "h2", + "data_atom": "h2", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "level": 2, + "nodes": [ + { + "text": "Key Collisions", + "type": "hype.Text" + } + ], + "tag": "\u003ch2\u003e", + "type": "hype.Heading" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "values/_strings.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Consider the following example. We wrap a ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "values/_strings.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "values/_strings.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": " multiple times, each time with a different value, but the same key, ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "values/_strings.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "request_id", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": ", which is of type ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "values/_strings.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "string", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": ".", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "pre", + "attributes": {}, + "filename": "values/_strings.md", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "src": "values/src/string-keys/main.go#example" + }, + "filename": "_strings.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/string-keys/main.go#example" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "content": "func main() {\n\t// create a new background context\n\tctx := context.Background()\n\n\t// call the A function\n\t// passing in the background context\n\tA(ctx)\n}\n\nfunc A(ctx context.Context) {\n\t// wrap the context with a request_id\n\t// to represent this specific A request\n\tctx = context.WithValue(ctx, \"request_id\", \"123\")\n\n\t// call the B function\n\t// passing in the wrapped context\n\tB(ctx)\n}\n\nfunc B(ctx context.Context) {\n\t// wrap the context with a request_id\n\t// to represent this specific B request\n\tctx = context.WithValue(ctx, \"request_id\", \"456\")\n\tLogger(ctx)\n}\n\n// Logger logs the webs request_id\n// as well as the request_id from the B\nfunc Logger(ctx context.Context) {\n\ta := ctx.Value(\"request_id\")\n\tfmt.Println(\"A\\t\", \"request_id:\", a)\n\n\tb := ctx.Value(\"request_id\")\n\tfmt.Println(\"B\\t\", \"request_id:\", b)\n}", + "file": "values/src/string-keys/main.go", + "lang": "go", + "name": "example", + "start": 8, + "end": 45 + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" src=\"values/src/string-keys/main.go#example\"\u003e", + "type": "hype.SourceCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "values/_strings.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "When we try to log both the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "values/_strings.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "request_id", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " for both ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "values/_strings.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "A", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " and ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "values/_strings.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "A", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " we see that they are both set to the same value.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "args": [ + "go", + "run", + "main.go" + ], + "atom": "cmd", + "attributes": { + "data-go-version": "go1.22.0", + "exec": "go run main.go", + "run": "main.go", + "src": "values/src/string-keys" + }, + "expected_exit": 0, + "filename": "values/_strings.md", + "html_node": { + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "run", + "main.go" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/12-context/values/src/string-keys", + "duration": "1.898965875s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go run main.go\n\nA\t request_id: 456\nB\t request_id: 456", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "A\t request_id: 456\nB\t request_id: 456", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "run", + "main.go" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/12-context/values/src/string-keys", + "duration": "1.898965875s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go run main.go\n\nA\t request_id: 456\nB\t request_id: 456", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "A\t request_id: 456\nB\t request_id: 456", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd data-go-version=\"go1.22.0\" exec=\"go run main.go\" run=\"main.go\" src=\"values/src/string-keys\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "values/_strings.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "One way to solve this problem would be try and \"namespace\" your ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "values/_strings.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "string", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " keys, ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "values/_strings.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "myapp.request_id", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": ". While you may never get into a collision scenario, the possibility of someone else using the same key is there.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "h2", + "attributes": {}, + "filename": "values/_strings.md", + "html_node": { + "data": "h2", + "data_atom": "h2", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "level": 2, + "nodes": [ + { + "text": "Custom String Key Types", + "type": "hype.Text" + } + ], + "tag": "\u003ch2\u003e", + "type": "hype.Heading" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "values/_strings.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Because Go is a typed language, we can leverage the type system to solve the problem of key collisions. We can create a new type based on ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "values/_strings.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "string", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " that we can use as the key.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "pre", + "attributes": {}, + "filename": "values/_strings.md", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "src": "values/src/custom-keys/main.go#types" + }, + "filename": "_strings.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/custom-keys/main.go#types" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "content": "// CtxKeyA is used to wrap keys\n// associated with a A request\n// \tCtxKeyA(\"request_id\")\n// \tCtxKeyA(\"user_id\")\ntype CtxKeyA string\n\n// CtxKeyB is used to wrap keys\n// associated with a B request\n// \tCtxKeyB(\"request_id\")\n// \tCtxKeyB(\"user_id\")\ntype CtxKeyB string", + "file": "values/src/custom-keys/main.go", + "lang": "go", + "name": "types", + "start": 8, + "end": 21 + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" src=\"values/src/custom-keys/main.go#types\"\u003e", + "type": "hype.SourceCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "pre", + "attributes": {}, + "filename": "values/_strings.md", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "src": "values/src/custom-keys/main.go#example" + }, + "filename": "_strings.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/custom-keys/main.go#example" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "content": "func A(ctx context.Context) {\n\t// wrap the context with a request_id\n\t// to represent this specific A request\n\tkey := CtxKeyA(\"request_id\")\n\tctx = context.WithValue(ctx, key, \"123\")\n\n\t// call B with the wrapped context\n\tB(ctx)\n}\n\nfunc B(ctx context.Context) {\n\t// wrap the context with a request_id\n\t// to represent this specific B request\n\tkey := CtxKeyB(\"request_id\")\n\tctx = context.WithValue(ctx, key, \"456\")\n\n\tLogger(ctx)\n}", + "file": "values/src/custom-keys/main.go", + "lang": "go", + "name": "example", + "start": 31, + "end": 51 + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" src=\"values/src/custom-keys/main.go#example\"\u003e", + "type": "hype.SourceCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "pre", + "attributes": {}, + "filename": "values/_strings.md", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "src": "values/src/custom-keys/main.go#logger" + }, + "filename": "_strings.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/custom-keys/main.go#logger" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "content": "// Logger logs the webs request_id\n// as well as the request_id from the B\nfunc Logger(ctx context.Context) {\n\t// retreive the request_id from the A request\n\taKey := CtxKeyA(\"request_id\")\n\taVal := ctx.Value(aKey)\n\n\t// print the request_id from the A request\n\tprint(\"A\", aKey, aVal)\n\n\t// retreive the request_id from the B request\n\tbKey := CtxKeyB(\"request_id\")\n\tbVal := ctx.Value(bKey)\n\n\t// print the request_id from the B request\n\tprint(\"B\", bKey, bVal)\n}", + "file": "values/src/custom-keys/main.go", + "lang": "go", + "name": "logger", + "start": 53, + "end": 72 + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" src=\"values/src/custom-keys/main.go#logger\"\u003e", + "type": "hype.SourceCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "values/_strings.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "The ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "values/_strings.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Logger", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " is now properly able to retrieve the two different ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "values/_strings.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "request_id", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " values because they are no longer of the same type.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "args": [ + "go", + "run", + "main.go" + ], + "atom": "cmd", + "attributes": { + "data-go-version": "go1.22.0", + "exec": "go run main.go", + "run": "main.go", + "src": "values/src/custom-keys" + }, + "expected_exit": 0, + "filename": "values/_strings.md", + "html_node": { + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "run", + "main.go" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/12-context/values/src/custom-keys", + "duration": "2.377087375s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go run main.go\n\nA: main.CtxKeyA(request_id): 123\nB: main.CtxKeyB(request_id): 456", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "A: main.CtxKeyA(request_id): 123\nB: main.CtxKeyB(request_id): 456", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "run", + "main.go" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/12-context/values/src/custom-keys", + "duration": "2.377087375s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go run main.go\n\nA: main.CtxKeyA(request_id): 123\nB: main.CtxKeyB(request_id): 456", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "A: main.CtxKeyA(request_id): 123\nB: main.CtxKeyB(request_id): 456", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd data-go-version=\"go1.22.0\" exec=\"go run main.go\" run=\"main.go\" src=\"values/src/custom-keys\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "values/_strings.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "This code can be further cleaned up by using constants for the keys that our package, or application, uses. This allows for cleaner code and makes it easier to document the potential keys that may be in a ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "values/_strings.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "values/_strings.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": ".", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "pre", + "attributes": {}, + "filename": "values/_strings.md", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "src": "values/src/custom-const/main.go#consts" + }, + "filename": "_strings.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/custom-const/main.go#consts" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "content": "const (\n\t// A_RequestID can be used to\n\t// retreive the request_id for\n\t// the A request\n\tA_RequestID CtxKeyA = \"request_id\"\n\t// \tA_SESSION_ID CtxKeyA = \"session_id\"\n\t// \tA_SERVER_ID CtxKeyA = \"server_id\"\n\t// \tother keys...\n\n\t// B_RequestID can be used to\n\t// retreive the request_id for\n\t// the B request\n\tB_RequestID CtxKeyB = \"request_id\"\n)", + "file": "values/src/custom-const/main.go", + "lang": "go", + "name": "consts", + "start": 23, + "end": 39 + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" src=\"values/src/custom-const/main.go#consts\"\u003e", + "type": "hype.SourceCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "pre", + "attributes": {}, + "filename": "values/_strings.md", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "src": "values/src/custom-const/main.go#logger" + }, + "filename": "_strings.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/custom-const/main.go#logger" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "content": "// Logger logs the webs request_id\n// as well as the request_id from the B\nfunc Logger(ctx context.Context) {\n\t// retreive the request_id from the A request\n\taKey := A_RequestID\n\taVal := ctx.Value(aKey)\n\n\t// print the request_id from the A request\n\tprint(\"A\", aKey, aVal)\n\n\t// retreive the request_id from the B request\n\tbKey := B_RequestID\n\tbVal := ctx.Value(bKey)\n\n\t// print the request_id from the B request\n\tprint(\"B\", bKey, bVal)\n}", + "file": "values/src/custom-const/main.go", + "lang": "go", + "name": "logger", + "start": 69, + "end": 88 + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" src=\"values/src/custom-const/main.go#logger\"\u003e", + "type": "hype.SourceCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "tag": "\u003cpage\u003e", + "title": "Problems with String Keys", + "type": "hype.Page" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "tag": "\u003cinclude src=\"values/_strings.md\"\u003e", + "type": "hype.Include" + } + ], + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "atom": "include", + "attributes": { + "src": "values/_securing.md" + }, + "dir": ".", + "filename": "values.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "_securing.md" + } + ], + "data": "include", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "page", + "attributes": {}, + "filename": "values/_securing.md", + "html_node": { + "data": "page", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "atom": "h1", + "attributes": {}, + "filename": "values/_securing.md", + "html_node": { + "data": "h1", + "data_atom": "h1", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "level": 1, + "nodes": [ + { + "text": "Securing Context Keys and Values", + "type": "hype.Text" + } + ], + "tag": "\u003ch1\u003e", + "type": "hype.Heading" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "values/_securing.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "If we export, make public, the types, and names, of the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "values/_securing.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "values/_securing.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": " keys our package or application uses, we run the risk of a malicious agent stealing, or modifying our values. For example, in a web request we might set a ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "values/_securing.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "request_id", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " at the beginning of the request, but a piece of middleware later in the chain might modify that value to something else.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "pre", + "attributes": {}, + "filename": "values/_securing.md", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "snippet": "types", + "src": "values/src/malicious/foo/foo.go" + }, + "filename": "_securing.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/malicious/foo/foo.go" + }, + { + "Namespace": "", + "Key": "snippet", + "Val": "types" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "content": "type CtxKey string\n\nconst (\n\tRequestID CtxKey = \"request_id\"\n)", + "file": "values/src/malicious/foo/foo.go", + "lang": "go", + "name": "types", + "start": 5, + "end": 12 + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" snippet=\"types\" src=\"values/src/malicious/foo/foo.go\"\u003e", + "type": "hype.SourceCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "pre", + "attributes": {}, + "filename": "values/_securing.md", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "snippet": "example", + "src": "values/src/malicious/bar/bar.go" + }, + "filename": "_securing.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/malicious/bar/bar.go" + }, + { + "Namespace": "", + "Key": "snippet", + "Val": "example" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "content": "func WithBar(ctx context.Context) context.Context {\n\t// wrap the context with a request_id\n\t// to represent this specific bar request\n\tctx = context.WithValue(ctx, RequestID, \"456\")\n\n\t// maliciously replace the request_id\n\t// set by foo\n\tctx = context.WithValue(ctx, foo.RequestID, \"???\")\n\n\t// return the wrapped context\n\treturn ctx\n}", + "file": "values/src/malicious/bar/bar.go", + "lang": "go", + "name": "example", + "start": 17, + "end": 31 + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" snippet=\"example\" src=\"values/src/malicious/bar/bar.go\"\u003e", + "type": "hype.SourceCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "values/_securing.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "pre", + "attributes": {}, + "filename": "values/_securing.md", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "snippet": "example", + "src": "values/src/malicious/main.go" + }, + "filename": "_securing.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/malicious/main.go" + }, + { + "Namespace": "", + "Key": "snippet", + "Val": "example" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "content": "func main() {\n\t// create a background context\n\tctx := context.Background()\n\n\t// wrap the context with foo\n\tctx = foo.WithFoo(ctx)\n\n\t// wrap the context with bar\n\tctx = bar.WithBar(ctx)\n\n\t// retrieve the foo.RequestID\n\t// value from the context\n\tid := ctx.Value(foo.RequestID)\n\n\t// print the value\n\tfmt.Println(\"foo.RequestID: \", id)\n}", + "file": "values/src/malicious/main.go", + "lang": "go", + "name": "example", + "start": 10, + "end": 29 + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" snippet=\"example\" src=\"values/src/malicious/main.go\"\u003e", + "type": "hype.SourceCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "atom": "pre", + "attributes": {}, + "filename": "values/_securing.md", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "snippet": "example", + "src": "values/src/malicious/foo/foo.go" + }, + "filename": "_securing.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/malicious/foo/foo.go" + }, + { + "Namespace": "", + "Key": "snippet", + "Val": "example" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "content": "func WithFoo(ctx context.Context) context.Context {\n\t// wrap the context with a request_id\n\t// to represent this specific foo request\n\tctx = context.WithValue(ctx, RequestID, \"123\")\n\n\t// return the wrapped context\n\treturn ctx\n}", + "file": "values/src/malicious/foo/foo.go", + "lang": "go", + "name": "example", + "start": 14, + "end": 24 + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" snippet=\"example\" src=\"values/src/malicious/foo/foo.go\"\u003e", + "type": "hype.SourceCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ] + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "args": [ + "go", + "run", + "main.go" + ], + "atom": "cmd", + "attributes": { + "data-go-version": "go1.22.0", + "exec": "go run main.go", + "run": "main.go", + "src": "values/src/malicious" + }, + "expected_exit": 0, + "filename": "values/_securing.md", + "html_node": { + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "run", + "main.go" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/12-context/values/src/malicious", + "duration": "4.797870125s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go run main.go\n\nfoo.RequestID: ???", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "foo.RequestID: ???", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "run", + "main.go" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/12-context/values/src/malicious", + "duration": "4.797870125s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go run main.go\n\nfoo.RequestID: ???", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "foo.RequestID: ???", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd data-go-version=\"go1.22.0\" exec=\"go run main.go\" run=\"main.go\" src=\"values/src/malicious\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "h2", + "attributes": {}, + "filename": "values/_securing.md", + "html_node": { + "data": "h2", + "data_atom": "h2", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "level": 2, + "nodes": [ + { + "text": "Securing by Not Exporting", + "type": "hype.Text" + } + ], + "tag": "\u003ch2\u003e", + "type": "hype.Heading" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "values/_securing.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "The best way to secure your that your key/value pairs aren't maliciously overwritten, or accessed, is by not exporting the types, and any constants, used for keys.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "pre", + "attributes": {}, + "filename": "values/_securing.md", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "snippet": "types", + "src": "values/src/secured/foo/foo.go" + }, + "filename": "_securing.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/secured/foo/foo.go" + }, + { + "Namespace": "", + "Key": "snippet", + "Val": "types" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "content": "type ctxKey string\n\nconst (\n\trequestID ctxKey = \"request_id\"\n)", + "file": "values/src/secured/foo/foo.go", + "lang": "go", + "name": "types", + "start": 8, + "end": 15 + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" snippet=\"types\" src=\"values/src/secured/foo/foo.go\"\u003e", + "type": "hype.SourceCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "values/_securing.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Now, you are in control of what values from the context you wish to make public. For example, we can add a helper function to allow others to get access to the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "values/_securing.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "request_id", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " value.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "values/_securing.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Because the return value from ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context.Value", + "href": "https://pkg.go.dev/context#Context.Value", + "target": "_blank" + }, + "filename": "values/_securing.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "values/_securing.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context.Value", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context.Value\" href=\"https://pkg.go.dev/context#Context.Value\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context.Value" + } + ], + { + "text": " is an empty interface, ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "values/_securing.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "interface{}", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": ", we can use these helper functions to, not just retrieve access to the value, but also type assert the value to the type we want, or return an error if it doesn't.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "pre", + "attributes": {}, + "filename": "values/_securing.md", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "snippet": "example", + "src": "values/src/secured/foo/foo.go" + }, + "filename": "_securing.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/secured/foo/foo.go" + }, + { + "Namespace": "", + "Key": "snippet", + "Val": "example" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "content": "func RequestIDFrom(ctx context.Context) (string, error) {\n\t// get the request_id from the context\n\ts, ok := ctx.Value(requestID).(string)\n\tif !ok {\n\t\treturn \"\", fmt.Errorf(\"request_id not found in context\")\n\t}\n\treturn s, nil\n}", + "file": "values/src/secured/foo/foo.go", + "lang": "go", + "name": "example", + "start": 26, + "end": 36 + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" snippet=\"example\" src=\"values/src/secured/foo/foo.go\"\u003e", + "type": "hype.SourceCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "values/_securing.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Our application can be updated to use the new helper function to print the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "values/_securing.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "request_id", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " or exit if there was a problem getting the value.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "pre", + "attributes": {}, + "filename": "values/_securing.md", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "snippet": "example", + "src": "values/src/secured/main.go" + }, + "filename": "_securing.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/secured/main.go" + }, + { + "Namespace": "", + "Key": "snippet", + "Val": "example" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "content": "func main() {\n\t// create a background context\n\tctx := context.Background()\n\n\t// wrap the context with foo\n\tctx = foo.WithFoo(ctx)\n\n\t// wrap the context with bar\n\tctx = bar.WithBar(ctx)\n\n\t// retrieve the foo.RequestID\n\t// value from the context\n\tid, err := foo.RequestIDFrom(ctx)\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\n\t// print the value\n\tfmt.Println(\"foo.RequestID: \", id)\n}", + "file": "values/src/secured/main.go", + "lang": "go", + "name": "example", + "start": 11, + "end": 33 + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" snippet=\"example\" src=\"values/src/secured/main.go\"\u003e", + "type": "hype.SourceCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "values/_securing.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "The malicious ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "values/_securing.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "bar", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " package can no longer set, or retrieve, the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "values/_securing.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "request_id", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " value set by the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "values/_securing.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "foo", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " package. The ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "values/_securing.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "bar", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " package does not have the ability to create a new type of value ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "values/_securing.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "foo.ctxKey", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " because the type is un-exported can be accessed outside of the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "values/_securing.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "foo", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " package.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "pre", + "attributes": {}, + "filename": "values/_securing.md", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "snippet": "example", + "src": "values/src/secured/bar/bar.go" + }, + "filename": "_securing.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/secured/bar/bar.go" + }, + { + "Namespace": "", + "Key": "snippet", + "Val": "example" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "content": "func WithBar(ctx context.Context) context.Context {\n\t// wrap the context with a request_id\n\t// to represent this specific bar request\n\tctx = context.WithValue(ctx, requestID, \"456\")\n\n\t// no longer able to set the foo request id\n\t// it does not have access to the foo.ctxKey type\n\t// as it is not exported, so bar can not create\n\t// a new key of that type.\n\t// ctx = context.WithValue(ctx, foo.ctxKey(\"request_id\"), \"???\")\n\n\t// return the wrapped context\n\treturn ctx\n}", + "file": "values/src/secured/bar/bar.go", + "lang": "go", + "name": "example", + "start": 16, + "end": 32 + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" snippet=\"example\" src=\"values/src/secured/bar/bar.go\"\u003e", + "type": "hype.SourceCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "values/_securing.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "As a result of securing our ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "values/_securing.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "values/_securing.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": " values, the application now correctly retrieves the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "values/_securing.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "request_id", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " value set by the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "values/_securing.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "foo", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " package.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "args": [ + "go", + "run", + "main.go" + ], + "atom": "cmd", + "attributes": { + "data-go-version": "go1.22.0", + "exec": "go run main.go", + "run": "main.go", + "src": "values/src/secured" + }, + "expected_exit": 0, + "filename": "values/_securing.md", + "html_node": { + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "run", + "main.go" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/12-context/values/src/secured", + "duration": "3.755957s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go run main.go\n\nfoo.RequestID: 123", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "foo.RequestID: 123", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "run", + "main.go" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/12-context/values/src/secured", + "duration": "3.755957s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go run main.go\n\nfoo.RequestID: 123", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "foo.RequestID: 123", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd data-go-version=\"go1.22.0\" exec=\"go run main.go\" run=\"main.go\" src=\"values/src/secured\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "tag": "\u003cpage\u003e", + "title": "Securing Context Keys and Values", + "type": "hype.Page" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "tag": "\u003cinclude src=\"values/_securing.md\"\u003e", + "type": "hype.Include" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "tag": "\u003cinclude src=\"values/values.md\"\u003e", + "type": "hype.Include" + } + ], + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "atom": "include", + "attributes": { + "src": "cancellation/cancellation.md" + }, + "dir": "cancellation", + "filename": "module.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "cancellation/cancellation.md" + } + ], + "data": "include", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "page", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "page", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "atom": "h1", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "h1", + "data_atom": "h1", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "level": 1, + "nodes": [ + { + "text": "Cancellation Propagation with Contexts", + "type": "hype.Text" + } + ], + "tag": "\u003ch1\u003e", + "type": "hype.Heading" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "While having the ability to pass contextual information via the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "cancellation.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": " is useful, the real benefit, and design of the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context", + "href": "https://pkg.go.dev/context", + "target": "_blank" + }, + "filename": "cancellation.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context\" href=\"https://pkg.go.dev/context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context" + } + ], + { + "text": " package, is that it can be used to propagate cancellation events to those listening to the context. When a parent ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "cancellation.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": " is canceled, all its children are also canceled.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "h2", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "h2", + "data_atom": "h2", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "level": 2, + "nodes": [ + { + "text": "Creating a Cancellable Context", + "type": "hype.Text" + } + ], + "tag": "\u003ch2\u003e", + "type": "hype.Heading" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "In order to cancel a ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "cancellation.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": ", we must have a way of cancelling it. The ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#WithCancel", + "href": "https://pkg.go.dev/context#WithCancel", + "target": "_blank" + }, + "filename": "cancellation.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.WithCancel", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#WithCancel\" href=\"https://pkg.go.dev/context#WithCancel\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#WithCancel" + } + ], + { + "text": " function, ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-17" + }, + "filename": "cancellation.md", + "html_node": { + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-17" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.17", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-17\"\u003e", + "type": "hype.Link", + "url": "#listing-1-17" + } + ], + "tag": "\u003cref id=\"listing-1-17\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ", wraps a given ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "cancellation.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": " with a ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "cancellation.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": " that can be cancelled.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-17", + "type": "listing" + }, + "filename": "cancellation.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "withcancel.doc" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "args": [ + "go", + "doc", + "context.WithCancel" + ], + "atom": "cmd", + "attributes": { + "data-go-version": "go1.22.0", + "doc": "context.WithCancel", + "exec": "go doc context.WithCancel" + }, + "expected_exit": 0, + "filename": "cancellation", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "data-go-version", + "Val": "go1.22.0" + }, + { + "Namespace": "", + "Key": "doc", + "Val": "context.WithCancel" + }, + { + "Namespace": "", + "Key": "exec", + "Val": "go doc context.WithCancel" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "doc", + "context.WithCancel" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypejs", + "duration": "1.5545045s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go doc context.WithCancel\n\npackage context // import \u0026#34;context\u0026#34;\n\nfunc WithCancel(parent Context) (ctx Context, cancel CancelFunc)\n WithCancel returns a copy of parent with a new Done channel. The returned\n context\u0026#39;s Done channel is closed when the returned cancel function is called\n or when the parent context\u0026#39;s Done channel is closed, whichever happens\n first.\n\n Canceling this context releases resources associated with it, so code should\n call cancel as soon as the operations running in this Context complete.", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "package context // import \"context\"\n\nfunc WithCancel(parent Context) (ctx Context, cancel CancelFunc)\n WithCancel returns a copy of parent with a new Done channel. The returned\n context's Done channel is closed when the returned cancel function is called\n or when the parent context's Done channel is closed, whichever happens\n first.\n\n Canceling this context releases resources associated with it, so code should\n call cancel as soon as the operations running in this Context complete.", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "doc", + "context.WithCancel" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypejs", + "duration": "1.5545045s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go doc context.WithCancel\n\npackage context // import \u0026#34;context\u0026#34;\n\nfunc WithCancel(parent Context) (ctx Context, cancel CancelFunc)\n WithCancel returns a copy of parent with a new Done channel. The returned\n context\u0026#39;s Done channel is closed when the returned cancel function is called\n or when the parent context\u0026#39;s Done channel is closed, whichever happens\n first.\n\n Canceling this context releases resources associated with it, so code should\n call cancel as soon as the operations running in this Context complete.", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "package context // import \"context\"\n\nfunc WithCancel(parent Context) (ctx Context, cancel CancelFunc)\n WithCancel returns a copy of parent with a new Done channel. The returned\n context's Done channel is closed when the returned cancel function is called\n or when the parent context's Done channel is closed, whichever happens\n first.\n\n Canceling this context releases resources associated with it, so code should\n call cancel as soon as the operations running in this Context complete.", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd data-go-version=\"go1.22.0\" doc=\"context.WithCancel\" exec=\"go doc context.WithCancel\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "cancellation", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.17:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "The ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#WithCancel", + "href": "https://pkg.go.dev/context#WithCancel", + "target": "_blank" + }, + "filename": "cancellation", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "for", + "Val": "context#WithCancel" + }, + { + "Namespace": "", + "Key": "href", + "Val": "https://pkg.go.dev/context#WithCancel" + }, + { + "Namespace": "", + "Key": "target", + "Val": "_blank" + } + ], + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": {}, + "filename": "cancellation", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.WithCancel", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ] + ], + "tag": "\u003ca for=\"context#WithCancel\" href=\"https://pkg.go.dev/context#WithCancel\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#WithCancel" + } + ], + { + "text": " function.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 17, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-17\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "The ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#WithCancel", + "href": "https://pkg.go.dev/context#WithCancel", + "target": "_blank" + }, + "filename": "cancellation.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.WithCancel", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#WithCancel\" href=\"https://pkg.go.dev/context#WithCancel\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#WithCancel" + } + ], + { + "text": " function returns a second argument, that of a ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#CancelFunc", + "href": "https://pkg.go.dev/context#CancelFunc", + "target": "_blank" + }, + "filename": "cancellation.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.CancelFunc", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#CancelFunc\" href=\"https://pkg.go.dev/context#CancelFunc\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#CancelFunc" + } + ], + { + "text": " function, which can be used to cancel the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "cancellation.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": ".", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "h3", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "h3", + "data_atom": "h3", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "level": 3, + "nodes": [ + { + "text": "The Cancel Function", + "type": "hype.Text" + } + ], + "tag": "\u003ch3\u003e", + "type": "hype.Heading" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "There a few things that need to be noted about the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#CancelFunc", + "href": "https://pkg.go.dev/context#CancelFunc", + "target": "_blank" + }, + "filename": "cancellation.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.CancelFunc", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#CancelFunc\" href=\"https://pkg.go.dev/context#CancelFunc\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#CancelFunc" + } + ], + { + "text": " function, ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-18" + }, + "filename": "cancellation.md", + "html_node": { + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-18" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.18", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-18\"\u003e", + "type": "hype.Link", + "url": "#listing-1-18" + } + ], + "tag": "\u003cref id=\"listing-1-18\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ". So let's examine each in more detail.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-18", + "type": "listing" + }, + "filename": "cancellation.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "cancelfunc.doc" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "args": [ + "go", + "doc", + "context.CancelFunc" + ], + "atom": "cmd", + "attributes": { + "data-go-version": "go1.22.0", + "doc": "context.CancelFunc", + "exec": "go doc context.CancelFunc" + }, + "expected_exit": 0, + "filename": "cancellation", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "data-go-version", + "Val": "go1.22.0" + }, + { + "Namespace": "", + "Key": "doc", + "Val": "context.CancelFunc" + }, + { + "Namespace": "", + "Key": "exec", + "Val": "go doc context.CancelFunc" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "doc", + "context.CancelFunc" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypejs", + "duration": "1.784131375s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go doc context.CancelFunc\n\npackage context // import \u0026#34;context\u0026#34;\n\ntype CancelFunc func()\n A CancelFunc tells an operation to abandon its work. A CancelFunc does not\n wait for the work to stop. A CancelFunc may be called by multiple goroutines\n simultaneously. After the first call, subsequent calls to a CancelFunc do\n nothing.", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "package context // import \"context\"\n\ntype CancelFunc func()\n A CancelFunc tells an operation to abandon its work. A CancelFunc does not\n wait for the work to stop. A CancelFunc may be called by multiple goroutines\n simultaneously. After the first call, subsequent calls to a CancelFunc do\n nothing.", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "doc", + "context.CancelFunc" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypejs", + "duration": "1.784131375s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go doc context.CancelFunc\n\npackage context // import \u0026#34;context\u0026#34;\n\ntype CancelFunc func()\n A CancelFunc tells an operation to abandon its work. A CancelFunc does not\n wait for the work to stop. A CancelFunc may be called by multiple goroutines\n simultaneously. After the first call, subsequent calls to a CancelFunc do\n nothing.", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "package context // import \"context\"\n\ntype CancelFunc func()\n A CancelFunc tells an operation to abandon its work. A CancelFunc does not\n wait for the work to stop. A CancelFunc may be called by multiple goroutines\n simultaneously. After the first call, subsequent calls to a CancelFunc do\n nothing.", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd data-go-version=\"go1.22.0\" doc=\"context.CancelFunc\" exec=\"go doc context.CancelFunc\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "cancellation", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.18:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "The ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#CancelFunc", + "href": "https://pkg.go.dev/context#CancelFunc", + "target": "_blank" + }, + "filename": "cancellation", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "for", + "Val": "context#CancelFunc" + }, + { + "Namespace": "", + "Key": "href", + "Val": "https://pkg.go.dev/context#CancelFunc" + }, + { + "Namespace": "", + "Key": "target", + "Val": "_blank" + } + ], + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": {}, + "filename": "cancellation", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.CancelFunc", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ] + ], + "tag": "\u003ca for=\"context#CancelFunc\" href=\"https://pkg.go.dev/context#CancelFunc\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#CancelFunc" + } + ], + { + "text": " function.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 18, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-18\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "h4", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "h4", + "data_atom": "h4", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "level": 4, + "nodes": [ + { + "text": "Idempotent Behavior", + "type": "hype.Text" + } + ], + "tag": "\u003ch4\u003e", + "type": "hype.Heading" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + { + "atom": "blockquote", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "blockquote", + "data_atom": "blockquote", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\"After the first call, subsequent calls to a CancelFunc do nothing\".", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "tag": "\u003cblockquote\u003e", + "type": "hype.Element" + }, + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "According to the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#CancelFunc", + "href": "https://pkg.go.dev/context#CancelFunc", + "target": "_blank" + }, + "filename": "cancellation.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.CancelFunc", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#CancelFunc\" href=\"https://pkg.go.dev/context#CancelFunc\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#CancelFunc" + } + ], + { + "text": " documentation, the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#CancelFunc", + "href": "https://pkg.go.dev/context#CancelFunc", + "target": "_blank" + }, + "filename": "cancellation.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.CancelFunc", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#CancelFunc\" href=\"https://pkg.go.dev/context#CancelFunc\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#CancelFunc" + } + ], + { + "text": " function is ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "href": "https://en.wikipedia.org/wiki/Idempotence", + "target": "_blank" + }, + "filename": "cancellation.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "href", + "Val": "https://en.wikipedia.org/wiki/Idempotence" + } + ], + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "idempotent", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"https://en.wikipedia.org/wiki/Idempotence\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://en.wikipedia.org/wiki/Idempotence" + } + ], + { + "text": ", ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-19" + }, + "filename": "cancellation.md", + "html_node": { + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-19" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.19", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-19\"\u003e", + "type": "hype.Link", + "url": "#listing-1-19" + } + ], + "tag": "\u003cref id=\"listing-1-19\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ". That is, calling it multiple times has no effect beyond the first call.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-19", + "type": "listing" + }, + "filename": "cancellation.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "idempotent" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + { + "atom": "pre", + "attributes": {}, + "filename": "cancellation", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go" + }, + "filename": "cancellation", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "class", + "Val": "language-go" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "text": "ctx, cancel := context.WithCancel(context.Background())\ncancel() // cancels the context\ncancel() // has no effect\ncancel() // has no effect\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\"\u003e", + "type": "hype.FencedCode" + } + ] + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + }, + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "cancellation", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.19:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "The idempotent behavior of the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#CancelFunc", + "href": "https://pkg.go.dev/context#CancelFunc", + "target": "_blank" + }, + "filename": "cancellation", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "for", + "Val": "context#CancelFunc" + }, + { + "Namespace": "", + "Key": "href", + "Val": "https://pkg.go.dev/context#CancelFunc" + }, + { + "Namespace": "", + "Key": "target", + "Val": "_blank" + } + ], + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": {}, + "filename": "cancellation", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.CancelFunc", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ] + ], + "tag": "\u003ca for=\"context#CancelFunc\" href=\"https://pkg.go.dev/context#CancelFunc\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#CancelFunc" + } + ], + { + "text": " function.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 19, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-19\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "h4", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "h4", + "data_atom": "h4", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "level": 4, + "nodes": [ + { + "text": "Leaking Resources", + "type": "hype.Text" + } + ], + "tag": "\u003ch4\u003e", + "type": "hype.Heading" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + { + "atom": "blockquote", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "blockquote", + "data_atom": "blockquote", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\"Canceling this context releases resources associated with it, so code should call cancel as soon as the operations running in this Context complete.\"", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "tag": "\u003cblockquote\u003e", + "type": "hype.Element" + }, + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Often you will want to defer execution of the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#CancelFunc", + "href": "https://pkg.go.dev/context#CancelFunc", + "target": "_blank" + }, + "filename": "cancellation.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.CancelFunc", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#CancelFunc\" href=\"https://pkg.go.dev/context#CancelFunc\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#CancelFunc" + } + ], + { + "text": " function until the function, or application, exits. This ensure proper shutdown of the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "cancellation.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": " and prevents the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "cancellation.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": " from leaking resources.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-20", + "type": "listing" + }, + "filename": "cancellation.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "leaking" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + { + "atom": "pre", + "attributes": {}, + "filename": "cancellation", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go" + }, + "filename": "cancellation", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "class", + "Val": "language-go" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "text": "ctx, cancel := context.WithCancel(context.Background())\n// ensure the cancel function is called at least once\n// to avoid leaking resources\ndefer cancel()\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\"\u003e", + "type": "hype.FencedCode" + } + ] + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + }, + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "cancellation", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.20:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "Prevent leaking goroutines by calling the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#CancelFunc", + "href": "https://pkg.go.dev/context#CancelFunc", + "target": "_blank" + }, + "filename": "cancellation", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "for", + "Val": "context#CancelFunc" + }, + { + "Namespace": "", + "Key": "href", + "Val": "https://pkg.go.dev/context#CancelFunc" + }, + { + "Namespace": "", + "Key": "target", + "Val": "_blank" + } + ], + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": {}, + "filename": "cancellation", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.CancelFunc", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ] + ], + "tag": "\u003ca for=\"context#CancelFunc\" href=\"https://pkg.go.dev/context#CancelFunc\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#CancelFunc" + } + ] + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 20, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-20\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + { + "atom": "blockquote", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "blockquote", + "data_atom": "blockquote", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "strong", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "strong", + "data_atom": "strong", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "ALWAYS", + "type": "hype.Text" + } + ], + "tag": "\u003cstrong\u003e", + "type": "hype.Element" + }, + { + "text": " call the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#CancelFunc", + "href": "https://pkg.go.dev/context#CancelFunc", + "target": "_blank" + }, + "filename": "cancellation.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.CancelFunc", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#CancelFunc\" href=\"https://pkg.go.dev/context#CancelFunc\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#CancelFunc" + } + ], + { + "text": " function when you no longer need the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "cancellation.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": ". Failure to do so may cause your program to leak resources.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "tag": "\u003cblockquote\u003e", + "type": "hype.Element" + }, + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "h2", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "h2", + "data_atom": "h2", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "level": 2, + "nodes": [ + { + "text": "Cancelling a Context", + "type": "hype.Text" + } + ], + "tag": "\u003ch2\u003e", + "type": "hype.Heading" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Consider ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-21" + }, + "filename": "cancellation.md", + "html_node": { + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-21" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.21", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-21\"\u003e", + "type": "hype.Link", + "url": "#listing-1-21" + } + ], + "tag": "\u003cref id=\"listing-1-21\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ". The ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "listener", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " function takes a ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "cancellation.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": " as its first argument and an ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "int", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " representing the goroutine id as its second argument.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "The ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "listener", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " function will block until the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "cancellation.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": " is cancelled, which close the channel behind ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context.Done", + "href": "https://pkg.go.dev/context#Context.Done", + "target": "_blank" + }, + "filename": "cancellation.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context.Done", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context.Done\" href=\"https://pkg.go.dev/context#Context.Done\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context.Done" + } + ], + { + "text": " method. This will unblock the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "listener", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " function and allow it to exit.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-21", + "type": "listing" + }, + "filename": "cancellation.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "basic.listener" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + { + "atom": "pre", + "attributes": {}, + "filename": "cancellation", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "src": "cancellation/src/basic/main.go#listener" + }, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/basic/main.go#listener" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "content": "func listener(ctx context.Context, i int) {\n\tfmt.Printf(\"listener %d is waiting\\n\", i)\n\n\t// this will block until the context\n\t// given context is canceled\n\t\u003c-ctx.Done()\n\n\tfmt.Printf(\"listener %d is exiting\\n\", i)\n}", + "file": "cancellation/src/basic/main.go", + "lang": "go", + "name": "listener", + "start": 9, + "end": 20 + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" src=\"cancellation/src/basic/main.go#listener\"\u003e", + "type": "hype.SourceCode" + } + ] + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + }, + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "cancellation", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.21:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "Blocking on ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context.Done", + "href": "https://pkg.go.dev/context#Context.Done", + "target": "_blank" + }, + "filename": "cancellation", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "for", + "Val": "context#Context.Done" + }, + { + "Namespace": "", + "Key": "href", + "Val": "https://pkg.go.dev/context#Context.Done" + }, + { + "Namespace": "", + "Key": "target", + "Val": "_blank" + } + ], + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": {}, + "filename": "cancellation", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context.Done", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ] + ], + "tag": "\u003ca for=\"context#Context.Done\" href=\"https://pkg.go.dev/context#Context.Done\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context.Done" + } + ], + { + "text": ".", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 21, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-21\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "wThe application creates a ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Background", + "href": "https://pkg.go.dev/context#Background", + "target": "_blank" + }, + "filename": "cancellation.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Background", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Background\" href=\"https://pkg.go.dev/context#Background\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Background" + } + ], + { + "text": " context and then wraps it with a cancellable ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "cancellation.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": ". The ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#CancelFunc", + "href": "https://pkg.go.dev/context#CancelFunc", + "target": "_blank" + }, + "filename": "cancellation.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.CancelFunc", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#CancelFunc\" href=\"https://pkg.go.dev/context#CancelFunc\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#CancelFunc" + } + ], + { + "text": " returned by is immediately deferred to ensure the application doesn't leak any resources.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "In ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-22" + }, + "filename": "cancellation.md", + "html_node": { + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-22" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.22", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-22\"\u003e", + "type": "hype.Link", + "url": "#listing-1-22" + } + ], + "tag": "\u003cref id=\"listing-1-22\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": " we create several goroutines that will listen for the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "cancellation.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": " to be cancelled.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-22", + "type": "listing" + }, + "filename": "cancellation.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "basic.main" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + { + "atom": "pre", + "attributes": {}, + "filename": "cancellation", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "src": "cancellation/src/basic/main.go#main" + }, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/basic/main.go#main" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "content": "func main() {\n\n\t// create a background context\n\tctx := context.Background()\n\n\t// wrap the context with the ability\n\t// to cancel it\n\tctx, cancel := context.WithCancel(ctx)\n\n\t// defer cancellation of the context\n\t// to ensure that any resources are\n\t// cleaned up regardless of how the\n\t// function exits\n\tdefer cancel()\n\n\t// create 5 listeners\n\tfor i := 0; i \u003c 5; i++ {\n\n\t\t// launch listener in a goroutine\n\t\tgo listener(ctx, i)\n\n\t}\n\n\t// allow the listeners to start\n\ttime.Sleep(time.Millisecond * 500)\n\n\tfmt.Println(\"canceling the context\")\n\n\t// cancel the context and tell the\n\t// listeners to exit\n\tcancel()\n\n\t// allow the listeners to exit\n\ttime.Sleep(time.Millisecond * 500)\n}", + "file": "cancellation/src/basic/main.go", + "lang": "go", + "name": "main", + "start": 22, + "end": 59 + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" src=\"cancellation/src/basic/main.go#main\"\u003e", + "type": "hype.SourceCode" + } + ] + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + }, + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "cancellation", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.22:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "Using context cancellation.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 22, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-22\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "As we can see from the output, ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-23" + }, + "filename": "cancellation.md", + "html_node": { + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-23" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.23", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-23\"\u003e", + "type": "hype.Link", + "url": "#listing-1-23" + } + ], + "tag": "\u003cref id=\"listing-1-23\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ", the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "listener", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " function unblocks and exits when the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#CancelFunc", + "href": "https://pkg.go.dev/context#CancelFunc", + "target": "_blank" + }, + "filename": "cancellation.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.CancelFunc", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#CancelFunc\" href=\"https://pkg.go.dev/context#CancelFunc\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#CancelFunc" + } + ], + { + "text": " is called, ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "cancel()", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": ".", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-23", + "type": "listing" + }, + "filename": "cancellation.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "basic.out" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "args": [ + "go", + "run", + "main.go" + ], + "atom": "cmd", + "attributes": { + "data-go-version": "go1.22.0", + "exec": "go run main.go", + "run": "main.go", + "src": "cancellation/src/basic" + }, + "expected_exit": 0, + "filename": "cancellation", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "data-go-version", + "Val": "go1.22.0" + }, + { + "Namespace": "", + "Key": "exec", + "Val": "go run main.go" + }, + { + "Namespace": "", + "Key": "run", + "Val": "main.go" + }, + { + "Namespace": "", + "Key": "src", + "Val": "./src/basic" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "run", + "main.go" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/12-context/cancellation/src/basic", + "duration": "2.533940458s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go run main.go\n\nlistener 4 is waiting\nlistener 0 is waiting\nlistener 1 is waiting\nlistener 2 is waiting\nlistener 3 is waiting\ncanceling the context\nlistener 4 is exiting\nlistener 3 is exiting\nlistener 2 is exiting\nlistener 1 is exiting\nlistener 0 is exiting", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "listener 4 is waiting\nlistener 0 is waiting\nlistener 1 is waiting\nlistener 2 is waiting\nlistener 3 is waiting\ncanceling the context\nlistener 4 is exiting\nlistener 3 is exiting\nlistener 2 is exiting\nlistener 1 is exiting\nlistener 0 is exiting", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "run", + "main.go" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/12-context/cancellation/src/basic", + "duration": "2.533940458s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go run main.go\n\nlistener 4 is waiting\nlistener 0 is waiting\nlistener 1 is waiting\nlistener 2 is waiting\nlistener 3 is waiting\ncanceling the context\nlistener 4 is exiting\nlistener 3 is exiting\nlistener 2 is exiting\nlistener 1 is exiting\nlistener 0 is exiting", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "listener 4 is waiting\nlistener 0 is waiting\nlistener 1 is waiting\nlistener 2 is waiting\nlistener 3 is waiting\ncanceling the context\nlistener 4 is exiting\nlistener 3 is exiting\nlistener 2 is exiting\nlistener 1 is exiting\nlistener 0 is exiting", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd data-go-version=\"go1.22.0\" exec=\"go run main.go\" run=\"main.go\" src=\"cancellation/src/basic\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "cancellation", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.23:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "The output of the application.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 23, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-23\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "h3", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "h3", + "data_atom": "h3", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "level": 3, + "nodes": [ + { + "text": "Only Child Nodes of the Context are Cancelled", + "type": "hype.Text" + } + ], + "tag": "\u003ch3\u003e", + "type": "hype.Heading" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "The illustration in ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-24" + }, + "filename": "cancellation.md", + "html_node": { + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-24" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.24", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-24\"\u003e", + "type": "hype.Link", + "url": "#listing-1-24" + } + ], + "tag": "\u003cref id=\"listing-1-24\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": " shows that by cancelling a node in the hierarchy, all its child nodes are also cancelled. Other nodes, such as parent and sibling nodes, in the hierarchy are unaffected.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-24", + "type": "listing" + }, + "filename": "cancellation.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "cancellation.svg" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "atom": "img", + "attributes": { + "src": "cancellation/assets/cancellation.svg" + }, + "filename": "cancellation", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "assets/cancellation.svg" + } + ], + "data": "img", + "data_atom": "img", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [], + "tag": "\u003cimg src=\"cancellation/assets/cancellation.svg\"\u003e", + "type": "hype.Image" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "cancellation", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.24:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "Cancellation propagation.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 24, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-24\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "h2", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "h2", + "data_atom": "h2", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "level": 2, + "nodes": [ + { + "text": "Listening for Cancellation Confirmation", + "type": "hype.Text" + } + ], + "tag": "\u003ch2\u003e", + "type": "hype.Heading" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Previously, we have use ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "time#Sleep", + "href": "https://pkg.go.dev/time#Sleep", + "target": "_blank" + }, + "filename": "cancellation.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "time.Sleep", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"time#Sleep\" href=\"https://pkg.go.dev/time#Sleep\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/time#Sleep" + } + ], + { + "text": " to block the execution of the program. This is not a good practice, as it can lead to deadlocks and other problems. Instead, the application should receive a ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "cancellation.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": " cancellation confirmation.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "h3", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "h3", + "data_atom": "h3", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "level": 3, + "nodes": [ + { + "text": "Starting a Concurrent Monitor", + "type": "hype.Text" + } + ], + "tag": "\u003ch3\u003e", + "type": "hype.Heading" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Consider ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-25" + }, + "filename": "cancellation.md", + "html_node": { + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-25" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.25", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-25\"\u003e", + "type": "hype.Link", + "url": "#listing-1-25" + } + ], + "tag": "\u003cref id=\"listing-1-25\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ". To start a ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Monitor", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " we must use the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Start", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " method giving it a ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "cancellation.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": ". In return, the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Start", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " method returns a ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "cancellation.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": " that can be listened to by the application to confirm the shutdown of the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Monitor", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " later on.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-25", + "type": "listing" + }, + "filename": "cancellation.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "cancelling.start" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + { + "atom": "pre", + "attributes": {}, + "filename": "cancellation", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "src": "cancellation/src/cancelling/main.go#start" + }, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/cancelling/main.go#start" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "content": "type Monitor struct {\n\tcancel context.CancelFunc\n}\n\nfunc (m *Monitor) Start(ctx context.Context) context.Context {\n\n\t// start the monitor with the given context\n\tgo m.listen(ctx)\n\n\t// create a new context that will be canceled\n\t// when the monitor is shut down\n\tctx, cancel := context.WithCancel(context.Background())\n\n\t// hold on to the cancellation function\n\t// when context that started the manager is canceled\n\t// this cancellation function will be called.\n\tm.cancel = cancel\n\n\t// return the new, cancellable, context.\n\t// clients can listen to this context\n\t// for cancellation to ensure the\n\t// monitor is properly shut down.\n\treturn ctx\n}", + "file": "cancellation/src/cancelling/main.go", + "lang": "go", + "name": "start", + "start": 10, + "end": 36 + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" src=\"cancellation/src/cancelling/main.go#start\"\u003e", + "type": "hype.SourceCode" + } + ] + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + }, + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "cancellation", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.25:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "Accepting a ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "cancellation", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "for", + "Val": "context#Context" + }, + { + "Namespace": "", + "Key": "href", + "Val": "https://pkg.go.dev/context#Context" + }, + { + "Namespace": "", + "Key": "target", + "Val": "_blank" + } + ], + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": {}, + "filename": "cancellation", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ] + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": " and returning a new one.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 25, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-25\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "To prevent the application from blocking, we launch a the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "listen", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " method in a goroutine with the given ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "cancellation.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": ". Unless this ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "cancellation.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": " is cancelled, the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "listen", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " method will never stop and will continue to leak resources until the application exits.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "The ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#CancelFunc", + "href": "https://pkg.go.dev/context#CancelFunc", + "target": "_blank" + }, + "filename": "cancellation.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.CancelFunc", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#CancelFunc\" href=\"https://pkg.go.dev/context#CancelFunc\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#CancelFunc" + } + ], + { + "text": " is held onto by the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Manager", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " so when the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Manager", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " is told to cancel by the client, it will also cancel the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Monitor", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " context. This will tell the client that the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Monitor", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " has been shutdown, confirming the cancellation of the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Monitor", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": ".", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "h3", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "h3", + "data_atom": "h3", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "level": 3, + "nodes": [ + { + "text": "Monitor Checking", + "type": "hype.Text" + } + ], + "tag": "\u003ch3\u003e", + "type": "hype.Heading" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "The ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "listen", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " method will block until the given ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "cancellation.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": ", given by the application, is cancelled, ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-26" + }, + "filename": "cancellation.md", + "html_node": { + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-26" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.26", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-26\"\u003e", + "type": "hype.Link", + "url": "#listing-1-26" + } + ], + "tag": "\u003cref id=\"listing-1-26\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ". We first make sure to defer the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#CancelFunc", + "href": "https://pkg.go.dev/context#CancelFunc", + "target": "_blank" + }, + "filename": "cancellation.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.CancelFunc", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#CancelFunc\" href=\"https://pkg.go.dev/context#CancelFunc\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#CancelFunc" + } + ], + { + "text": " in the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Monitor", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " to ensure that if any the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "listen", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " method exits for any reason, clients will be notified that the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Monitor", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " has been shutdown.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-26", + "type": "listing" + }, + "filename": "cancellation.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "cancelling.listen" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + { + "atom": "pre", + "attributes": {}, + "filename": "cancellation", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "src": "cancellation/src/cancelling/main.go#listen" + }, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/cancelling/main.go#listen" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "content": "func (m *Monitor) listen(ctx context.Context) {\n\tdefer m.cancel()\n\n\t// create a new ticker channel to listen to\n\ttick := time.NewTicker(time.Millisecond * 10)\n\tdefer tick.Stop()\n\n\t// use an infinite loop to continue to listen\n\t// to new messages after the select statement\n\t// has been executed\n\tfor {\n\t\tselect {\n\t\tcase \u003c-ctx.Done(): // listen for context cancellation\n\t\t\t// shut down if the context is canceled\n\t\t\tfmt.Println(\"shutting down monitor\")\n\n\t\t\t// if the monitor was told to shut down\n\t\t\t// then it should call its cancel function\n\t\t\t// so the client will know that the monitor\n\t\t\t// has properly shut down.\n\t\t\tm.cancel()\n\n\t\t\t// return from the function\n\t\t\treturn\n\t\tcase \u003c-tick.C: // listen to the ticker channel\n\t\t\t// and print a message every time it ticks\n\t\t\tfmt.Println(\"monitor check\")\n\t\t}\n\t}\n\n}", + "file": "cancellation/src/cancelling/main.go", + "lang": "go", + "name": "listen", + "start": 38, + "end": 71 + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" src=\"cancellation/src/cancelling/main.go#listen\"\u003e", + "type": "hype.SourceCode" + } + ] + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + }, + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "cancellation", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.26:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "cancellation", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Monitor", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " will call its ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#CancelFunc", + "href": "https://pkg.go.dev/context#CancelFunc", + "target": "_blank" + }, + "filename": "cancellation", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "for", + "Val": "context#CancelFunc" + }, + { + "Namespace": "", + "Key": "href", + "Val": "https://pkg.go.dev/context#CancelFunc" + }, + { + "Namespace": "", + "Key": "target", + "Val": "_blank" + } + ], + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": {}, + "filename": "cancellation", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.CancelFunc", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ] + ], + "tag": "\u003ca for=\"context#CancelFunc\" href=\"https://pkg.go.dev/context#CancelFunc\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#CancelFunc" + } + ], + { + "text": " if external ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "cancellation", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "for", + "Val": "context#Context" + }, + { + "Namespace": "", + "Key": "href", + "Val": "https://pkg.go.dev/context#Context" + }, + { + "Namespace": "", + "Key": "target", + "Val": "_blank" + } + ], + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": {}, + "filename": "cancellation", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ] + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": " is cancelled.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 26, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-26\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "h3", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "h3", + "data_atom": "h3", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "level": 3, + "nodes": [ + { + "text": "Using the Cancellation Confirmation", + "type": "hype.Text" + } + ], + "tag": "\u003ch3\u003e", + "type": "hype.Heading" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "In ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-27" + }, + "filename": "cancellation.md", + "html_node": { + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-27" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.27", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-27\"\u003e", + "type": "hype.Link", + "url": "#listing-1-27" + } + ], + "tag": "\u003cref id=\"listing-1-27\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ", the application starts with a ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Background", + "href": "https://pkg.go.dev/context#Background", + "target": "_blank" + }, + "filename": "cancellation.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Background", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Background\" href=\"https://pkg.go.dev/context#Background\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Background" + } + ], + { + "text": " context and then wraps that with a cancellable ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "cancellation.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": ". The ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#CancelFunc", + "href": "https://pkg.go.dev/context#CancelFunc", + "target": "_blank" + }, + "filename": "cancellation.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.CancelFunc", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#CancelFunc\" href=\"https://pkg.go.dev/context#CancelFunc\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#CancelFunc" + } + ], + { + "text": " returned by is immediately deferred to ensure the application doesn't leak any resources. After a short while, in a goroutine, the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "cancel", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " function is called, the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "cancellation.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": " is cancelled.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "The ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Monitor", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " is then started our cancellable ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "cancellation.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": ". The ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "cancellation.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": " returned by the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Start", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " method is listened to by the application. When the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Monitor", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " is cancelled, the application will be unblocked and can exit. Alternatively, if the application is still running after a couple of seconds the application is forcibly terminated.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-27", + "type": "listing" + }, + "filename": "cancellation.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "cancelling.main" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + { + "atom": "pre", + "attributes": {}, + "filename": "cancellation", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "src": "cancellation/src/cancelling/main.go#main" + }, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/cancelling/main.go#main" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "content": "func main() {\n\n\t// create a new background context\n\tctx := context.Background()\n\n\t// wrap the background context with a\n\t// cancellable context.\n\t// this context can be listened to any\n\t// children of this context for notification\n\t// of application shutdown/cancellation.\n\tctx, cancel := context.WithCancel(ctx)\n\n\t// ensure the cancel function is called\n\t// to shut down the monitor when the program\n\t// is exits\n\tdefer cancel()\n\n\t// launch a goroutine to cancel the application\n\t// context after a short while.\n\tgo func() {\n\t\ttime.Sleep(time.Millisecond * 50)\n\n\t\t// cancel the application context\n\t\t// this will shut the monitor down\n\t\tcancel()\n\t}()\n\n\t// create a new monitor\n\tmon := Monitor{}\n\n\t// start the monitor with the application context\n\t// this will return a context that can be listened to\n\t// for cancellation signaling the monitor has shut down.\n\tctx = mon.Start(ctx)\n\n\t// block the application until either the context\n\t// is canceled or the application times out\n\tselect {\n\tcase \u003c-ctx.Done(): // listen for context cancellation\n\t\t// success shutdown\n\t\tos.Exit(0)\n\tcase \u003c-time.After(time.Second * 2): // timeout after 2 second\n\t\tfmt.Println(\"timed out while trying to shut down the monitor\")\n\n\t\t// check if there was an error from the\n\t\t// monitor's context\n\t\tif err := ctx.Err(); err != nil {\n\t\t\tfmt.Printf(\"error: %s\\n\", err)\n\t\t}\n\n\t\t// non-successful shutdown\n\t\tos.Exit(1)\n\t}\n}", + "file": "cancellation/src/cancelling/main.go", + "lang": "go", + "name": "main", + "start": 73, + "end": 129 + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" src=\"cancellation/src/cancelling/main.go#main\"\u003e", + "type": "hype.SourceCode" + } + ] + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + }, + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "cancellation", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.27:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "Using the cancellation confirmation.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 27, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-27\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "As we can see from the output, in ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-28" + }, + "filename": "cancellation.md", + "html_node": { + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-28" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.28", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-28\"\u003e", + "type": "hype.Link", + "url": "#listing-1-28" + } + ], + "tag": "\u003cref id=\"listing-1-28\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ", the application waits for the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Monitor", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " to properly shutdown before exiting. We were also able to remove the use of ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "time#Sleep", + "href": "https://pkg.go.dev/time#Sleep", + "target": "_blank" + }, + "filename": "cancellation.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "cancellation.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "time.Sleep", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"time#Sleep\" href=\"https://pkg.go.dev/time#Sleep\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/time#Sleep" + } + ], + { + "text": " to allow the monitor to finish.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-28", + "type": "listing" + }, + "filename": "cancellation.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "cancelling.out" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "args": [ + "go", + "run", + "main.go" + ], + "atom": "cmd", + "attributes": { + "data-go-version": "go1.22.0", + "exec": "go run main.go", + "run": "main.go", + "src": "cancellation/src/cancelling" + }, + "expected_exit": 0, + "filename": "cancellation", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "data-go-version", + "Val": "go1.22.0" + }, + { + "Namespace": "", + "Key": "exec", + "Val": "go run main.go" + }, + { + "Namespace": "", + "Key": "run", + "Val": "main.go" + }, + { + "Namespace": "", + "Key": "src", + "Val": "./src/cancelling" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "run", + "main.go" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/12-context/cancellation/src/cancelling", + "duration": "1.829054s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go run main.go\n\nmonitor check\nmonitor check\nmonitor check\nmonitor check\nmonitor check\nmonitor check\nshutting down monitor", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "monitor check\nmonitor check\nmonitor check\nmonitor check\nmonitor check\nmonitor check\nshutting down monitor", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "run", + "main.go" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/12-context/cancellation/src/cancelling", + "duration": "1.829054s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go run main.go\n\nmonitor check\nmonitor check\nmonitor check\nmonitor check\nmonitor check\nmonitor check\nshutting down monitor", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "monitor check\nmonitor check\nmonitor check\nmonitor check\nmonitor check\nmonitor check\nshutting down monitor", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd data-go-version=\"go1.22.0\" exec=\"go run main.go\" run=\"main.go\" src=\"cancellation/src/cancelling\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "cancellation", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.28:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "The output of the application.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 28, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-28\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "tag": "\u003cpage\u003e", + "title": "Cancellation Propagation with Contexts", + "type": "hype.Page" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "tag": "\u003cinclude src=\"cancellation/cancellation.md\"\u003e", + "type": "hype.Include" + } + ], + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "atom": "include", + "attributes": { + "src": "timeouts/timeouts.md" + }, + "dir": "timeouts", + "filename": "module.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "timeouts/timeouts.md" + } + ], + "data": "include", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "page", + "attributes": {}, + "filename": "timeouts.md", + "html_node": { + "data": "page", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "atom": "h1", + "attributes": {}, + "filename": "timeouts.md", + "html_node": { + "data": "h1", + "data_atom": "h1", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "level": 1, + "nodes": [ + { + "text": "Timeouts and Deadlines", + "type": "hype.Text" + } + ], + "tag": "\u003ch1\u003e", + "type": "hype.Heading" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "timeouts.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "In addition to allowing us to manually cancel a ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "timeouts.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "timeouts.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": ", the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context", + "href": "https://pkg.go.dev/context", + "target": "_blank" + }, + "filename": "timeouts.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "timeouts.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context\" href=\"https://pkg.go.dev/context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context" + } + ], + { + "text": " package also provides mechanisms for creating a ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "timeouts.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "timeouts.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": " that will self-cancel after, or at, a given time. Using these mechanics allows us to control how long to run some before we give up and assume that the operation has failed.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "h2", + "attributes": {}, + "filename": "timeouts.md", + "html_node": { + "data": "h2", + "data_atom": "h2", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "level": 2, + "nodes": [ + { + "text": "Cancelling at a Specific Time", + "type": "hype.Text" + } + ], + "tag": "\u003ch2\u003e", + "type": "hype.Heading" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "timeouts.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "The ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context", + "href": "https://pkg.go.dev/context", + "target": "_blank" + }, + "filename": "timeouts.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "timeouts.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context\" href=\"https://pkg.go.dev/context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context" + } + ], + { + "text": " package provides two functions for creating time based, self-cancelling, a ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "timeouts.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "timeouts.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": "; ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#WithTimeout", + "href": "https://pkg.go.dev/context#WithTimeout", + "target": "_blank" + }, + "filename": "timeouts.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "timeouts.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.WithTimeout", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#WithTimeout\" href=\"https://pkg.go.dev/context#WithTimeout\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#WithTimeout" + } + ], + { + "text": " and ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#WithDeadline", + "href": "https://pkg.go.dev/context#WithDeadline", + "target": "_blank" + }, + "filename": "timeouts.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "timeouts.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.WithDeadline", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#WithDeadline\" href=\"https://pkg.go.dev/context#WithDeadline\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#WithDeadline" + } + ], + { + "text": ".", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-29", + "type": "listing" + }, + "filename": "timeouts.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "withdeadline.doc" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "args": [ + "go", + "doc", + "context.WithDeadline" + ], + "atom": "cmd", + "attributes": { + "data-go-version": "go1.22.0", + "doc": "context.WithDeadline", + "exec": "go doc context.WithDeadline" + }, + "expected_exit": 0, + "filename": "timeouts", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "data-go-version", + "Val": "go1.22.0" + }, + { + "Namespace": "", + "Key": "doc", + "Val": "context.WithDeadline" + }, + { + "Namespace": "", + "Key": "exec", + "Val": "go doc context.WithDeadline" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "doc", + "context.WithDeadline" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypejs", + "duration": "876.42275ms", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go doc context.WithDeadline\n\npackage context // import \u0026#34;context\u0026#34;\n\nfunc WithDeadline(parent Context, d time.Time) (Context, CancelFunc)\n WithDeadline returns a copy of the parent context with the deadline\n adjusted to be no later than d. If the parent\u0026#39;s deadline is already earlier\n than d, WithDeadline(parent, d) is semantically equivalent to parent.\n The returned [Context.Done] channel is closed when the deadline expires,\n when the returned cancel function is called, or when the parent context\u0026#39;s\n Done channel is closed, whichever happens first.\n\n Canceling this context releases resources associated with it, so code should\n call cancel as soon as the operations running in this Context complete.", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "package context // import \"context\"\n\nfunc WithDeadline(parent Context, d time.Time) (Context, CancelFunc)\n WithDeadline returns a copy of the parent context with the deadline\n adjusted to be no later than d. If the parent's deadline is already earlier\n than d, WithDeadline(parent, d) is semantically equivalent to parent.\n The returned [Context.Done] channel is closed when the deadline expires,\n when the returned cancel function is called, or when the parent context's\n Done channel is closed, whichever happens first.\n\n Canceling this context releases resources associated with it, so code should\n call cancel as soon as the operations running in this Context complete.", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "doc", + "context.WithDeadline" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypejs", + "duration": "876.42275ms", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go doc context.WithDeadline\n\npackage context // import \u0026#34;context\u0026#34;\n\nfunc WithDeadline(parent Context, d time.Time) (Context, CancelFunc)\n WithDeadline returns a copy of the parent context with the deadline\n adjusted to be no later than d. If the parent\u0026#39;s deadline is already earlier\n than d, WithDeadline(parent, d) is semantically equivalent to parent.\n The returned [Context.Done] channel is closed when the deadline expires,\n when the returned cancel function is called, or when the parent context\u0026#39;s\n Done channel is closed, whichever happens first.\n\n Canceling this context releases resources associated with it, so code should\n call cancel as soon as the operations running in this Context complete.", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "package context // import \"context\"\n\nfunc WithDeadline(parent Context, d time.Time) (Context, CancelFunc)\n WithDeadline returns a copy of the parent context with the deadline\n adjusted to be no later than d. If the parent's deadline is already earlier\n than d, WithDeadline(parent, d) is semantically equivalent to parent.\n The returned [Context.Done] channel is closed when the deadline expires,\n when the returned cancel function is called, or when the parent context's\n Done channel is closed, whichever happens first.\n\n Canceling this context releases resources associated with it, so code should\n call cancel as soon as the operations running in this Context complete.", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd data-go-version=\"go1.22.0\" doc=\"context.WithDeadline\" exec=\"go doc context.WithDeadline\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "timeouts", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.29:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "The ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#WithDeadline", + "href": "https://pkg.go.dev/context#WithDeadline", + "target": "_blank" + }, + "filename": "timeouts", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "for", + "Val": "context#WithDeadline" + }, + { + "Namespace": "", + "Key": "href", + "Val": "https://pkg.go.dev/context#WithDeadline" + }, + { + "Namespace": "", + "Key": "target", + "Val": "_blank" + } + ], + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": {}, + "filename": "timeouts", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.WithDeadline", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ] + ], + "tag": "\u003ca for=\"context#WithDeadline\" href=\"https://pkg.go.dev/context#WithDeadline\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#WithDeadline" + } + ], + { + "text": " function.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 29, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-29\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "timeouts.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "When using ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#WithDeadline", + "href": "https://pkg.go.dev/context#WithDeadline", + "target": "_blank" + }, + "filename": "timeouts.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "timeouts.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.WithDeadline", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#WithDeadline\" href=\"https://pkg.go.dev/context#WithDeadline\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#WithDeadline" + } + ], + { + "text": ", ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-29" + }, + "filename": "timeouts.md", + "html_node": { + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-29" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.29", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-29\"\u003e", + "type": "hype.Link", + "url": "#listing-1-29" + } + ], + "tag": "\u003cref id=\"listing-1-29\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ", we need to provide an ", + "type": "hype.Text" + }, + { + "atom": "strong", + "attributes": {}, + "filename": "timeouts.md", + "html_node": { + "data": "strong", + "data_atom": "strong", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "absolute", + "type": "hype.Text" + } + ], + "tag": "\u003cstrong\u003e", + "type": "hype.Element" + }, + { + "text": " time at which the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "timeouts.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "timeouts.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": " should be cancelled. That means we need an exact date/time we want this ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "timeouts.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "timeouts.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": " to be cancelled, for example ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "timeouts.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "March 14, 2029 3:45pm", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": ".", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "timeouts.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Consider ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-30" + }, + "filename": "timeouts.md", + "html_node": { + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-30" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.30", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-30\"\u003e", + "type": "hype.Link", + "url": "#listing-1-30" + } + ], + "tag": "\u003cref id=\"listing-1-30\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ". In it, we create a new ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "time#Time", + "href": "https://pkg.go.dev/time#Time", + "target": "_blank" + }, + "filename": "timeouts.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "timeouts.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "time.Time", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"time#Time\" href=\"https://pkg.go.dev/time#Time\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/time#Time" + } + ], + { + "text": " for ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "timeouts.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "January 1, 2030 00:00:00", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " and use it to create a ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "timeouts.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "timeouts.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": " that will self-cancel at that date and time.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-30", + "type": "listing" + }, + "filename": "timeouts.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "deadline.example" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + { + "atom": "pre", + "attributes": {}, + "filename": "timeouts", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "src": "timeouts/src/with-deadline/main.go#example" + }, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/with-deadline/main.go#example" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "content": "func main() {\n\n\t// create a background context\n\tctx := context.Background()\n\n\t// create an absolute date/time (January 1, 2030)\n\tdeadline := time.Date(2030, 1, 1, 0, 0, 0, 0, time.UTC)\n\tfmt.Println(\"deadline:\", deadline.Format(time.RFC3339))\n\n\t// create a new context with a deadline\n\t// that will cancel at January 1, 2030 00:00:00.\n\tctx, cancel := context.WithDeadline(ctx, deadline)\n\tdefer cancel()\n\n\tprint(ctx)\n}", + "file": "timeouts/src/with-deadline/main.go", + "lang": "go", + "name": "example", + "start": 12, + "end": 30 + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" src=\"timeouts/src/with-deadline/main.go#example\"\u003e", + "type": "hype.SourceCode" + } + ] + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + }, + { + "atom": "hr", + "attributes": {}, + "filename": "timeouts", + "html_node": { + "data": "hr", + "data_atom": "hr", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [], + "tag": "\u003chr\u003e", + "type": "hype.Element" + }, + [ + { + "args": [ + "go", + "run", + "." + ], + "atom": "cmd", + "attributes": { + "data-go-version": "go1.22.0", + "exec": "go run .", + "run": ".", + "src": "timeouts/src/with-deadline" + }, + "expected_exit": 0, + "filename": "timeouts", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "data-go-version", + "Val": "go1.22.0" + }, + { + "Namespace": "", + "Key": "exec", + "Val": "go run ." + }, + { + "Namespace": "", + "Key": "run", + "Val": "." + }, + { + "Namespace": "", + "Key": "src", + "Val": "src/with-deadline" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "run", + "." + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/12-context/timeouts/src/with-deadline", + "duration": "3.035979875s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go run .\n\ndeadline: 2030-01-01T00:00:00Z\nWithTimeout(deadline: {wall:0 ext:64029052800 loc:\u0026lt;nil\u0026gt;})\n\t--\u0026gt; context.backgroundCtx", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "deadline: 2030-01-01T00:00:00Z\nWithTimeout(deadline: {wall:0 ext:64029052800 loc:\u003cnil\u003e})\n\t--\u003e context.backgroundCtx", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "run", + "." + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/12-context/timeouts/src/with-deadline", + "duration": "3.035979875s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go run .\n\ndeadline: 2030-01-01T00:00:00Z\nWithTimeout(deadline: {wall:0 ext:64029052800 loc:\u0026lt;nil\u0026gt;})\n\t--\u0026gt; context.backgroundCtx", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "deadline: 2030-01-01T00:00:00Z\nWithTimeout(deadline: {wall:0 ext:64029052800 loc:\u003cnil\u003e})\n\t--\u003e context.backgroundCtx", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd data-go-version=\"go1.22.0\" exec=\"go run .\" run=\".\" src=\"timeouts/src/with-deadline\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "timeouts", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.30:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "Using ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#WithDeadline", + "href": "https://pkg.go.dev/context#WithDeadline", + "target": "_blank" + }, + "filename": "timeouts", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "for", + "Val": "context#WithDeadline" + }, + { + "Namespace": "", + "Key": "href", + "Val": "https://pkg.go.dev/context#WithDeadline" + }, + { + "Namespace": "", + "Key": "target", + "Val": "_blank" + } + ], + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": {}, + "filename": "timeouts", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.WithDeadline", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ] + ], + "tag": "\u003ca for=\"context#WithDeadline\" href=\"https://pkg.go.dev/context#WithDeadline\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#WithDeadline" + } + ], + { + "text": ".", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 30, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-30\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "h2", + "attributes": {}, + "filename": "timeouts.md", + "html_node": { + "data": "h2", + "data_atom": "h2", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "level": 2, + "nodes": [ + { + "text": "Cancelling After a Duration", + "type": "hype.Text" + } + ], + "tag": "\u003ch2\u003e", + "type": "hype.Heading" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "timeouts.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "While being able to cancel a ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "timeouts.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "timeouts.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": " at a particular time is useful, more often than not we want to cancel a ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "timeouts.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "timeouts.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": " after a certain amount of time has passed.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-31", + "type": "listing" + }, + "filename": "timeouts.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "withtimeout.doc" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "args": [ + "go", + "doc", + "context.WithTimeout" + ], + "atom": "cmd", + "attributes": { + "data-go-version": "go1.22.0", + "doc": "context.WithTimeout", + "exec": "go doc context.WithTimeout" + }, + "expected_exit": 0, + "filename": "timeouts", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "data-go-version", + "Val": "go1.22.0" + }, + { + "Namespace": "", + "Key": "doc", + "Val": "context.WithTimeout" + }, + { + "Namespace": "", + "Key": "exec", + "Val": "go doc context.WithTimeout" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "doc", + "context.WithTimeout" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypejs", + "duration": "1.110710708s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go doc context.WithTimeout\n\npackage context // import \u0026#34;context\u0026#34;\n\nfunc WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc)\n WithTimeout returns WithDeadline(parent, time.Now().Add(timeout)).\n\n Canceling this context releases resources associated with it, so code should\n call cancel as soon as the operations running in this Context complete:\n\n func slowOperationWithTimeout(ctx context.Context) (Result, error) {\n \tctx, cancel := context.WithTimeout(ctx, 100*time.Millisecond)\n \tdefer cancel() // releases resources if slowOperation completes before timeout elapses\n \treturn slowOperation(ctx)\n }", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "package context // import \"context\"\n\nfunc WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc)\n WithTimeout returns WithDeadline(parent, time.Now().Add(timeout)).\n\n Canceling this context releases resources associated with it, so code should\n call cancel as soon as the operations running in this Context complete:\n\n func slowOperationWithTimeout(ctx context.Context) (Result, error) {\n \tctx, cancel := context.WithTimeout(ctx, 100*time.Millisecond)\n \tdefer cancel() // releases resources if slowOperation completes before timeout elapses\n \treturn slowOperation(ctx)\n }", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "doc", + "context.WithTimeout" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypejs", + "duration": "1.110710708s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go doc context.WithTimeout\n\npackage context // import \u0026#34;context\u0026#34;\n\nfunc WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc)\n WithTimeout returns WithDeadline(parent, time.Now().Add(timeout)).\n\n Canceling this context releases resources associated with it, so code should\n call cancel as soon as the operations running in this Context complete:\n\n func slowOperationWithTimeout(ctx context.Context) (Result, error) {\n \tctx, cancel := context.WithTimeout(ctx, 100*time.Millisecond)\n \tdefer cancel() // releases resources if slowOperation completes before timeout elapses\n \treturn slowOperation(ctx)\n }", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "package context // import \"context\"\n\nfunc WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc)\n WithTimeout returns WithDeadline(parent, time.Now().Add(timeout)).\n\n Canceling this context releases resources associated with it, so code should\n call cancel as soon as the operations running in this Context complete:\n\n func slowOperationWithTimeout(ctx context.Context) (Result, error) {\n \tctx, cancel := context.WithTimeout(ctx, 100*time.Millisecond)\n \tdefer cancel() // releases resources if slowOperation completes before timeout elapses\n \treturn slowOperation(ctx)\n }", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd data-go-version=\"go1.22.0\" doc=\"context.WithTimeout\" exec=\"go doc context.WithTimeout\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "timeouts", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.31:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "The ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#WithTimeout", + "href": "https://pkg.go.dev/context#WithTimeout", + "target": "_blank" + }, + "filename": "timeouts", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "for", + "Val": "context#WithTimeout" + }, + { + "Namespace": "", + "Key": "href", + "Val": "https://pkg.go.dev/context#WithTimeout" + }, + { + "Namespace": "", + "Key": "target", + "Val": "_blank" + } + ], + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": {}, + "filename": "timeouts", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.WithTimeout", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ] + ], + "tag": "\u003ca for=\"context#WithTimeout\" href=\"https://pkg.go.dev/context#WithTimeout\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#WithTimeout" + } + ], + { + "text": " function.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 31, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-31\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "timeouts.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "When using ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#WithTimeout", + "href": "https://pkg.go.dev/context#WithTimeout", + "target": "_blank" + }, + "filename": "timeouts.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "timeouts.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.WithTimeout", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#WithTimeout\" href=\"https://pkg.go.dev/context#WithTimeout\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#WithTimeout" + } + ], + { + "text": ", ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-31" + }, + "filename": "timeouts.md", + "html_node": { + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-31" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.31", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-31\"\u003e", + "type": "hype.Link", + "url": "#listing-1-31" + } + ], + "tag": "\u003cref id=\"listing-1-31\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": "a, we need to provide an ", + "type": "hype.Text" + }, + { + "atom": "strong", + "attributes": {}, + "filename": "timeouts.md", + "html_node": { + "data": "strong", + "data_atom": "strong", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "relative", + "type": "hype.Text" + } + ], + "tag": "\u003cstrong\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "time#Duration", + "href": "https://pkg.go.dev/time#Duration", + "target": "_blank" + }, + "filename": "timeouts.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "timeouts.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "time.Duration", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"time#Duration\" href=\"https://pkg.go.dev/time#Duration\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/time#Duration" + } + ], + { + "text": " at which the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "timeouts.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "timeouts.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": " should be cancelled.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "timeouts.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Consider ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-32" + }, + "filename": "timeouts.md", + "html_node": { + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-32" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.32", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-32\"\u003e", + "type": "hype.Link", + "url": "#listing-1-32" + } + ], + "tag": "\u003cref id=\"listing-1-32\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ". In it, we create a new self-cancelling ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "timeouts.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "timeouts.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": " that will self-cancel after 5 seconds using ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#WithTimeout", + "href": "https://pkg.go.dev/context#WithTimeout", + "target": "_blank" + }, + "filename": "timeouts.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "timeouts.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.WithTimeout", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#WithTimeout\" href=\"https://pkg.go.dev/context#WithTimeout\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#WithTimeout" + } + ], + { + "text": ".", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-32", + "type": "listing" + }, + "filename": "timeouts.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "timeout.example" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + { + "atom": "pre", + "attributes": {}, + "filename": "timeouts", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "src": "timeouts/src/with-timeout/main.go#example" + }, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/with-timeout/main.go#example" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "content": "func main() {\n\n\t// create a background context\n\tctx := context.Background()\n\n\t// create a new context with a timeout\n\t// that will cancel the context after 10ms\n\t// \tequivalent to:\n\t//\t\tcontext.WithDeadline(ctx, time.Now().Add(10 *time.Millisecond))\n\tctx, cancel := context.WithTimeout(ctx, 10*time.Millisecond)\n\tdefer cancel()\n\n\tprint(ctx)\n}", + "file": "timeouts/src/with-timeout/main.go", + "lang": "go", + "name": "example", + "start": 11, + "end": 27 + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" src=\"timeouts/src/with-timeout/main.go#example\"\u003e", + "type": "hype.SourceCode" + } + ] + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + }, + { + "atom": "hr", + "attributes": {}, + "filename": "timeouts", + "html_node": { + "data": "hr", + "data_atom": "hr", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [], + "tag": "\u003chr\u003e", + "type": "hype.Element" + }, + [ + { + "args": [ + "go", + "run", + "." + ], + "atom": "cmd", + "attributes": { + "data-go-version": "go1.22.0", + "exec": "go run .", + "run": ".", + "src": "timeouts/src/with-timeout" + }, + "expected_exit": 0, + "filename": "timeouts", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "data-go-version", + "Val": "go1.22.0" + }, + { + "Namespace": "", + "Key": "exec", + "Val": "go run ." + }, + { + "Namespace": "", + "Key": "run", + "Val": "." + }, + { + "Namespace": "", + "Key": "src", + "Val": "src/with-timeout" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "run", + "." + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/12-context/timeouts/src/with-timeout", + "duration": "3.627415708s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go run .\n\nWithTimeout(deadline: {wall:13937916055689088760 ext:10227626 loc:0x102cf9f00})\n\t--\u0026gt; context.backgroundCtx", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "WithTimeout(deadline: {wall:13937916055689088760 ext:10227626 loc:0x102cf9f00})\n\t--\u003e context.backgroundCtx", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "run", + "." + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/12-context/timeouts/src/with-timeout", + "duration": "3.627415708s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go run .\n\nWithTimeout(deadline: {wall:13937916055689088760 ext:10227626 loc:0x102cf9f00})\n\t--\u0026gt; context.backgroundCtx", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "WithTimeout(deadline: {wall:13937916055689088760 ext:10227626 loc:0x102cf9f00})\n\t--\u003e context.backgroundCtx", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd data-go-version=\"go1.22.0\" exec=\"go run .\" run=\".\" src=\"timeouts/src/with-timeout\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "timeouts", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.32:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "Using ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#WithTimeout", + "href": "https://pkg.go.dev/context#WithTimeout", + "target": "_blank" + }, + "filename": "timeouts", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "for", + "Val": "context#WithTimeout" + }, + { + "Namespace": "", + "Key": "href", + "Val": "https://pkg.go.dev/context#WithTimeout" + }, + { + "Namespace": "", + "Key": "target", + "Val": "_blank" + } + ], + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": {}, + "filename": "timeouts", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.WithTimeout", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ] + ], + "tag": "\u003ca for=\"context#WithTimeout\" href=\"https://pkg.go.dev/context#WithTimeout\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#WithTimeout" + } + ], + { + "text": ".", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 32, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-32\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "timeouts.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Functionally, we could have used ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#WithDeadline", + "href": "https://pkg.go.dev/context#WithDeadline", + "target": "_blank" + }, + "filename": "timeouts.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "timeouts.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.WithDeadline", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#WithDeadline\" href=\"https://pkg.go.dev/context#WithDeadline\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#WithDeadline" + } + ], + { + "text": " instead, but ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#WithTimeout", + "href": "https://pkg.go.dev/context#WithTimeout", + "target": "_blank" + }, + "filename": "timeouts.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "timeouts.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.WithTimeout", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#WithTimeout\" href=\"https://pkg.go.dev/context#WithTimeout\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#WithTimeout" + } + ], + { + "text": " is more convenient when we want to cancel a ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "timeouts.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "timeouts.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": " after a certain amount of time has passed.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "tag": "\u003cpage\u003e", + "title": "Timeouts and Deadlines", + "type": "hype.Page" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "tag": "\u003cinclude src=\"timeouts/timeouts.md\"\u003e", + "type": "hype.Include" + } + ], + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "atom": "include", + "attributes": { + "src": "errors/errors.md" + }, + "dir": "errors", + "filename": "module.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "errors/errors.md" + } + ], + "data": "include", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "page", + "attributes": {}, + "filename": "errors.md", + "html_node": { + "data": "page", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "atom": "h1", + "attributes": {}, + "filename": "errors.md", + "html_node": { + "data": "h1", + "data_atom": "h1", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "level": 1, + "nodes": [ + { + "text": "Context Errors", + "type": "hype.Text" + } + ], + "tag": "\u003ch1\u003e", + "type": "hype.Heading" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "errors.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "In a complex system, or even in a small one, when a ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "errors.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "errors.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": " is cancelled, we need a way to know what caused the cancellation. It is possible that ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "errors.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "errors.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": " was cancelled by a ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#CancelFunc", + "href": "https://pkg.go.dev/context#CancelFunc", + "target": "_blank" + }, + "filename": "errors.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "errors.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.CancelFunc", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#CancelFunc\" href=\"https://pkg.go.dev/context#CancelFunc\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#CancelFunc" + } + ], + { + "text": " successfully, if it was cancelled because it timed out, or some other reason.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "errors.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "The ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context.Err", + "href": "https://pkg.go.dev/context#Context.Err", + "target": "_blank" + }, + "filename": "errors.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "errors.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context.Err", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context.Err\" href=\"https://pkg.go.dev/context#Context.Err\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context.Err" + } + ], + { + "text": " method, ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-33" + }, + "filename": "errors.md", + "html_node": { + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-33" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.33", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-33\"\u003e", + "type": "hype.Link", + "url": "#listing-1-33" + } + ], + "tag": "\u003cref id=\"listing-1-33\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": " returns the error that caused the context to be cancelled.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-33", + "type": "listing" + }, + "filename": "errors.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "context.err" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "args": [ + "go", + "doc", + "context.Context.Err" + ], + "atom": "cmd", + "attributes": { + "data-go-version": "go1.22.0", + "doc": "context.Context.Err", + "exec": "go doc context.Context.Err" + }, + "expected_exit": 0, + "filename": "errors", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "data-go-version", + "Val": "go1.22.0" + }, + { + "Namespace": "", + "Key": "doc", + "Val": "context.Context.Err" + }, + { + "Namespace": "", + "Key": "exec", + "Val": "go doc context.Context.Err" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "doc", + "context.Context.Err" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypejs", + "duration": "1.37339775s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go doc context.Context.Err\n\npackage context // import \u0026#34;context\u0026#34;\n\ntype Context interface {\n\n\t// If Done is not yet closed, Err returns nil.\n\t// If Done is closed, Err returns a non-nil error explaining why:\n\t// Canceled if the context was canceled\n\t// or DeadlineExceeded if the context\u0026#39;s deadline passed.\n\t// After Err returns a non-nil error, successive calls to Err return the same error.\n\tErr() error\n}", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "package context // import \"context\"\n\ntype Context interface {\n\n\t// If Done is not yet closed, Err returns nil.\n\t// If Done is closed, Err returns a non-nil error explaining why:\n\t// Canceled if the context was canceled\n\t// or DeadlineExceeded if the context's deadline passed.\n\t// After Err returns a non-nil error, successive calls to Err return the same error.\n\tErr() error\n}", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "doc", + "context.Context.Err" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypejs", + "duration": "1.37339775s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go doc context.Context.Err\n\npackage context // import \u0026#34;context\u0026#34;\n\ntype Context interface {\n\n\t// If Done is not yet closed, Err returns nil.\n\t// If Done is closed, Err returns a non-nil error explaining why:\n\t// Canceled if the context was canceled\n\t// or DeadlineExceeded if the context\u0026#39;s deadline passed.\n\t// After Err returns a non-nil error, successive calls to Err return the same error.\n\tErr() error\n}", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "package context // import \"context\"\n\ntype Context interface {\n\n\t// If Done is not yet closed, Err returns nil.\n\t// If Done is closed, Err returns a non-nil error explaining why:\n\t// Canceled if the context was canceled\n\t// or DeadlineExceeded if the context's deadline passed.\n\t// After Err returns a non-nil error, successive calls to Err return the same error.\n\tErr() error\n}", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd data-go-version=\"go1.22.0\" doc=\"context.Context.Err\" exec=\"go doc context.Context.Err\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.33:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "The ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context.Err", + "href": "https://pkg.go.dev/context#Context.Err", + "target": "_blank" + }, + "filename": "errors", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "for", + "Val": "context#Context.Err" + }, + { + "Namespace": "", + "Key": "href", + "Val": "https://pkg.go.dev/context#Context.Err" + }, + { + "Namespace": "", + "Key": "target", + "Val": "_blank" + } + ], + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context.Err", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ] + ], + "tag": "\u003ca for=\"context#Context.Err\" href=\"https://pkg.go.dev/context#Context.Err\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context.Err" + } + ], + { + "text": " method.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 33, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-33\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "h2", + "attributes": {}, + "filename": "errors.md", + "html_node": { + "data": "h2", + "data_atom": "h2", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "level": 2, + "nodes": [ + { + "text": "Context Cancelled Error", + "type": "hype.Text" + } + ], + "tag": "\u003ch2\u003e", + "type": "hype.Heading" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "errors.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "The ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context", + "href": "https://pkg.go.dev/context", + "target": "_blank" + }, + "filename": "errors.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "errors.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context\" href=\"https://pkg.go.dev/context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context" + } + ], + { + "text": " package defines two different ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "builtin#error", + "href": "https://pkg.go.dev/builtin#error", + "target": "_blank" + }, + "filename": "errors.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "errors.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "error", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"builtin#error\" href=\"https://pkg.go.dev/builtin#error\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/builtin#error" + } + ], + { + "text": " variables that can be used to check an ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "builtin#error", + "href": "https://pkg.go.dev/builtin#error", + "target": "_blank" + }, + "filename": "errors.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "errors.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "error", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"builtin#error\" href=\"https://pkg.go.dev/builtin#error\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/builtin#error" + } + ], + { + "text": " that was returned from ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context.Err", + "href": "https://pkg.go.dev/context#Context.Err", + "target": "_blank" + }, + "filename": "errors.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "errors.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context.Err", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context.Err\" href=\"https://pkg.go.dev/context#Context.Err\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context.Err" + } + ], + { + "text": " method.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "errors.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "The first is ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Canceled", + "href": "https://pkg.go.dev/context#Canceled", + "target": "_blank" + }, + "filename": "errors.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "errors.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Canceled", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Canceled\" href=\"https://pkg.go.dev/context#Canceled\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Canceled" + } + ], + { + "text": ", ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-34" + }, + "filename": "errors.md", + "html_node": { + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-34" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.34", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-34\"\u003e", + "type": "hype.Link", + "url": "#listing-1-34" + } + ], + "tag": "\u003cref id=\"listing-1-34\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ", which is returned when the context is cancelled through the use of a ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#CancelFunc", + "href": "https://pkg.go.dev/context#CancelFunc", + "target": "_blank" + }, + "filename": "errors.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "errors.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.CancelFunc", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#CancelFunc\" href=\"https://pkg.go.dev/context#CancelFunc\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#CancelFunc" + } + ], + { + "text": " function. This ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "builtin#error", + "href": "https://pkg.go.dev/builtin#error", + "target": "_blank" + }, + "filename": "errors.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "errors.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "error", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"builtin#error\" href=\"https://pkg.go.dev/builtin#error\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/builtin#error" + } + ], + { + "text": " is considered to indicate a \"successful\" cancellation.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-34", + "type": "listing" + }, + "filename": "errors.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "canceled.doc" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "args": [ + "go", + "doc", + "context.Canceled" + ], + "atom": "cmd", + "attributes": { + "data-go-version": "go1.22.0", + "doc": "context.Canceled", + "exec": "go doc context.Canceled" + }, + "expected_exit": 0, + "filename": "errors", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "data-go-version", + "Val": "go1.22.0" + }, + { + "Namespace": "", + "Key": "doc", + "Val": "context.Canceled" + }, + { + "Namespace": "", + "Key": "exec", + "Val": "go doc context.Canceled" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "doc", + "context.Canceled" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypejs", + "duration": "1.788814125s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go doc context.Canceled\n\npackage context // import \u0026#34;context\u0026#34;\n\nvar Canceled = errors.New(\u0026#34;context canceled\u0026#34;)\n Canceled is the error returned by [Context.Err] when the context is\n canceled.", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "package context // import \"context\"\n\nvar Canceled = errors.New(\"context canceled\")\n Canceled is the error returned by [Context.Err] when the context is\n canceled.", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "doc", + "context.Canceled" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypejs", + "duration": "1.788814125s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go doc context.Canceled\n\npackage context // import \u0026#34;context\u0026#34;\n\nvar Canceled = errors.New(\u0026#34;context canceled\u0026#34;)\n Canceled is the error returned by [Context.Err] when the context is\n canceled.", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "package context // import \"context\"\n\nvar Canceled = errors.New(\"context canceled\")\n Canceled is the error returned by [Context.Err] when the context is\n canceled.", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd data-go-version=\"go1.22.0\" doc=\"context.Canceled\" exec=\"go doc context.Canceled\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.34:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "The ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Canceled", + "href": "https://pkg.go.dev/context#Canceled", + "target": "_blank" + }, + "filename": "errors", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "for", + "Val": "context#Canceled" + }, + { + "Namespace": "", + "Key": "href", + "Val": "https://pkg.go.dev/context#Canceled" + }, + { + "Namespace": "", + "Key": "target", + "Val": "_blank" + } + ], + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Canceled", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ] + ], + "tag": "\u003ca for=\"context#Canceled\" href=\"https://pkg.go.dev/context#Canceled\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Canceled" + } + ], + { + "text": " ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "builtin#error", + "href": "https://pkg.go.dev/builtin#error", + "target": "_blank" + }, + "filename": "errors", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "for", + "Val": "builtin#error" + }, + { + "Namespace": "", + "Key": "href", + "Val": "https://pkg.go.dev/builtin#error" + }, + { + "Namespace": "", + "Key": "target", + "Val": "_blank" + } + ], + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "error", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ] + ], + "tag": "\u003ca for=\"builtin#error\" href=\"https://pkg.go.dev/builtin#error\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/builtin#error" + } + ], + { + "text": ".", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 34, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-34\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "errors.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Consider ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-35" + }, + "filename": "errors.md", + "html_node": { + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-35" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.35", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-35\"\u003e", + "type": "hype.Link", + "url": "#listing-1-35" + } + ], + "tag": "\u003cref id=\"listing-1-35\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ". When we first check the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context.Err", + "href": "https://pkg.go.dev/context#Context.Err", + "target": "_blank" + }, + "filename": "errors.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "errors.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context.Err", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context.Err\" href=\"https://pkg.go.dev/context#Context.Err\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context.Err" + } + ], + { + "text": " method, it returns ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "nil", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": ". After we call the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#CancelFunc", + "href": "https://pkg.go.dev/context#CancelFunc", + "target": "_blank" + }, + "filename": "errors.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "errors.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.CancelFunc", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#CancelFunc\" href=\"https://pkg.go.dev/context#CancelFunc\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#CancelFunc" + } + ], + { + "text": " function provided by ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#WithCancel", + "href": "https://pkg.go.dev/context#WithCancel", + "target": "_blank" + }, + "filename": "errors.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "errors.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.WithCancel", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#WithCancel\" href=\"https://pkg.go.dev/context#WithCancel\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#WithCancel" + } + ], + { + "text": ", the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context.Err", + "href": "https://pkg.go.dev/context#Context.Err", + "target": "_blank" + }, + "filename": "errors.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "errors.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context.Err", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context.Err\" href=\"https://pkg.go.dev/context#Context.Err\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context.Err" + } + ], + { + "text": " method returns a ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Canceled", + "href": "https://pkg.go.dev/context#Canceled", + "target": "_blank" + }, + "filename": "errors.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "errors.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Canceled", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Canceled\" href=\"https://pkg.go.dev/context#Canceled\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Canceled" + } + ], + { + "text": " error.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-35", + "type": "listing" + }, + "filename": "errors.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "canceled.example" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + { + "atom": "pre", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "src": "errors/src/canceled/main.go#example" + }, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/canceled/main.go#example" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "content": "func main() {\n\n\t// create a background context\n\tctx := context.Background()\n\n\t// wrap the context with a\n\t// cancellable context\n\tctx, cancel := context.WithCancel(ctx)\n\n\t// check the error:\n\t//\t\u003cnil\u003e\n\tfmt.Println(\"ctx.Err()\", ctx.Err())\n\n\t// cancel the context\n\tcancel()\n\n\t// check the error:\n\t//\tcontext.Canceled\n\tfmt.Println(\"ctx.Err()\", ctx.Err())\n\n\t// check the error again:\n\t//\tcontext.Canceled\n\tfmt.Println(\"ctx.Err()\", ctx.Err())\n}", + "file": "errors/src/canceled/main.go", + "lang": "go", + "name": "example", + "start": 8, + "end": 34 + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" src=\"errors/src/canceled/main.go#example\"\u003e", + "type": "hype.SourceCode" + } + ] + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + }, + { + "atom": "hr", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "hr", + "data_atom": "hr", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [], + "tag": "\u003chr\u003e", + "type": "hype.Element" + }, + [ + { + "args": [ + "go", + "run", + "." + ], + "atom": "cmd", + "attributes": { + "data-go-version": "go1.22.0", + "exec": "go run .", + "run": ".", + "src": "errors/src/canceled" + }, + "expected_exit": 0, + "filename": "errors", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "data-go-version", + "Val": "go1.22.0" + }, + { + "Namespace": "", + "Key": "exec", + "Val": "go run ." + }, + { + "Namespace": "", + "Key": "run", + "Val": "." + }, + { + "Namespace": "", + "Key": "src", + "Val": "src/canceled" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "run", + "." + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/12-context/errors/src/canceled", + "duration": "3.558376s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go run .\n\nctx.Err() \u0026lt;nil\u0026gt;\nctx.Err() context canceled\nctx.Err() context canceled", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "ctx.Err() \u003cnil\u003e\nctx.Err() context canceled\nctx.Err() context canceled", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "run", + "." + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/12-context/errors/src/canceled", + "duration": "3.558376s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go run .\n\nctx.Err() \u0026lt;nil\u0026gt;\nctx.Err() context canceled\nctx.Err() context canceled", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "ctx.Err() \u003cnil\u003e\nctx.Err() context canceled\nctx.Err() context canceled", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd data-go-version=\"go1.22.0\" exec=\"go run .\" run=\".\" src=\"errors/src/canceled\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.35:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "Checking for cancellation errors.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 35, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-35\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "errors.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "As we can see from the output in ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-35" + }, + "filename": "errors.md", + "html_node": { + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-35" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.35", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-35\"\u003e", + "type": "hype.Link", + "url": "#listing-1-35" + } + ], + "tag": "\u003cref id=\"listing-1-35\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ", repeated calls to the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context.Err", + "href": "https://pkg.go.dev/context#Context.Err", + "target": "_blank" + }, + "filename": "errors.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "errors.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context.Err", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context.Err\" href=\"https://pkg.go.dev/context#Context.Err\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context.Err" + } + ], + { + "text": " method return the same ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Canceled", + "href": "https://pkg.go.dev/context#Canceled", + "target": "_blank" + }, + "filename": "errors.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "errors.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Canceled", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Canceled\" href=\"https://pkg.go.dev/context#Canceled\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Canceled" + } + ], + { + "text": " error.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "h2", + "attributes": {}, + "filename": "errors.md", + "html_node": { + "data": "h2", + "data_atom": "h2", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "level": 2, + "nodes": [ + { + "text": "Context Deadline Exceeded Error", + "type": "hype.Text" + } + ], + "tag": "\u003ch2\u003e", + "type": "hype.Heading" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "errors.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "When a ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "errors.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "errors.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": " is cancelled due to a deadline, or timeout, being exceeded, the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context.Err", + "href": "https://pkg.go.dev/context#Context.Err", + "target": "_blank" + }, + "filename": "errors.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "errors.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context.Err", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context.Err\" href=\"https://pkg.go.dev/context#Context.Err\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context.Err" + } + ], + { + "text": " method returns a ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#DeadlineExceeded", + "href": "https://pkg.go.dev/context#DeadlineExceeded", + "target": "_blank" + }, + "filename": "errors.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "errors.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.DeadlineExceeded", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#DeadlineExceeded\" href=\"https://pkg.go.dev/context#DeadlineExceeded\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#DeadlineExceeded" + } + ], + { + "text": " error, ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-36" + }, + "filename": "errors.md", + "html_node": { + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-36" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.36", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-36\"\u003e", + "type": "hype.Link", + "url": "#listing-1-36" + } + ], + "tag": "\u003cref id=\"listing-1-36\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ".", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-36", + "type": "listing" + }, + "filename": "errors.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "exceeded.doc" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "args": [ + "go", + "doc", + "context.DeadlineExceeded" + ], + "atom": "cmd", + "attributes": { + "data-go-version": "go1.22.0", + "doc": "context.DeadlineExceeded", + "exec": "go doc context.DeadlineExceeded" + }, + "expected_exit": 0, + "filename": "errors", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "data-go-version", + "Val": "go1.22.0" + }, + { + "Namespace": "", + "Key": "doc", + "Val": "context.DeadlineExceeded" + }, + { + "Namespace": "", + "Key": "exec", + "Val": "go doc context.DeadlineExceeded" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "doc", + "context.DeadlineExceeded" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypejs", + "duration": "1.615876042s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go doc context.DeadlineExceeded\n\npackage context // import \u0026#34;context\u0026#34;\n\nvar DeadlineExceeded error = deadlineExceededError{}\n DeadlineExceeded is the error returned by [Context.Err] when the context\u0026#39;s\n deadline passes.", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "package context // import \"context\"\n\nvar DeadlineExceeded error = deadlineExceededError{}\n DeadlineExceeded is the error returned by [Context.Err] when the context's\n deadline passes.", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "doc", + "context.DeadlineExceeded" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypejs", + "duration": "1.615876042s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go doc context.DeadlineExceeded\n\npackage context // import \u0026#34;context\u0026#34;\n\nvar DeadlineExceeded error = deadlineExceededError{}\n DeadlineExceeded is the error returned by [Context.Err] when the context\u0026#39;s\n deadline passes.", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "package context // import \"context\"\n\nvar DeadlineExceeded error = deadlineExceededError{}\n DeadlineExceeded is the error returned by [Context.Err] when the context's\n deadline passes.", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd data-go-version=\"go1.22.0\" doc=\"context.DeadlineExceeded\" exec=\"go doc context.DeadlineExceeded\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.36:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "The ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#DeadlineExceeded", + "href": "https://pkg.go.dev/context#DeadlineExceeded", + "target": "_blank" + }, + "filename": "errors", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "for", + "Val": "context#DeadlineExceeded" + }, + { + "Namespace": "", + "Key": "href", + "Val": "https://pkg.go.dev/context#DeadlineExceeded" + }, + { + "Namespace": "", + "Key": "target", + "Val": "_blank" + } + ], + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.DeadlineExceeded", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ] + ], + "tag": "\u003ca for=\"context#DeadlineExceeded\" href=\"https://pkg.go.dev/context#DeadlineExceeded\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#DeadlineExceeded" + } + ], + { + "text": " ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "builtin#error", + "href": "https://pkg.go.dev/builtin#error", + "target": "_blank" + }, + "filename": "errors", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "for", + "Val": "builtin#error" + }, + { + "Namespace": "", + "Key": "href", + "Val": "https://pkg.go.dev/builtin#error" + }, + { + "Namespace": "", + "Key": "target", + "Val": "_blank" + } + ], + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "error", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ] + ], + "tag": "\u003ca for=\"builtin#error\" href=\"https://pkg.go.dev/builtin#error\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/builtin#error" + } + ], + { + "text": ".", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 36, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-36\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "errors.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Consider ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-37" + }, + "filename": "errors.md", + "html_node": { + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-37" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.37", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-37\"\u003e", + "type": "hype.Link", + "url": "#listing-1-37" + } + ], + "tag": "\u003cref id=\"listing-1-37\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ". We create a ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "errors.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "errors.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": " that will self cancel after 1 second. When we check ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context.Err", + "href": "https://pkg.go.dev/context#Context.Err", + "target": "_blank" + }, + "filename": "errors.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "errors.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context.Err", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context.Err\" href=\"https://pkg.go.dev/context#Context.Err\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context.Err" + } + ], + { + "text": " method, before the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "errors.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "errors.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": " times out, it returns ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "errors.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "nil", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": ".", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-37", + "type": "listing" + }, + "filename": "errors.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "exceeded.example" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + { + "atom": "pre", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "src": "errors/src/deadline/main.go#example" + }, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/deadline/main.go#example" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "content": "func main() {\n\n\t// create a background context\n\tctx := context.Background()\n\n\t// wrap the context that will\n\t// self cancel after 10 milliseconds\n\tctx, cancel := context.WithTimeout(ctx, 10*time.Millisecond)\n\tdefer cancel()\n\n\t// check the error:\n\t//\t\u003cnil\u003e\n\tfmt.Println(\"ctx.Err()\", ctx.Err())\n\n\t// wait for the context to self cancel\n\t\u003c-ctx.Done()\n\n\t// check the error:\n\t//\tcontext.Canceled\n\tfmt.Println(\"ctx.Err()\", ctx.Err())\n\n\t// check the error again:\n\t//\tcontext.DeadlineExceeded\n\tfmt.Println(\"ctx.Err()\", ctx.Err())\n}", + "file": "errors/src/deadline/main.go", + "lang": "go", + "name": "example", + "start": 9, + "end": 36 + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" src=\"errors/src/deadline/main.go#example\"\u003e", + "type": "hype.SourceCode" + } + ] + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + }, + { + "atom": "hr", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "hr", + "data_atom": "hr", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [], + "tag": "\u003chr\u003e", + "type": "hype.Element" + }, + [ + { + "args": [ + "go", + "run", + "." + ], + "atom": "cmd", + "attributes": { + "data-go-version": "go1.22.0", + "exec": "go run .", + "run": ".", + "src": "errors/src/deadline" + }, + "expected_exit": 0, + "filename": "errors", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "data-go-version", + "Val": "go1.22.0" + }, + { + "Namespace": "", + "Key": "exec", + "Val": "go run ." + }, + { + "Namespace": "", + "Key": "run", + "Val": "." + }, + { + "Namespace": "", + "Key": "src", + "Val": "src/deadline" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "run", + "." + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/12-context/errors/src/deadline", + "duration": "2.1003655s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go run .\n\nctx.Err() \u0026lt;nil\u0026gt;\nctx.Err() context deadline exceeded\nctx.Err() context deadline exceeded", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "ctx.Err() \u003cnil\u003e\nctx.Err() context deadline exceeded\nctx.Err() context deadline exceeded", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "run", + "." + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/12-context/errors/src/deadline", + "duration": "2.1003655s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go run .\n\nctx.Err() \u0026lt;nil\u0026gt;\nctx.Err() context deadline exceeded\nctx.Err() context deadline exceeded", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "ctx.Err() \u003cnil\u003e\nctx.Err() context deadline exceeded\nctx.Err() context deadline exceeded", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd data-go-version=\"go1.22.0\" exec=\"go run .\" run=\".\" src=\"errors/src/deadline\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "errors", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.37:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "Checking for deadline exceeded errors.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 37, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-37\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "errors.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "As we can see from the output, the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "errors.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "errors.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": " times out after the specified time, and the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context.Err", + "href": "https://pkg.go.dev/context#Context.Err", + "target": "_blank" + }, + "filename": "errors.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "errors.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context.Err", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context.Err\" href=\"https://pkg.go.dev/context#Context.Err\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context.Err" + } + ], + { + "text": " method returns a ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#DeadlineExceeded", + "href": "https://pkg.go.dev/context#DeadlineExceeded", + "target": "_blank" + }, + "filename": "errors.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "errors.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.DeadlineExceeded", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#DeadlineExceeded\" href=\"https://pkg.go.dev/context#DeadlineExceeded\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#DeadlineExceeded" + } + ], + { + "text": " error.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "tag": "\u003cpage\u003e", + "title": "Context Errors", + "type": "hype.Page" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "tag": "\u003cinclude src=\"errors/errors.md\"\u003e", + "type": "hype.Include" + } + ], + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "atom": "include", + "attributes": { + "src": "signals/signals.md" + }, + "dir": "signals", + "filename": "module.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "signals/signals.md" + } + ], + "data": "include", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "page", + "attributes": {}, + "filename": "signals.md", + "html_node": { + "data": "page", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "atom": "h1", + "attributes": {}, + "filename": "signals.md", + "html_node": { + "data": "h1", + "data_atom": "h1", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "level": 1, + "nodes": [ + { + "text": "Listening for System Signals with Context", + "type": "hype.Text" + } + ], + "tag": "\u003ch1\u003e", + "type": "hype.Heading" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "signals.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Previously, when discussing channels, we saw how to capture system signals, such as ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "signals.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "ctrl-c", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": ", using ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "os/signal#Notify", + "href": "https://pkg.go.dev/os/signal#Notify", + "target": "_blank" + }, + "filename": "signals.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "signals.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "signal.Notify", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"os/signal#Notify\" href=\"https://pkg.go.dev/os/signal#Notify\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/os/signal#Notify" + } + ], + { + "text": ". The ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "os/signal#NotifyContext", + "href": "https://pkg.go.dev/os/signal#NotifyContext", + "target": "_blank" + }, + "filename": "signals.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "signals.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "signal.NotifyContext", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"os/signal#NotifyContext\" href=\"https://pkg.go.dev/os/signal#NotifyContext\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/os/signal#NotifyContext" + } + ], + { + "text": " function, ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-38" + }, + "filename": "signals.md", + "html_node": { + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-38" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.38", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-38\"\u003e", + "type": "hype.Link", + "url": "#listing-1-38" + } + ], + "tag": "\u003cref id=\"listing-1-38\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ", is a variant of ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "os/signal#Notify", + "href": "https://pkg.go.dev/os/signal#Notify", + "target": "_blank" + }, + "filename": "signals.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "signals.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "signal.Notify", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"os/signal#Notify\" href=\"https://pkg.go.dev/os/signal#Notify\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/os/signal#Notify" + } + ], + { + "text": " that takes a ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "signals.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "signals.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": " as an argument. In return, we are given a ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "signals.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "signals.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": " that will be canceled when the signal is received.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-38", + "type": "listing" + }, + "filename": "signals.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "notify.doc" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "args": [ + "go", + "doc", + "os/signal.NotifyContext" + ], + "atom": "cmd", + "attributes": { + "data-go-version": "go1.22.0", + "doc": "os/signal.NotifyContext", + "exec": "go doc os/signal.NotifyContext" + }, + "expected_exit": 0, + "filename": "signals", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "data-go-version", + "Val": "go1.22.0" + }, + { + "Namespace": "", + "Key": "doc", + "Val": "os/signal.NotifyContext" + }, + { + "Namespace": "", + "Key": "exec", + "Val": "go doc os/signal.NotifyContext" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "doc", + "os/signal.NotifyContext" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypejs", + "duration": "1.466130459s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go doc os/signal.NotifyContext\n\npackage signal // import \u0026#34;os/signal\u0026#34;\n\nfunc NotifyContext(parent context.Context, signals ...os.Signal) (ctx context.Context, stop context.CancelFunc)\n NotifyContext returns a copy of the parent context that is marked done (its\n Done channel is closed) when one of the listed signals arrives, when the\n returned stop function is called, or when the parent context\u0026#39;s Done channel\n is closed, whichever happens first.\n\n The stop function unregisters the signal behavior, which, like signal.Reset,\n may restore the default behavior for a given signal. For example,\n the default behavior of a Go program receiving os.Interrupt is to exit.\n Calling NotifyContext(parent, os.Interrupt) will change the behavior to\n cancel the returned context. Future interrupts received will not trigger the\n default (exit) behavior until the returned stop function is called.\n\n The stop function releases resources associated with it, so code should call\n stop as soon as the operations running in this Context complete and signals\n no longer need to be diverted to the context.", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "package signal // import \"os/signal\"\n\nfunc NotifyContext(parent context.Context, signals ...os.Signal) (ctx context.Context, stop context.CancelFunc)\n NotifyContext returns a copy of the parent context that is marked done (its\n Done channel is closed) when one of the listed signals arrives, when the\n returned stop function is called, or when the parent context's Done channel\n is closed, whichever happens first.\n\n The stop function unregisters the signal behavior, which, like signal.Reset,\n may restore the default behavior for a given signal. For example,\n the default behavior of a Go program receiving os.Interrupt is to exit.\n Calling NotifyContext(parent, os.Interrupt) will change the behavior to\n cancel the returned context. Future interrupts received will not trigger the\n default (exit) behavior until the returned stop function is called.\n\n The stop function releases resources associated with it, so code should call\n stop as soon as the operations running in this Context complete and signals\n no longer need to be diverted to the context.", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "doc", + "os/signal.NotifyContext" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypejs", + "duration": "1.466130459s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go doc os/signal.NotifyContext\n\npackage signal // import \u0026#34;os/signal\u0026#34;\n\nfunc NotifyContext(parent context.Context, signals ...os.Signal) (ctx context.Context, stop context.CancelFunc)\n NotifyContext returns a copy of the parent context that is marked done (its\n Done channel is closed) when one of the listed signals arrives, when the\n returned stop function is called, or when the parent context\u0026#39;s Done channel\n is closed, whichever happens first.\n\n The stop function unregisters the signal behavior, which, like signal.Reset,\n may restore the default behavior for a given signal. For example,\n the default behavior of a Go program receiving os.Interrupt is to exit.\n Calling NotifyContext(parent, os.Interrupt) will change the behavior to\n cancel the returned context. Future interrupts received will not trigger the\n default (exit) behavior until the returned stop function is called.\n\n The stop function releases resources associated with it, so code should call\n stop as soon as the operations running in this Context complete and signals\n no longer need to be diverted to the context.", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "package signal // import \"os/signal\"\n\nfunc NotifyContext(parent context.Context, signals ...os.Signal) (ctx context.Context, stop context.CancelFunc)\n NotifyContext returns a copy of the parent context that is marked done (its\n Done channel is closed) when one of the listed signals arrives, when the\n returned stop function is called, or when the parent context's Done channel\n is closed, whichever happens first.\n\n The stop function unregisters the signal behavior, which, like signal.Reset,\n may restore the default behavior for a given signal. For example,\n the default behavior of a Go program receiving os.Interrupt is to exit.\n Calling NotifyContext(parent, os.Interrupt) will change the behavior to\n cancel the returned context. Future interrupts received will not trigger the\n default (exit) behavior until the returned stop function is called.\n\n The stop function releases resources associated with it, so code should call\n stop as soon as the operations running in this Context complete and signals\n no longer need to be diverted to the context.", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd data-go-version=\"go1.22.0\" doc=\"os/signal.NotifyContext\" exec=\"go doc os/signal.NotifyContext\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "signals", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.38:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "The ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "os/signal#NotifyContext", + "href": "https://pkg.go.dev/os/signal#NotifyContext", + "target": "_blank" + }, + "filename": "signals", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "for", + "Val": "os/signal#NotifyContext" + }, + { + "Namespace": "", + "Key": "href", + "Val": "https://pkg.go.dev/os/signal#NotifyContext" + }, + { + "Namespace": "", + "Key": "target", + "Val": "_blank" + } + ], + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": {}, + "filename": "signals", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "signal.NotifyContext", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ] + ], + "tag": "\u003ca for=\"os/signal#NotifyContext\" href=\"https://pkg.go.dev/os/signal#NotifyContext\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/os/signal#NotifyContext" + } + ], + { + "text": " function.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 38, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-38\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "signals.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Consider ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-39" + }, + "filename": "signals.md", + "html_node": { + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-39" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.39", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-39\"\u003e", + "type": "hype.Link", + "url": "#listing-1-39" + } + ], + "tag": "\u003cref id=\"listing-1-39\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ". We use ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "os/signal#NotifyContext", + "href": "https://pkg.go.dev/os/signal#NotifyContext", + "target": "_blank" + }, + "filename": "signals.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "signals.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "signal.NotifyContext", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"os/signal#NotifyContext\" href=\"https://pkg.go.dev/os/signal#NotifyContext\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/os/signal#NotifyContext" + } + ], + { + "text": " to listen for ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "signals.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "ctrl-c", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": ". This function returns a wrapped ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "signals.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "signals.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": " that will cancel when the signal is received. It also returns a ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#CancelFunc", + "href": "https://pkg.go.dev/context#CancelFunc", + "target": "_blank" + }, + "filename": "signals.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "signals.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.CancelFunc", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#CancelFunc\" href=\"https://pkg.go.dev/context#CancelFunc\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#CancelFunc" + } + ], + { + "text": " that can be used to cancel ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "signals.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "signals.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": " when needed.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-39", + "type": "listing" + }, + "filename": "signals.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "signals.example" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + { + "atom": "pre", + "attributes": {}, + "filename": "signals", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "src": "signals/src/signals/main.go#example" + }, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/signals/main.go#example" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "content": "func main() {\n\n\t// create a background context\n\tctx := context.Background()\n\n\t// wrap the context with a timeout\n\t// of 50 milliseconds to ensure the application\n\t// will eventually exit\n\tctx, cancel := context.WithTimeout(ctx, 50*time.Millisecond)\n\tdefer cancel()\n\n\t// wrap the context with a context\n\t// that will be cancelled when an\n\t// interrupt signal is received (ctrl-c)\n\tctx, cancel = signal.NotifyContext(ctx, os.Interrupt)\n\tdefer cancel()\n\n\t// lauch a goroutine that will\n\t// trigger an interrupt signal\n\t// after 10 milliseconds (ctrl-c)\n\tgo func() {\n\t\ttime.Sleep(10 * time.Millisecond)\n\n\t\tfmt.Println(\"sending ctrl-c\")\n\n\t\t// send the interrupt signal\n\t\t// to the current process\n\t\tsyscall.Kill(syscall.Getpid(), syscall.SIGINT)\n\t}()\n\n\tfmt.Println(\"waiting for context to finish\")\n\n\t// wait for the context to finish\n\t\u003c-ctx.Done()\n\n\tfmt.Printf(\"context finished: %v\\n\", ctx.Err())\n\n}", + "file": "signals/src/signals/main.go", + "lang": "go", + "name": "example", + "start": 12, + "end": 52 + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" src=\"signals/src/signals/main.go#example\"\u003e", + "type": "hype.SourceCode" + } + ] + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + }, + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "signals", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.39:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "Listening for system signals.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 39, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-39\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "h2", + "attributes": {}, + "filename": "signals.md", + "html_node": { + "data": "h2", + "data_atom": "h2", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "level": 2, + "nodes": [ + { + "text": "Testing Signals", + "type": "hype.Text" + } + ], + "tag": "\u003ch2\u003e", + "type": "hype.Heading" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "signals.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Testing system signals is tricky and care must be taken not to accidentally exit your running tests. Unfortunately, the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "syscall", + "href": "https://pkg.go.dev/syscall", + "target": "_blank" + }, + "filename": "signals.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "signals.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "syscall", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"syscall\" href=\"https://pkg.go.dev/syscall\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/syscall" + } + ], + { + "text": " package does not provide a \"test\" signal, or a way to implement a test signal.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "signals.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "We can use ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "syscall#SIGUSR1", + "href": "https://pkg.go.dev/syscall#SIGUSR1", + "target": "_blank" + }, + "filename": "signals.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "signals.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "syscall.SIGUSR1", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"syscall#SIGUSR1\" href=\"https://pkg.go.dev/syscall#SIGUSR1\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/syscall#SIGUSR1" + } + ], + { + "text": " or ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "syscall#SIGUSR2", + "href": "https://pkg.go.dev/syscall#SIGUSR2", + "target": "_blank" + }, + "filename": "signals.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "signals.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "syscall.SIGUSR2", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"syscall#SIGUSR2\" href=\"https://pkg.go.dev/syscall#SIGUSR2\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/syscall#SIGUSR2" + } + ], + { + "text": " in our tests as these are allocated to the developer to use for their own purposes.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "signals.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "When we are testing signals, we are testing a ", + "type": "hype.Text" + }, + { + "atom": "strong", + "attributes": {}, + "filename": "signals.md", + "html_node": { + "data": "strong", + "data_atom": "strong", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "global", + "type": "hype.Text" + } + ], + "tag": "\u003cstrong\u003e", + "type": "hype.Element" + }, + { + "text": " signal, that will caught by anyone else who is listening to that signal. Because of this we want to make that when testing signals we aren't running the tests in parallel and that we don't have other tests also listening to the same signal.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "signals.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Consider ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-40" + }, + "filename": "signals.md", + "html_node": { + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-40" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.40", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-40\"\u003e", + "type": "hype.Link", + "url": "#listing-1-40" + } + ], + "tag": "\u003cref id=\"listing-1-40\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ". How do we test that the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "signals.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listener", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " function will respond properly to a signal? We don't want to make that the responsibility of the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "signals.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listener", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " function, it already has a ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "signals.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "signals.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": " that it can listen to for cancellation. The ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "signals.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listener", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " function doesn't care why it was told to stop listening, it just needs to stop listening. This could be because we receive an interrupt signal, because a deadline has passed, or because the application no longer needs the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "signals.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Lister", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " function to keep running.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-40", + "type": "listing" + }, + "filename": "signals.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "testing.func" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + { + "atom": "pre", + "attributes": {}, + "filename": "signals", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "src": "signals/src/testing/signals_test.go#func" + }, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/testing/signals_test.go#func" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "content": "func Listener(ctx context.Context, t testing.TB) {\n\tt.Log(\"waiting for context to finish\")\n\n\t// wait for the context to finish\n\t\u003c-ctx.Done()\n\n}", + "file": "signals/src/testing/signals_test.go", + "lang": "go", + "name": "func", + "start": 13, + "end": 22 + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" src=\"signals/src/testing/signals_test.go#func\"\u003e", + "type": "hype.SourceCode" + } + ] + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + }, + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "signals", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.40:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "The ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "signals", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listener", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " function.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 40, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-40\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "signals.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "In, ", + "type": "hype.Text" + }, + [ + { + "atom": "ref", + "attributes": { + "id": "listing-1-41" + }, + "filename": "signals.md", + "html_node": { + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "a", + "attributes": { + "href": "#listing-1-41" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.41", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"#listing-1-41\"\u003e", + "type": "hype.Link", + "url": "#listing-1-41" + } + ], + "tag": "\u003cref id=\"listing-1-41\"\u003e", + "type": "hype.Ref" + } + ], + { + "text": ", before we call the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "signals.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listener", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " function, we first create a ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "signals.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "signals.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": " that will self-cancel after 5 seconds if nothing else happens. We then wrap that ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "signals.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "signals.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": " with one received from the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "os/signal#NotifyContext", + "href": "https://pkg.go.dev/os/signal#NotifyContext", + "target": "_blank" + }, + "filename": "signals.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "signals.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "signal.NotifyContext", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"os/signal#NotifyContext\" href=\"https://pkg.go.dev/os/signal#NotifyContext\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/os/signal#NotifyContext" + } + ], + { + "text": " function, that will self-cancel when the system receives a ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "signals.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "TEST_SIGNAL", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " signal.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "signals.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Our test blocks with a ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "signals.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "select", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " waiting for either ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "signals.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "signals.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": " to be cancelled, and then respond accordingly.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-41", + "type": "listing" + }, + "filename": "signals.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "testing.example" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + { + "atom": "pre", + "attributes": {}, + "filename": "signals", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "src": "signals/src/testing/signals_test.go#example" + }, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/testing/signals_test.go#example" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "content": "// use syscall.SIGUSR2 to test\nconst TEST_SIGNAL = syscall.SIGUSR2\n\nfunc Test_Signals(t *testing.T) {\n\n\t// create a background context\n\tctx := context.Background()\n\n\t// wrap the context with a context\n\t// that will self cancel after 5 seconds\n\t// if the context is not finished\n\tctx, cancel := context.WithTimeout(ctx, 5*time.Second)\n\tdefer cancel()\n\n\t// wrap the context with a context\n\t// that will self cancel if the system\n\t// receives a TEST_SIGNAL\n\tsigCtx, cancel := signal.NotifyContext(ctx, TEST_SIGNAL)\n\tdefer cancel()\n\n\tprint(t, sigCtx)\n\n\t// launch a goroutine to wait for the context\n\t// to finish\n\tgo Listener(sigCtx, t)\n\n\t// launch a goroutine to send a TEST_SIGNAL\n\t// to the system after 1 second\n\tgo func() {\n\t\ttime.Sleep(time.Second)\n\n\t\tt.Log(\"sending test signal\")\n\n\t\t// send the TEST_SIGNAL to the system\n\t\tsyscall.Kill(syscall.Getpid(), TEST_SIGNAL)\n\t}()\n\n\t// wait for the context to finish\n\tselect {\n\tcase \u003c-ctx.Done():\n\t\tt.Log(\"context finished\")\n\tcase \u003c-sigCtx.Done():\n\t\tt.Log(\"signal received\")\n\t\tt.Log(\"successfully completed\")\n\t\treturn\n\t}\n\n\terr := ctx.Err()\n\tif err == nil {\n\t\treturn\n\t}\n\n\t// if we receive a DeadlineExceeded error then\n\t// the context timed out and the signal was never\n\t// received.\n\tif err == context.DeadlineExceeded {\n\t\tt.Fatal(\"unexpected error\", err)\n\t}\n\n}", + "file": "signals/src/testing/signals_test.go", + "lang": "go", + "name": "example", + "start": 24, + "end": 89 + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" src=\"signals/src/testing/signals_test.go#example\"\u003e", + "type": "hype.SourceCode" + } + ] + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + }, + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "signals", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.41:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "Testing the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "signals", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listener", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " function.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 41, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-41\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "signals.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Inside the test, in a goroutine, we can trigger the ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "signals.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "TEST_SIGNAL", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " signal by sending it to the current process, ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "syscall#Getpid", + "href": "https://pkg.go.dev/syscall#Getpid", + "target": "_blank" + }, + "filename": "signals.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "signals.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "syscall.Getpid", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"syscall#Getpid\" href=\"https://pkg.go.dev/syscall#Getpid\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/syscall#Getpid" + } + ], + { + "text": ", with the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "syscall#Kill", + "href": "https://pkg.go.dev/syscall#Kill", + "target": "_blank" + }, + "filename": "signals.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "signals.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "syscall.Kill", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"syscall#Kill\" href=\"https://pkg.go.dev/syscall#Kill\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/syscall#Kill" + } + ], + { + "text": " function.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figure", + "attributes": { + "id": "listing-1-42", + "type": "listing" + }, + "filename": "signals.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "id", + "Val": "testing.kill" + }, + { + "Namespace": "", + "Key": "type", + "Val": "listing" + } + ], + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + { + "atom": "pre", + "attributes": {}, + "filename": "signals", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "code", + "attributes": { + "class": "language-go", + "language": "go", + "src": "signals/src/testing/signals_test.go#kill" + }, + "filename": "", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/testing/signals_test.go#kill" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "content": "// launch a goroutine to send a TEST_SIGNAL\n// to the system after 1 second\ngo func() {\n\ttime.Sleep(time.Second)\n\n\tt.Log(\"sending test signal\")\n\n\t// send the TEST_SIGNAL to the system\n\tsyscall.Kill(syscall.Getpid(), TEST_SIGNAL)\n}()", + "file": "signals/src/testing/signals_test.go", + "lang": "go", + "name": "kill", + "start": 52, + "end": 63 + } + ], + "tag": "\u003ccode class=\"language-go\" language=\"go\" src=\"signals/src/testing/signals_test.go#kill\"\u003e", + "type": "hype.SourceCode" + } + ] + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + }, + { + "atom": "hr", + "attributes": {}, + "filename": "signals", + "html_node": { + "data": "hr", + "data_atom": "hr", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [], + "tag": "\u003chr\u003e", + "type": "hype.Element" + }, + [ + { + "args": [ + "go", + "test", + "-v" + ], + "atom": "cmd", + "attributes": { + "data-go-version": "go1.22.0", + "exec": "go test -v", + "src": "signals/src/testing", + "test": "-v" + }, + "expected_exit": 0, + "filename": "signals", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "data-go-version", + "Val": "go1.22.0" + }, + { + "Namespace": "", + "Key": "exec", + "Val": "go test -v" + }, + { + "Namespace": "", + "Key": "src", + "Val": "src/testing" + }, + { + "Namespace": "", + "Key": "test", + "Val": "-v" + } + ], + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "args": [ + "go", + "test", + "-v" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/12-context/signals/src/testing", + "duration": "5.893321459s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go test -v\n\n=== RUN Test_Signals\n signals_test.go:46: SignalCtx([]os.Signal{31})\n \t--\u0026gt; WithCancel\n \t\t--\u0026gt; WithTimeout(deadline: {wall:13937916062423232528 ext:5000742917 loc:0x10097cf60})\n \t\t\t--\u0026gt; context.backgroundCtx\n signals_test.go:15: waiting for context to finish\n signals_test.go:58: sending test signal\n signals_test.go:70: signal received\n signals_test.go:71: successfully completed\n--- PASS: Test_Signals (1.00s)\nPASS\nok \tdemo\t3.765s", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "=== RUN Test_Signals\n signals_test.go:46: SignalCtx([]os.Signal{31})\n \t--\u003e WithCancel\n \t\t--\u003e WithTimeout(deadline: {wall:13937916062423232528 ext:5000742917 loc:0x10097cf60})\n \t\t\t--\u003e context.backgroundCtx\n signals_test.go:15: waiting for context to finish\n signals_test.go:58: sending test signal\n signals_test.go:70: signal received\n signals_test.go:71: successfully completed\n--- PASS: Test_Signals (1.00s)\nPASS\nok \tdemo\t3.765s", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + } + ], + "result": { + "args": [ + "go", + "test", + "-v" + ], + "atom": "result", + "attributes": {}, + "dir": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/12-context/signals/src/testing", + "duration": "5.893321459s", + "err": null, + "exit": 0, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "pre", + "attributes": {}, + "filename": "", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-shell", + "language": "shell" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "shell", + "nodes": [ + { + "text": "$ go test -v\n\n=== RUN Test_Signals\n signals_test.go:46: SignalCtx([]os.Signal{31})\n \t--\u0026gt; WithCancel\n \t\t--\u0026gt; WithTimeout(deadline: {wall:13937916062423232528 ext:5000742917 loc:0x10097cf60})\n \t\t\t--\u0026gt; context.backgroundCtx\n signals_test.go:15: waiting for context to finish\n signals_test.go:58: sending test signal\n signals_test.go:70: signal received\n signals_test.go:71: successfully completed\n--- PASS: Test_Signals (1.00s)\nPASS\nok \tdemo\t3.765s", + "type": "hype.Text" + }, + { + "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.22.0\n", + "type": "hype.Text" + } + ], + "tag": "\u003ccode class=\"language-shell\" language=\"shell\"\u003e", + "type": "hype.FencedCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + "stderr": "", + "stdout": "=== RUN Test_Signals\n signals_test.go:46: SignalCtx([]os.Signal{31})\n \t--\u003e WithCancel\n \t\t--\u003e WithTimeout(deadline: {wall:13937916062423232528 ext:5000742917 loc:0x10097cf60})\n \t\t\t--\u003e context.backgroundCtx\n signals_test.go:15: waiting for context to finish\n signals_test.go:58: sending test signal\n signals_test.go:70: signal received\n signals_test.go:71: successfully completed\n--- PASS: Test_Signals (1.00s)\nPASS\nok \tdemo\t3.765s", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd data-go-version=\"go1.22.0\" exec=\"go test -v\" src=\"signals/src/testing\" test=\"-v\"\u003e", + "timeout": "30s", + "type": "hype.Cmd" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "figcaption", + "attributes": {}, + "filename": "signals", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "em", + "attributes": { + "class": "figure-name" + }, + "filename": "", + "html_node": { + "data": "em", + "data_atom": "em", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Listing 1.42:", + "type": "hype.Text" + } + ], + "tag": "\u003cem class=\"figure-name\"\u003e", + "type": "hype.Element" + }, + { + "text": " ", + "type": "hype.Text" + }, + { + "text": "Sending a ", + "type": "hype.Text" + }, + [ + { + "atom": "code", + "attributes": {}, + "filename": "signals", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "TEST_SIGNAL", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + { + "text": " signal.", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "pos": 42, + "section_id": 1, + "style": "listing", + "tag": "\u003cfigure id=\"listing-1-42\" type=\"listing\"\u003e", + "type": "hype.Figure" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "tag": "\u003cpage\u003e", + "title": "Listening for System Signals with Context", + "type": "hype.Page" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "tag": "\u003cinclude src=\"signals/signals.md\"\u003e", + "type": "hype.Include" + } + ], + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "atom": "page", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "page", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "atom": "h1", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "h1", + "data_atom": "h1", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "level": 1, + "nodes": [ + { + "text": "Summary", + "type": "hype.Text" + } + ], + "tag": "\u003ch1\u003e", + "type": "hype.Heading" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "p", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "In this ", + "type": "hype.Text" + }, + { + "atom": "binding", + "attributes": { + "part": "" + }, + "filename": "module.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "part", + "Val": "" + } + ], + "data": "binding", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [], + "tag": "\u003cbinding part=\"\"\u003e", + "type": "hype.Element" + }, + { + "text": " we explore the concept of contexts in Go. We learn that contexts are a way to manage cancellation, timeouts, and other request-scoped values across API boundaries and between processes. We also learn how to use contexts to clean up a lot of code involving channels, such as listening for system signals. We discussed the nodal hierarchy of how the ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context", + "href": "https://pkg.go.dev/context", + "target": "_blank" + }, + "filename": "module.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context\" href=\"https://pkg.go.dev/context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context" + } + ], + { + "text": " package wraps a new ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "module.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": " around a parent ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "module.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": ". We learned the different was to cancel a ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "module.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": " and how to use multiple ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context#Context", + "href": "https://pkg.go.dev/context#Context", + "target": "_blank" + }, + "filename": "module.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context.Context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context#Context\" href=\"https://pkg.go.dev/context#Context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context#Context" + } + ], + { + "text": "s to confirm shutdown behavior. The ", + "type": "hype.Text" + }, + [ + { + "atom": "a", + "attributes": { + "for": "context", + "href": "https://pkg.go.dev/context", + "target": "_blank" + }, + "filename": "module.md", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "context", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" + } + ], + "tag": "\u003ca for=\"context\" href=\"https://pkg.go.dev/context\" target=\"_blank\"\u003e", + "type": "hype.Link", + "url": "https://pkg.go.dev/context" + } + ], + { + "text": " package, while small, is a very powerful tool for managing concurrency in your application.", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "tag": "\u003cpage\u003e", + "title": "Summary", + "type": "hype.Page" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "tag": "\u003cbody\u003e", + "type": "hype.Body" + } + ] + ], + "tag": "\u003chtml\u003e", + "type": "hype.Element" + } + ], + "tag": "", + "type": "hype.Element" + } + ], + "parser": { + "type": "hype.Parser", + "root": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/12-context", + "section": 1, + "contents": "# Context\n\nIntroduced in Go 1.7, the \u003cgodoc\u003econtext\u003c/godoc\u003e package was introduced to provide a cleaner way, than the use of channels, of managing cancellation and timeouts across goroutines.\n\nWhile the scope, and API footprint of the package is pretty small, it was a welcome addition to the language when introduced.\n\nThe \u003cgodoc\u003econtext\u003c/godoc\u003e package, \u003cref\u003econtext\u003c/ref\u003e, defines the \u003cgodoc\u003econtext#Context\u003c/godoc\u003e type, which carries deadlines, cancellation signals, and other request-scoped values across API boundaries and between processes.\n\nContext is, mostly, used for controlling concurrent subsystems in your application. This week we will cover the different kinds of behavior with contexts including canceling, timeouts, and values. We'll also see how we can clean up a lot of code involving channels by using contexts.\n\n\u003cfigure id=\"context\" type=\"listing\"\u003e\n\n\u003cgo doc=\"-short context\"\u003e\u003c/go\u003e\n\n\u003cfigcaption\u003eThe \u003cgodoc\u003econtext\u003c/godoc\u003e package.\u003c/figcaption\u003e\n\n\u003c/figure\u003e\n\n\u003cinclude src=\"basics/basics.md\"\u003e\u003c/include\u003e\n\n\u003cinclude src=\"rules/rules.md\"\u003e\u003c/include\u003e\n\n\u003cinclude src=\"nodes/nodes.md\"\u003e\u003c/include\u003e\n\n\u003cinclude src=\"values/values.md\"\u003e\u003c/include\u003e\n\n\u003cinclude src=\"cancellation/cancellation.md\"\u003e\u003c/include\u003e\n\n\u003cinclude src=\"timeouts/timeouts.md\"\u003e\u003c/include\u003e\n\n\u003cinclude src=\"errors/errors.md\"\u003e\u003c/include\u003e\n\n\u003cinclude src=\"signals/signals.md\"\u003e\u003c/include\u003e\n\n# Summary\n\nIn this \u003cbinding part\u003e\u003c/binding\u003e we explore the concept of contexts in Go. We learn that contexts are a way to manage cancellation, timeouts, and other request-scoped values across API boundaries and between processes. We also learn how to use contexts to clean up a lot of code involving channels, such as listening for system signals. We discussed the nodal hierarchy of how the \u003cgodoc\u003econtext\u003c/godoc\u003e package wraps a new \u003cgodoc\u003econtext#Context\u003c/godoc\u003e around a parent \u003cgodoc\u003econtext#Context\u003c/godoc\u003e. We learned the different was to cancel a \u003cgodoc\u003econtext#Context\u003c/godoc\u003e and how to use multiple \u003cgodoc\u003econtext#Context\u003c/godoc\u003es to confirm shutdown behavior. The \u003cgodoc\u003econtext\u003c/godoc\u003e package, while small, is a very powerful tool for managing concurrency in your application.\n" + }, + "root": "/Users/markbates/Dropbox/dev/guides/content/book/chapters/12-context", + "section_id": 1, + "snippets": { + "rules": { + ".go": "// %s", + ".html": "\u003c!-- %s --\u003e", + ".js": "// %s", + ".md": "\u003c!-- %s --\u003e", + ".rb": "# %s", + ".ts": "// %s" + }, + "snippets": { + "basics/src/background/empty/main.go": { + "example": { + "content": "func main() {\n\tctx := context.Background()\n\n\t// print the current value\n\t// of the context\n\tfmt.Printf(\"%v\\n\", ctx)\n\n\t// print Go-syntax representation of the value\n\tfmt.Printf(\"\\t%#v\\n\", ctx)\n}", + "file": "basics/src/background/empty/main.go", + "lang": "go", + "name": "example", + "start": 8, + "end": 20 + }, + "out": { + "content": "context.Background\n\t(*context.emptyCtx)(0xc000016100)", + "file": "basics/src/background/empty/main.go", + "lang": "go", + "name": "out", + "start": 23, + "end": 26 + } + }, + "basics/src/background/implementation/main.go": { + "example": { + "content": "func main() {\n\tctx := context.Background()\n\n\t// print the current value\n\t// of the context\n\tfmt.Printf(\"%v\\n\", ctx)\n\n\t// print Go-syntax representation of the value\n\tfmt.Printf(\"\\t%#v\\n\", ctx)\n\n\t// print the value of the Done channel\n\t// does not block because we are not\n\t// trying to read/write to the channel\n\tfmt.Printf(\"\\tDone:\\t%#v\\n\", ctx.Done())\n\n\t// print the value of the Err\n\tfmt.Printf(\"\\tErr:\\t%#v\\n\", ctx.Err())\n\n\t// print the value of \"KEY\"\n\tfmt.Printf(\"\\tValue:\\t%#v\\n\", ctx.Value(\"KEY\"))\n\n\t// print the deadline time\n\t// and true/false if there is no deadline\n\tdeadline, ok := ctx.Deadline()\n\tfmt.Printf(\"\\tDeadline:\\t%s (%t)\\n\", deadline, ok)\n}", + "file": "basics/src/background/implementation/main.go", + "lang": "go", + "name": "example", + "start": 8, + "end": 36 + }, + "out": { + "content": "context.Background\n\t(*context.emptyCtx)(0xc000016100)\n\tDone:\t(\u003c-chan struct {})(nil)\n\tErr:\t\u003cnil\u003e\n\tValue:\t\u003cnil\u003e\n\tDeadline:\t0001-01-01 00:00:00 +0000 UTC (false)", + "file": "basics/src/background/implementation/main.go", + "lang": "go", + "name": "out", + "start": 39, + "end": 46 + } + }, + "cancellation/src/basic/main.go": { + "listener": { + "content": "func listener(ctx context.Context, i int) {\n\tfmt.Printf(\"listener %d is waiting\\n\", i)\n\n\t// this will block until the context\n\t// given context is canceled\n\t\u003c-ctx.Done()\n\n\tfmt.Printf(\"listener %d is exiting\\n\", i)\n}", + "file": "cancellation/src/basic/main.go", + "lang": "go", + "name": "listener", + "start": 9, + "end": 20 + }, + "main": { + "content": "func main() {\n\n\t// create a background context\n\tctx := context.Background()\n\n\t// wrap the context with the ability\n\t// to cancel it\n\tctx, cancel := context.WithCancel(ctx)\n\n\t// defer cancellation of the context\n\t// to ensure that any resources are\n\t// cleaned up regardless of how the\n\t// function exits\n\tdefer cancel()\n\n\t// create 5 listeners\n\tfor i := 0; i \u003c 5; i++ {\n\n\t\t// launch listener in a goroutine\n\t\tgo listener(ctx, i)\n\n\t}\n\n\t// allow the listeners to start\n\ttime.Sleep(time.Millisecond * 500)\n\n\tfmt.Println(\"canceling the context\")\n\n\t// cancel the context and tell the\n\t// listeners to exit\n\tcancel()\n\n\t// allow the listeners to exit\n\ttime.Sleep(time.Millisecond * 500)\n}", + "file": "cancellation/src/basic/main.go", + "lang": "go", + "name": "main", + "start": 22, + "end": 59 + }, + "out": { + "content": "listener 0 is waiting\nlistener 3 is waiting\nlistener 2 is waiting\nlistener 1 is waiting\nlistener 4 is waiting\ncanceling the context\nlistener 4 is exiting\nlistener 0 is exiting\nlistener 1 is exiting\nlistener 3 is exiting\nlistener 2 is exiting", + "file": "cancellation/src/basic/main.go", + "lang": "go", + "name": "out", + "start": 62, + "end": 74 + } + }, + "cancellation/src/cancelling/main.go": { + "listen": { + "content": "func (m *Monitor) listen(ctx context.Context) {\n\tdefer m.cancel()\n\n\t// create a new ticker channel to listen to\n\ttick := time.NewTicker(time.Millisecond * 10)\n\tdefer tick.Stop()\n\n\t// use an infinite loop to continue to listen\n\t// to new messages after the select statement\n\t// has been executed\n\tfor {\n\t\tselect {\n\t\tcase \u003c-ctx.Done(): // listen for context cancellation\n\t\t\t// shut down if the context is canceled\n\t\t\tfmt.Println(\"shutting down monitor\")\n\n\t\t\t// if the monitor was told to shut down\n\t\t\t// then it should call its cancel function\n\t\t\t// so the client will know that the monitor\n\t\t\t// has properly shut down.\n\t\t\tm.cancel()\n\n\t\t\t// return from the function\n\t\t\treturn\n\t\tcase \u003c-tick.C: // listen to the ticker channel\n\t\t\t// and print a message every time it ticks\n\t\t\tfmt.Println(\"monitor check\")\n\t\t}\n\t}\n\n}", + "file": "cancellation/src/cancelling/main.go", + "lang": "go", + "name": "listen", + "start": 38, + "end": 71 + }, + "main": { + "content": "func main() {\n\n\t// create a new background context\n\tctx := context.Background()\n\n\t// wrap the background context with a\n\t// cancellable context.\n\t// this context can be listened to any\n\t// children of this context for notification\n\t// of application shutdown/cancellation.\n\tctx, cancel := context.WithCancel(ctx)\n\n\t// ensure the cancel function is called\n\t// to shut down the monitor when the program\n\t// is exits\n\tdefer cancel()\n\n\t// launch a goroutine to cancel the application\n\t// context after a short while.\n\tgo func() {\n\t\ttime.Sleep(time.Millisecond * 50)\n\n\t\t// cancel the application context\n\t\t// this will shut the monitor down\n\t\tcancel()\n\t}()\n\n\t// create a new monitor\n\tmon := Monitor{}\n\n\t// start the monitor with the application context\n\t// this will return a context that can be listened to\n\t// for cancellation signaling the monitor has shut down.\n\tctx = mon.Start(ctx)\n\n\t// block the application until either the context\n\t// is canceled or the application times out\n\tselect {\n\tcase \u003c-ctx.Done(): // listen for context cancellation\n\t\t// success shutdown\n\t\tos.Exit(0)\n\tcase \u003c-time.After(time.Second * 2): // timeout after 2 second\n\t\tfmt.Println(\"timed out while trying to shut down the monitor\")\n\n\t\t// check if there was an error from the\n\t\t// monitor's context\n\t\tif err := ctx.Err(); err != nil {\n\t\t\tfmt.Printf(\"error: %s\\n\", err)\n\t\t}\n\n\t\t// non-successful shutdown\n\t\tos.Exit(1)\n\t}\n}", + "file": "cancellation/src/cancelling/main.go", + "lang": "go", + "name": "main", + "start": 73, + "end": 129 + }, + "out": { + "content": "monitor check\nmonitor check\nmonitor check\nmonitor check\nmonitor check\nshutting down monitor", + "file": "cancellation/src/cancelling/main.go", + "lang": "go", + "name": "out", + "start": 132, + "end": 139 + }, + "start": { + "content": "type Monitor struct {\n\tcancel context.CancelFunc\n}\n\nfunc (m *Monitor) Start(ctx context.Context) context.Context {\n\n\t// start the monitor with the given context\n\tgo m.listen(ctx)\n\n\t// create a new context that will be canceled\n\t// when the monitor is shut down\n\tctx, cancel := context.WithCancel(context.Background())\n\n\t// hold on to the cancellation function\n\t// when context that started the manager is canceled\n\t// this cancellation function will be called.\n\tm.cancel = cancel\n\n\t// return the new, cancellable, context.\n\t// clients can listen to this context\n\t// for cancellation to ensure the\n\t// monitor is properly shut down.\n\treturn ctx\n}", + "file": "cancellation/src/cancelling/main.go", + "lang": "go", + "name": "start", + "start": 10, + "end": 36 + } + }, + "errors/src/canceled/main.go": { + "example": { + "content": "func main() {\n\n\t// create a background context\n\tctx := context.Background()\n\n\t// wrap the context with a\n\t// cancellable context\n\tctx, cancel := context.WithCancel(ctx)\n\n\t// check the error:\n\t//\t\u003cnil\u003e\n\tfmt.Println(\"ctx.Err()\", ctx.Err())\n\n\t// cancel the context\n\tcancel()\n\n\t// check the error:\n\t//\tcontext.Canceled\n\tfmt.Println(\"ctx.Err()\", ctx.Err())\n\n\t// check the error again:\n\t//\tcontext.Canceled\n\tfmt.Println(\"ctx.Err()\", ctx.Err())\n}", + "file": "errors/src/canceled/main.go", + "lang": "go", + "name": "example", + "start": 8, + "end": 34 + }, + "out": { + "content": "ctx.Err() \u003cnil\u003e\nctx.Err() context canceled\nctx.Err() context canceled", + "file": "errors/src/canceled/main.go", + "lang": "go", + "name": "out", + "start": 37, + "end": 41 + } + }, + "errors/src/deadline/main.go": { + "example": { + "content": "func main() {\n\n\t// create a background context\n\tctx := context.Background()\n\n\t// wrap the context that will\n\t// self cancel after 10 milliseconds\n\tctx, cancel := context.WithTimeout(ctx, 10*time.Millisecond)\n\tdefer cancel()\n\n\t// check the error:\n\t//\t\u003cnil\u003e\n\tfmt.Println(\"ctx.Err()\", ctx.Err())\n\n\t// wait for the context to self cancel\n\t\u003c-ctx.Done()\n\n\t// check the error:\n\t//\tcontext.Canceled\n\tfmt.Println(\"ctx.Err()\", ctx.Err())\n\n\t// check the error again:\n\t//\tcontext.DeadlineExceeded\n\tfmt.Println(\"ctx.Err()\", ctx.Err())\n}", + "file": "errors/src/deadline/main.go", + "lang": "go", + "name": "example", + "start": 9, + "end": 36 + } + }, + "nodes/src/node-tree/main.go": { + "example": { + "content": "func A(ctx context.Context) {\n\t// wrap ctx with a new context\n\t// with the ID set to \"A\"\n\tA := context.WithValue(ctx, ID, \"A\")\n\tprint(\"A\", A)\n\n\t// pass the A context to the A1 function\n\tA1(A)\n}\n\nfunc A1(ctx context.Context) {\n\tA1 := context.WithValue(ctx, ID, \"A1\")\n\tprint(\"A1\", A1)\n}\n\nfunc B(ctx context.Context) {\n\t// wrap ctx with a new context\n\t// with the ID set to \"B\"\n\tB := context.WithValue(ctx, ID, \"B\")\n\tprint(\"B\", B)\n\n\t// pass the B context to the B1 function\n\tB1(B)\n}\n\nfunc B1(ctx context.Context) {\n\t// wrap ctx with a new context\n\t// with the ID set to \"B1\"\n\tB1 := context.WithValue(ctx, ID, \"B1\")\n\tprint(\"B1\", B1)\n\n\t// pass the B1 context to the B1a function\n\tB1a(B1)\n}\n\nfunc B1a(ctx context.Context) {\n\t// wrap ctx with a new context\n\t// with the ID set to \"B1a\"\n\tB1a := context.WithValue(ctx, ID, \"B1a\")\n\tprint(\"B1a\", B1a)\n}", + "file": "nodes/src/node-tree/main.go", + "lang": "go", + "name": "example", + "start": 30, + "end": 73 + }, + "main": { + "content": "func main() {\n\t// create a background context\n\tbg := context.Background()\n\n\t// pass the background context to the A function\n\tA(bg)\n\n\t// pass the background context to the B function\n\tB(bg)\n}", + "file": "nodes/src/node-tree/main.go", + "lang": "go", + "name": "main", + "start": 16, + "end": 28 + } + }, + "signals/src/signals/main.go": { + "example": { + "content": "func main() {\n\n\t// create a background context\n\tctx := context.Background()\n\n\t// wrap the context with a timeout\n\t// of 50 milliseconds to ensure the application\n\t// will eventually exit\n\tctx, cancel := context.WithTimeout(ctx, 50*time.Millisecond)\n\tdefer cancel()\n\n\t// wrap the context with a context\n\t// that will be cancelled when an\n\t// interrupt signal is received (ctrl-c)\n\tctx, cancel = signal.NotifyContext(ctx, os.Interrupt)\n\tdefer cancel()\n\n\t// lauch a goroutine that will\n\t// trigger an interrupt signal\n\t// after 10 milliseconds (ctrl-c)\n\tgo func() {\n\t\ttime.Sleep(10 * time.Millisecond)\n\n\t\tfmt.Println(\"sending ctrl-c\")\n\n\t\t// send the interrupt signal\n\t\t// to the current process\n\t\tsyscall.Kill(syscall.Getpid(), syscall.SIGINT)\n\t}()\n\n\tfmt.Println(\"waiting for context to finish\")\n\n\t// wait for the context to finish\n\t\u003c-ctx.Done()\n\n\tfmt.Printf(\"context finished: %v\\n\", ctx.Err())\n\n}", + "file": "signals/src/signals/main.go", + "lang": "go", + "name": "example", + "start": 12, + "end": 52 + } + }, + "signals/src/testing/signals_test.go": { + "example": { + "content": "// use syscall.SIGUSR2 to test\nconst TEST_SIGNAL = syscall.SIGUSR2\n\nfunc Test_Signals(t *testing.T) {\n\n\t// create a background context\n\tctx := context.Background()\n\n\t// wrap the context with a context\n\t// that will self cancel after 5 seconds\n\t// if the context is not finished\n\tctx, cancel := context.WithTimeout(ctx, 5*time.Second)\n\tdefer cancel()\n\n\t// wrap the context with a context\n\t// that will self cancel if the system\n\t// receives a TEST_SIGNAL\n\tsigCtx, cancel := signal.NotifyContext(ctx, TEST_SIGNAL)\n\tdefer cancel()\n\n\tprint(t, sigCtx)\n\n\t// launch a goroutine to wait for the context\n\t// to finish\n\tgo Listener(sigCtx, t)\n\n\t// launch a goroutine to send a TEST_SIGNAL\n\t// to the system after 1 second\n\tgo func() {\n\t\ttime.Sleep(time.Second)\n\n\t\tt.Log(\"sending test signal\")\n\n\t\t// send the TEST_SIGNAL to the system\n\t\tsyscall.Kill(syscall.Getpid(), TEST_SIGNAL)\n\t}()\n\n\t// wait for the context to finish\n\tselect {\n\tcase \u003c-ctx.Done():\n\t\tt.Log(\"context finished\")\n\tcase \u003c-sigCtx.Done():\n\t\tt.Log(\"signal received\")\n\t\tt.Log(\"successfully completed\")\n\t\treturn\n\t}\n\n\terr := ctx.Err()\n\tif err == nil {\n\t\treturn\n\t}\n\n\t// if we receive a DeadlineExceeded error then\n\t// the context timed out and the signal was never\n\t// received.\n\tif err == context.DeadlineExceeded {\n\t\tt.Fatal(\"unexpected error\", err)\n\t}\n\n}", + "file": "signals/src/testing/signals_test.go", + "lang": "go", + "name": "example", + "start": 24, + "end": 89 + }, + "func": { + "content": "func Listener(ctx context.Context, t testing.TB) {\n\tt.Log(\"waiting for context to finish\")\n\n\t// wait for the context to finish\n\t\u003c-ctx.Done()\n\n}", + "file": "signals/src/testing/signals_test.go", + "lang": "go", + "name": "func", + "start": 13, + "end": 22 + }, + "kill": { + "content": "// launch a goroutine to send a TEST_SIGNAL\n// to the system after 1 second\ngo func() {\n\ttime.Sleep(time.Second)\n\n\tt.Log(\"sending test signal\")\n\n\t// send the TEST_SIGNAL to the system\n\tsyscall.Kill(syscall.Getpid(), TEST_SIGNAL)\n}()", + "file": "signals/src/testing/signals_test.go", + "lang": "go", + "name": "kill", + "start": 52, + "end": 63 + } + }, + "timeouts/src/with-deadline/main.go": { + "example": { + "content": "func main() {\n\n\t// create a background context\n\tctx := context.Background()\n\n\t// create an absolute date/time (January 1, 2030)\n\tdeadline := time.Date(2030, 1, 1, 0, 0, 0, 0, time.UTC)\n\tfmt.Println(\"deadline:\", deadline.Format(time.RFC3339))\n\n\t// create a new context with a deadline\n\t// that will cancel at January 1, 2030 00:00:00.\n\tctx, cancel := context.WithDeadline(ctx, deadline)\n\tdefer cancel()\n\n\tprint(ctx)\n}", + "file": "timeouts/src/with-deadline/main.go", + "lang": "go", + "name": "example", + "start": 12, + "end": 30 + }, + "out": { + "content": "deadline: 2030-01-01T00:00:00Z\nWithTimeout(deadline: {wall:0 ext:64029052800 loc:\u003cnil\u003e})\n\t--\u003e Background", + "file": "timeouts/src/with-deadline/main.go", + "lang": "go", + "name": "out", + "start": 38, + "end": 42 + } + }, + "timeouts/src/with-timeout/main.go": { + "example": { + "content": "func main() {\n\n\t// create a background context\n\tctx := context.Background()\n\n\t// create a new context with a timeout\n\t// that will cancel the context after 10ms\n\t// \tequivalent to:\n\t//\t\tcontext.WithDeadline(ctx, time.Now().Add(10 *time.Millisecond))\n\tctx, cancel := context.WithTimeout(ctx, 10*time.Millisecond)\n\tdefer cancel()\n\n\tprint(ctx)\n}", + "file": "timeouts/src/with-timeout/main.go", + "lang": "go", + "name": "example", + "start": 11, + "end": 27 + } + }, + "values/src/custom-const/main.go": { + "consts": { + "content": "const (\n\t// A_RequestID can be used to\n\t// retreive the request_id for\n\t// the A request\n\tA_RequestID CtxKeyA = \"request_id\"\n\t// \tA_SESSION_ID CtxKeyA = \"session_id\"\n\t// \tA_SERVER_ID CtxKeyA = \"server_id\"\n\t// \tother keys...\n\n\t// B_RequestID can be used to\n\t// retreive the request_id for\n\t// the B request\n\tB_RequestID CtxKeyB = \"request_id\"\n)", + "file": "values/src/custom-const/main.go", + "lang": "go", + "name": "consts", + "start": 23, + "end": 39 + }, + "example": { + "content": "func A(ctx context.Context) {\n\t// wrap the context with a request_id\n\t// to represent this specific A request\n\tctx = context.WithValue(ctx, A_RequestID, \"123\")\n\n\t// call B with the wrapped context\n\tB(ctx)\n}\n\nfunc B(ctx context.Context) {\n\t// wrap the context with a request_id\n\t// to represent this specific B request\n\tctx = context.WithValue(ctx, B_RequestID, \"456\")\n\n\tLogger(ctx)\n}", + "file": "values/src/custom-const/main.go", + "lang": "go", + "name": "example", + "start": 49, + "end": 67 + }, + "logger": { + "content": "// Logger logs the webs request_id\n// as well as the request_id from the B\nfunc Logger(ctx context.Context) {\n\t// retreive the request_id from the A request\n\taKey := A_RequestID\n\taVal := ctx.Value(aKey)\n\n\t// print the request_id from the A request\n\tprint(\"A\", aKey, aVal)\n\n\t// retreive the request_id from the B request\n\tbKey := B_RequestID\n\tbVal := ctx.Value(bKey)\n\n\t// print the request_id from the B request\n\tprint(\"B\", bKey, bVal)\n}", + "file": "values/src/custom-const/main.go", + "lang": "go", + "name": "logger", + "start": 69, + "end": 88 + }, + "out": { + "content": "A: main.CtxKeyA(request_id): 123\nB: main.CtxKeyB(request_id): 456", + "file": "values/src/custom-const/main.go", + "lang": "go", + "name": "out", + "start": 95, + "end": 98 + }, + "types": { + "content": "// CtxKeyA is used to wrap keys\n// associated with a A request\n// \tCtxKeyA(\"request_id\")\n// \tCtxKeyA(\"user_id\")\ntype CtxKeyA string\n\n// CtxKeyB is used to wrap keys\n// associated with a B request\n// \tCtxKeyB(\"request_id\")\n// \tCtxKeyB(\"user_id\")\ntype CtxKeyB string", + "file": "values/src/custom-const/main.go", + "lang": "go", + "name": "types", + "start": 8, + "end": 21 + } + }, + "values/src/custom-keys/main.go": { + "example": { + "content": "func A(ctx context.Context) {\n\t// wrap the context with a request_id\n\t// to represent this specific A request\n\tkey := CtxKeyA(\"request_id\")\n\tctx = context.WithValue(ctx, key, \"123\")\n\n\t// call B with the wrapped context\n\tB(ctx)\n}\n\nfunc B(ctx context.Context) {\n\t// wrap the context with a request_id\n\t// to represent this specific B request\n\tkey := CtxKeyB(\"request_id\")\n\tctx = context.WithValue(ctx, key, \"456\")\n\n\tLogger(ctx)\n}", + "file": "values/src/custom-keys/main.go", + "lang": "go", + "name": "example", + "start": 31, + "end": 51 + }, + "logger": { + "content": "// Logger logs the webs request_id\n// as well as the request_id from the B\nfunc Logger(ctx context.Context) {\n\t// retreive the request_id from the A request\n\taKey := CtxKeyA(\"request_id\")\n\taVal := ctx.Value(aKey)\n\n\t// print the request_id from the A request\n\tprint(\"A\", aKey, aVal)\n\n\t// retreive the request_id from the B request\n\tbKey := CtxKeyB(\"request_id\")\n\tbVal := ctx.Value(bKey)\n\n\t// print the request_id from the B request\n\tprint(\"B\", bKey, bVal)\n}", + "file": "values/src/custom-keys/main.go", + "lang": "go", + "name": "logger", + "start": 53, + "end": 72 + }, + "out": { + "content": "A: main.CtxKeyA(request_id): 123\nB: main.CtxKeyB(request_id): 456", + "file": "values/src/custom-keys/main.go", + "lang": "go", + "name": "out", + "start": 79, + "end": 82 + }, + "types": { + "content": "// CtxKeyA is used to wrap keys\n// associated with a A request\n// \tCtxKeyA(\"request_id\")\n// \tCtxKeyA(\"user_id\")\ntype CtxKeyA string\n\n// CtxKeyB is used to wrap keys\n// associated with a B request\n// \tCtxKeyB(\"request_id\")\n// \tCtxKeyB(\"user_id\")\ntype CtxKeyB string", + "file": "values/src/custom-keys/main.go", + "lang": "go", + "name": "types", + "start": 8, + "end": 21 + } + }, + "values/src/keys/main.go": { + "custom": { + "content": "// defining a custom string type will\n// help prevent key collisions.\ntype CtxKey string\nctx = context.WithValue(ctx, CtxKey(\"key\"), \"value\")", + "file": "values/src/keys/main.go", + "lang": "go", + "name": "custom", + "start": 27, + "end": 32 + }, + "example": { + "content": "ctx := context.Background()\n\n// strings shouldn't be used as keys\n// because they can easily collide\n// with other functions, libraries, etc.\n// that set that same key.\n// instead strings should wrapped in their\n// own type.\nctx = context.WithValue(ctx, \"key\", \"value\")\n\n// keys must be comparable.\n// maps, and other complex types,\n// are not comparable and can't be used\n// used as keys.\nctx = context.WithValue(ctx, map[string]int{}, \"another value\")", + "file": "values/src/keys/main.go", + "lang": "go", + "name": "example", + "start": 9, + "end": 25 + } + }, + "values/src/malicious/bar/bar.go": { + "example": { + "content": "func WithBar(ctx context.Context) context.Context {\n\t// wrap the context with a request_id\n\t// to represent this specific bar request\n\tctx = context.WithValue(ctx, RequestID, \"456\")\n\n\t// maliciously replace the request_id\n\t// set by foo\n\tctx = context.WithValue(ctx, foo.RequestID, \"???\")\n\n\t// return the wrapped context\n\treturn ctx\n}", + "file": "values/src/malicious/bar/bar.go", + "lang": "go", + "name": "example", + "start": 17, + "end": 31 + }, + "types": { + "content": "type CtxKey string\n\nconst (\n\tRequestID CtxKey = \"request_id\"\n)", + "file": "values/src/malicious/bar/bar.go", + "lang": "go", + "name": "types", + "start": 8, + "end": 15 + } + }, + "values/src/malicious/foo/foo.go": { + "example": { + "content": "func WithFoo(ctx context.Context) context.Context {\n\t// wrap the context with a request_id\n\t// to represent this specific foo request\n\tctx = context.WithValue(ctx, RequestID, \"123\")\n\n\t// return the wrapped context\n\treturn ctx\n}", + "file": "values/src/malicious/foo/foo.go", + "lang": "go", + "name": "example", + "start": 14, + "end": 24 + }, + "types": { + "content": "type CtxKey string\n\nconst (\n\tRequestID CtxKey = \"request_id\"\n)", + "file": "values/src/malicious/foo/foo.go", + "lang": "go", + "name": "types", + "start": 5, + "end": 12 + } + }, + "values/src/malicious/main.go": { + "example": { + "content": "func main() {\n\t// create a background context\n\tctx := context.Background()\n\n\t// wrap the context with foo\n\tctx = foo.WithFoo(ctx)\n\n\t// wrap the context with bar\n\tctx = bar.WithBar(ctx)\n\n\t// retrieve the foo.RequestID\n\t// value from the context\n\tid := ctx.Value(foo.RequestID)\n\n\t// print the value\n\tfmt.Println(\"foo.RequestID: \", id)\n}", + "file": "values/src/malicious/main.go", + "lang": "go", + "name": "example", + "start": 10, + "end": 29 + }, + "out": { + "content": "foo.RequestID: ???", + "file": "values/src/malicious/main.go", + "lang": "go", + "name": "out", + "start": 32, + "end": 34 + } + }, + "values/src/resolution/main.go": { + "example": { + "content": "func main() {\n\n\t// create a new background context\n\tctx := context.Background()\n\n\t// wrap the context with a new context\n\t// that has the key \"A\" and the value \"a\",\n\tctx = context.WithValue(ctx, CtxKey(\"A\"), \"a\")\n\n\t// wrap the context with a new context\n\t// that has the key \"B\" and the value \"b\",\n\tctx = context.WithValue(ctx, CtxKey(\"B\"), \"b\")\n\n\t// wrap the context with a new context\n\t// that has the key \"C\" and the value \"c\",\n\tctx = context.WithValue(ctx, CtxKey(\"C\"), \"c\")\n\n\t// print the final context\n\tprint(\"ctx\", ctx)\n\n\t// retreive and print the value\n\t// for the key \"A\"\n\ta := ctx.Value(CtxKey(\"A\"))\n\tfmt.Println(\"A:\", a)\n\n\t// retreive and print the value\n\t// for the key \"B\"\n\tb := ctx.Value(CtxKey(\"B\"))\n\tfmt.Println(\"B:\", b)\n\n\t// retreive and print the value\n\t// for the key \"C\"\n\tc := ctx.Value(CtxKey(\"C\"))\n\tfmt.Println(\"C:\", c)\n\n}", + "file": "values/src/resolution/main.go", + "lang": "go", + "name": "example", + "start": 15, + "end": 53 + } + }, + "values/src/secured/bar/bar.go": { + "example": { + "content": "func WithBar(ctx context.Context) context.Context {\n\t// wrap the context with a request_id\n\t// to represent this specific bar request\n\tctx = context.WithValue(ctx, requestID, \"456\")\n\n\t// no longer able to set the foo request id\n\t// it does not have access to the foo.ctxKey type\n\t// as it is not exported, so bar can not create\n\t// a new key of that type.\n\t// ctx = context.WithValue(ctx, foo.ctxKey(\"request_id\"), \"???\")\n\n\t// return the wrapped context\n\treturn ctx\n}", + "file": "values/src/secured/bar/bar.go", + "lang": "go", + "name": "example", + "start": 16, + "end": 32 + }, + "types": { + "content": "type ctxKey string\n\nconst (\n\trequestID ctxKey = \"request_id\"\n)", + "file": "values/src/secured/bar/bar.go", + "lang": "go", + "name": "types", + "start": 7, + "end": 14 + } + }, + "values/src/secured/foo/foo.go": { + "example": { + "content": "func RequestIDFrom(ctx context.Context) (string, error) {\n\t// get the request_id from the context\n\ts, ok := ctx.Value(requestID).(string)\n\tif !ok {\n\t\treturn \"\", fmt.Errorf(\"request_id not found in context\")\n\t}\n\treturn s, nil\n}", + "file": "values/src/secured/foo/foo.go", + "lang": "go", + "name": "example", + "start": 26, + "end": 36 + }, + "types": { + "content": "type ctxKey string\n\nconst (\n\trequestID ctxKey = \"request_id\"\n)", + "file": "values/src/secured/foo/foo.go", + "lang": "go", + "name": "types", + "start": 8, + "end": 15 + } + }, + "values/src/secured/main.go": { + "example": { + "content": "func main() {\n\t// create a background context\n\tctx := context.Background()\n\n\t// wrap the context with foo\n\tctx = foo.WithFoo(ctx)\n\n\t// wrap the context with bar\n\tctx = bar.WithBar(ctx)\n\n\t// retrieve the foo.RequestID\n\t// value from the context\n\tid, err := foo.RequestIDFrom(ctx)\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\n\t// print the value\n\tfmt.Println(\"foo.RequestID: \", id)\n}", + "file": "values/src/secured/main.go", + "lang": "go", + "name": "example", + "start": 11, + "end": 33 + }, + "out": { + "content": "foo.RequestID: 123", + "file": "values/src/secured/main.go", + "lang": "go", + "name": "out", + "start": 36, + "end": 38 + } + }, + "values/src/string-keys/main.go": { + "example": { + "content": "func main() {\n\t// create a new background context\n\tctx := context.Background()\n\n\t// call the A function\n\t// passing in the background context\n\tA(ctx)\n}\n\nfunc A(ctx context.Context) {\n\t// wrap the context with a request_id\n\t// to represent this specific A request\n\tctx = context.WithValue(ctx, \"request_id\", \"123\")\n\n\t// call the B function\n\t// passing in the wrapped context\n\tB(ctx)\n}\n\nfunc B(ctx context.Context) {\n\t// wrap the context with a request_id\n\t// to represent this specific B request\n\tctx = context.WithValue(ctx, \"request_id\", \"456\")\n\tLogger(ctx)\n}\n\n// Logger logs the webs request_id\n// as well as the request_id from the B\nfunc Logger(ctx context.Context) {\n\ta := ctx.Value(\"request_id\")\n\tfmt.Println(\"A\\t\", \"request_id:\", a)\n\n\tb := ctx.Value(\"request_id\")\n\tfmt.Println(\"B\\t\", \"request_id:\", b)\n}", + "file": "values/src/string-keys/main.go", + "lang": "go", + "name": "example", + "start": 8, + "end": 45 + }, + "out": { + "content": "A\t request_id: 456\nB\t request_id: 456", + "file": "values/src/string-keys/main.go", + "lang": "go", + "name": "out", + "start": 48, + "end": 51 + } + } + } + }, + "title": "Context", + "type": "hype.Document" +} diff --git a/src/testdata/arrays.json b/src/testdata/arrays.json deleted file mode 100644 index c8a8d5e..0000000 --- a/src/testdata/arrays.json +++ /dev/null @@ -1,14140 +0,0 @@ -{ - "nodes": [ - { - "file": "module.md", - "nodes": [ - { - "atom": "html", - "file": "module.md", - "nodes": [ - { - "atom": "head", - "file": "module.md", - "type": "*hype.Element" - }, - [ - { - "atom": "body", - "file": "module.md", - "nodes": [ - [ - { - "atom": "page", - "file": "module.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "h1", - "file": "module.md", - "level": 1, - "nodes": [ - { - "text": "Arrays, Slices, and Iteration", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "module.md", - "nodes": [ - { - "text": "In this ", - "type": "hype.Text" - }, - { - "atom": "binding", - "attributes": { - "part": "" - }, - "file": "module.md", - "type": "*hype.Element" - }, - { - "text": " we cover the built-in list types, ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "arrays", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " and ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "slices", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ". Next, we move on to learning about Go's ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "for", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " keyword for iteration. Finally, we cover using the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "range", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " keyword to simplify iteration.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "title": "Arrays, Slices, and Iteration", - "type": "*hype.Page" - } - ], - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "include", - "attributes": { - "src": "arrays_slices/arrays_slices.md" - }, - "dir": "arrays_slices", - "file": "module.md", - "nodes": [ - [ - { - "atom": "page", - "file": "arrays_slices.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "h1", - "file": "arrays_slices.md", - "level": 1, - "nodes": [ - { - "text": "List Types: Arrays and Slices", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "arrays_slices.md", - "nodes": [ - { - "text": "Go has on two built-in, ordered, list collection types; arrays and slices. Unlike other languages there are no built-in, complex, list types such as ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "href": "https://en.wikipedia.org/wiki/Linked_list", - "target": "_blank" - }, - "file": "arrays_slices.md", - "nodes": [ - { - "text": "linked lists", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "https://en.wikipedia.org/wiki/Linked_list" - } - ], - { - "text": " or ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "href": "https://en.wikipedia.org/wiki/Tree_%28data_structure%29", - "target": "_blank" - }, - "file": "arrays_slices.md", - "nodes": [ - { - "text": "trees", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "https://en.wikipedia.org/wiki/Tree_%28data_structure%29" - } - ], - { - "text": ". Instead, Go uses the concept of ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "href": "https://en.wikipedia.org/wiki/Object_composition", - "target": "_blank" - }, - "file": "arrays_slices.md", - "nodes": [ - { - "text": "composition", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "https://en.wikipedia.org/wiki/Object_composition" - } - ], - { - "text": " to allow for the creation of more complex data structures, an example of which can be found with the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "container/list#List", - "href": "https://pkg.go.dev/container/list#List", - "target": "_blank" - }, - "file": "arrays_slices.md", - "nodes": [ - { - "atom": "code", - "file": "arrays_slices.md", - "nodes": [ - { - "text": "list.List", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/container/list#List" - } - ], - { - "text": " type. We will cover composition in more detail later in this ", - "type": "hype.Text" - }, - { - "atom": "binding", - "attributes": { - "whole": "" - }, - "file": "arrays_slices.md", - "type": "*hype.Element" - }, - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "arrays_slices.md", - "nodes": [ - { - "text": "Arrays and slices are both ordered collections of values. The only difference between them is that arrays are fixed in size, while slices are not.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "arrays_slices.md", - "nodes": [ - { - "text": "Arrays in Go are useful when planning for detailed layout of memory. Using arrays can sometimes help avoid allocation when you know exactly how much data you want to store. Arrays are also used as the building blocks of slices.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "arrays_slices.md", - "nodes": [ - { - "text": "Slices wrap arrays in Go, and provide a more general, powerful, and convenient way to work with ordered collections of values.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "arrays_slices.md", - "level": 2, - "nodes": [ - { - "text": "Differences Between Arrays and Slices", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "arrays_slices.md", - "nodes": [ - { - "text": "Arrays and slices are both ordered collections of values. Both require that the values all be of the same type. Arrays, however, have a fixed length, while slices can grow as needed.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-1", - "type": "listing" - }, - "file": "arrays_slices.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "table", - "file": "arrays_slices", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "thead", - "file": "arrays_slices", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "tr", - "file": "arrays_slices", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "th", - "file": "arrays_slices", - "type": "*hype.TH" - } - ], - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "th", - "file": "arrays_slices", - "nodes": [ - { - "text": "Arrays", - "type": "hype.Text" - } - ], - "type": "*hype.TH" - } - ], - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "th", - "file": "arrays_slices", - "nodes": [ - { - "text": "Slices", - "type": "hype.Text" - } - ], - "type": "*hype.TH" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "type": "*hype.TR" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "type": "*hype.THead" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - { - "atom": "tbody", - "file": "arrays_slices", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "tr", - "file": "arrays_slices", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "td", - "file": "arrays_slices", - "nodes": [ - { - "text": "Fixed Length", - "type": "hype.Text" - } - ], - "type": "*hype.TD" - } - ], - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "td", - "file": "arrays_slices", - "nodes": [ - { - "text": "X", - "type": "hype.Text" - } - ], - "type": "*hype.TD" - } - ], - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "td", - "file": "arrays_slices", - "nodes": [ - { - "text": "-", - "type": "hype.Text" - } - ], - "type": "*hype.TD" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "type": "*hype.TR" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "tr", - "file": "arrays_slices", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "td", - "file": "arrays_slices", - "nodes": [ - { - "text": "Fixed Type", - "type": "hype.Text" - } - ], - "type": "*hype.TD" - } - ], - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "td", - "file": "arrays_slices", - "nodes": [ - { - "text": "X", - "type": "hype.Text" - } - ], - "type": "*hype.TD" - } - ], - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "td", - "file": "arrays_slices", - "nodes": [ - { - "text": "X", - "type": "hype.Text" - } - ], - "type": "*hype.TD" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "type": "*hype.TR" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "tr", - "file": "arrays_slices", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "td", - "file": "arrays_slices", - "nodes": [ - { - "text": "Zero Based", - "type": "hype.Text" - } - ], - "type": "*hype.TD" - } - ], - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "td", - "file": "arrays_slices", - "nodes": [ - { - "text": "X", - "type": "hype.Text" - } - ], - "type": "*hype.TD" - } - ], - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "td", - "file": "arrays_slices", - "nodes": [ - { - "text": "X", - "type": "hype.Text" - } - ], - "type": "*hype.TD" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "type": "*hype.TR" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": "\n", - "type": "hype.Text" - } - ], - "type": "*hype.Table" - } - ], - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "arrays_slices", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.1:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Differences between arrays and slices", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 1, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "arrays_slices.md", - "nodes": [ - { - "text": "The capacity of an array is defined at creation time. Once an array has allocated it's size, the size can no longer be changed. All of the memory needed to store the array is allocated at creation time. This means that the array is a fixed size, and once created, it cannot be resized. The array will be garbage collected once it's no longer in use.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-2", - "type": "listing" - }, - "file": "arrays_slices.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "arrays_slices", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "arrays_slices/src/array/main.go#main" - }, - "lang": "go", - "nodes": [ - { - "content": "func main() {\n\tnames := [4]string{\"Kurt\", \"Janis\", \"Jimi\", \"Amy\"}\n\tfmt.Println(names)\n}", - "file": "arrays_slices/src/array/main.go", - "lang": "go", - "name": "main", - "start": 5, - "end": 11, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "run", - "." - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go run .", - "run": ".", - "src": "arrays_slices/src/array" - }, - "expected_exit": 0, - "file": "arrays_slices", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\n[Kurt Janis Jimi Amy]", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/03-collections/arrays_slices/src/array", - "stdout": "W0t1cnQgSmFuaXMgSmltaSBBbXld", - "duration": 1181170208, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\n[Kurt Janis Jimi Amy]", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/03-collections/arrays_slices/src/array", - "stdout": "W0t1cnQgSmFuaXMgSmltaSBBbXld", - "duration": 1181170208, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "arrays_slices", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.2:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "An array of four strings.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 2, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "arrays_slices.md", - "nodes": [ - { - "text": "In ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-2" - }, - "file": "arrays_slices.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-2" - }, - "nodes": [ - { - "text": "Listing 1.2", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-2" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": " we created an array of four strings. The array is allocated at creation time, and once created, it cannot be resized.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "arrays_slices.md", - "nodes": [ - { - "text": "Arrays are very useful when you know exactly how much data you will need to store. Often, though, you will not know the size you will need at creation time, in this case, you will need to use slices.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "arrays_slices.md", - "nodes": [ - { - "text": "Slices are a more flexible and flexible way to store data. They are not fixed in size, and can grow as needed. Because of their flexibility, slices are more often used in daily situations instead of arrays.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-3", - "type": "listing" - }, - "file": "arrays_slices.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "arrays_slices", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "arrays_slices/src/slice/main.go#example" - }, - "lang": "go", - "nodes": [ - { - "content": "func main() {\n\tnames := []string{\"Kurt\", \"Janis\", \"Jimi\", \"Amy\"}\n\tfmt.Println(names)\n}", - "file": "arrays_slices/src/slice/main.go", - "lang": "go", - "name": "example", - "start": 5, - "end": 11, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "run", - "." - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go run .", - "run": ".", - "src": "arrays_slices/src/slice" - }, - "expected_exit": 0, - "file": "arrays_slices", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\n[Kurt Janis Jimi Amy]", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/03-collections/arrays_slices/src/slice", - "stdout": "W0t1cnQgSmFuaXMgSmltaSBBbXld", - "duration": 2616416375, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\n[Kurt Janis Jimi Amy]", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/03-collections/arrays_slices/src/slice", - "stdout": "W0t1cnQgSmFuaXMgSmltaSBBbXld", - "duration": 2616416375, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "arrays_slices", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.3:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "A slice of four strings.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 3, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "arrays_slices.md", - "nodes": [ - { - "text": "In ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-3" - }, - "file": "arrays_slices.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-3" - }, - "nodes": [ - { - "text": "Listing 1.3", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-3" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": " we created a slice of four strings. The slice is not allocated at creation time, and can grow as needed.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "arrays_slices.md", - "level": 2, - "nodes": [ - { - "text": "Spot the Difference", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "arrays_slices.md", - "nodes": [ - { - "text": "Once created, arrays and slices, behave nearly identically. The only place to see the difference is in the way they are created. Arrays require that you specify the size of the array at creation time. Slices do not require that you specify the size of the array at creation time.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-4", - "type": "listing" - }, - "file": "arrays_slices.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "arrays_slices", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "snippet": "example", - "src": "arrays_slices/src/diff/main.go" - }, - "lang": "go", - "nodes": [ - { - "content": "func main() {\n\tnamesArray := [4]string{\"Kurt\", \"Janis\", \"Jimi\", \"Amy\"}\n\tnamesSlice := []string{\"Kurt\", \"Janis\", \"Jimi\", \"Amy\"}\n\n\tfmt.Println(namesArray)\n\tfmt.Println(namesSlice)\n}", - "file": "arrays_slices/src/diff/main.go", - "lang": "go", - "name": "example", - "start": 5, - "end": 14, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "run", - "." - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go run .", - "run": ".", - "src": "arrays_slices/src/diff" - }, - "expected_exit": 0, - "file": "arrays_slices", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\n[Kurt Janis Jimi Amy]\n[Kurt Janis Jimi Amy]", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/03-collections/arrays_slices/src/diff", - "stdout": "W0t1cnQgSmFuaXMgSmltaSBBbXldCltLdXJ0IEphbmlzIEppbWkgQW15XQ==", - "duration": 3467705250, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\n[Kurt Janis Jimi Amy]\n[Kurt Janis Jimi Amy]", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/03-collections/arrays_slices/src/diff", - "stdout": "W0t1cnQgSmFuaXMgSmltaSBBbXldCltLdXJ0IEphbmlzIEppbWkgQW15XQ==", - "duration": 3467705250, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "arrays_slices", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.4:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Creating an array versus a slice.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 4, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "arrays_slices.md", - "nodes": [ - { - "text": "In ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-4" - }, - "file": "arrays_slices.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-4" - }, - "nodes": [ - { - "text": "Listing 1.4", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-4" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": " the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "arrays_slices.md", - "nodes": [ - { - "text": "namesArray", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " variable is an array of four strings. The ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "arrays_slices.md", - "nodes": [ - { - "text": "namesSlice", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " variable is a slice that currently has four strings.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "arrays_slices.md", - "level": 2, - "nodes": [ - { - "text": "Initializing Arrays and Slices", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "arrays_slices.md", - "nodes": [ - { - "text": "With simple data types, such as strings, numbers, and booleans, no special initialization is needed to use them. With more complex data types, values may need to be initialized before they can be used. At this initialization time, you have the option of filling the type with values, or leaving the type empty.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "arrays_slices.md", - "nodes": [ - { - "text": "When initializing a type, you must use a pair of curly braces to indicate that the type is being initialized; ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "arrays_slices.md", - "nodes": [ - { - "text": "\u003ctype\u003e{\u003coptional: values\u003e}", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "arrays_slices.md", - "nodes": [ - { - "text": "Arrays and slices don't need to be initialized before they are used. As with strings and numbers, they can be used without being initialized. However, initializing an array or slice gives you the ability to fill the array or slice with values immediately.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-5", - "type": "listing" - }, - "file": "arrays_slices.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "arrays_slices", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "snippet": "example", - "src": "arrays_slices/src/inline/main.go" - }, - "lang": "go", - "nodes": [ - { - "content": "func main() {\n\t// initialize array without values:\n\ta := [5]int{}\n\n\t// initialize slice without values:\n\tb := []int{}\n\n\t// initialize array with values:\n\tc := [3]int{1, 2, 3}\n\n\t// initialize slice with values:\n\td := []int{1, 2, 3}\n\n\t// declare an array variable:\n\tvar e [5]int\n\n\t// declare slice variable:\n\tvar f []int\n\n\tfmt.Println(a)\n\tfmt.Println(b)\n\tfmt.Println(c)\n\tfmt.Println(d)\n\tfmt.Println(e)\n\tfmt.Println(f)\n}", - "file": "arrays_slices/src/inline/main.go", - "lang": "go", - "name": "example", - "start": 5, - "end": 33, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "run", - "." - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go run .", - "run": ".", - "src": "arrays_slices/src/inline" - }, - "expected_exit": 0, - "file": "arrays_slices", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\n[0 0 0 0 0]\n[]\n[1 2 3]\n[1 2 3]\n[0 0 0 0 0]\n[]", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/03-collections/arrays_slices/src/inline", - "stdout": "WzAgMCAwIDAgMF0KW10KWzEgMiAzXQpbMSAyIDNdClswIDAgMCAwIDBdCltd", - "duration": 4246396417, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\n[0 0 0 0 0]\n[]\n[1 2 3]\n[1 2 3]\n[0 0 0 0 0]\n[]", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/03-collections/arrays_slices/src/inline", - "stdout": "WzAgMCAwIDAgMF0KW10KWzEgMiAzXQpbMSAyIDNdClswIDAgMCAwIDBdCltd", - "duration": 4246396417, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "arrays_slices", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.5:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Initializing arrays and slices.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 5, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "arrays_slices.md", - "level": 2, - "nodes": [ - { - "text": "Array and Slice Zero Values", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "arrays_slices.md", - "nodes": [ - { - "text": "The zero value of each element in an array or slice is the zero value for the type of elements in the array or slice. For example, if an array of strings is created, each element in the array will be a string with a zero value of ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "arrays_slices.md", - "nodes": [ - { - "text": "\"\"", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-6", - "type": "listing" - }, - "file": "arrays_slices.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "arrays_slices", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "snippet": "main", - "src": "arrays_slices/src/zero/main.go" - }, - "lang": "go", - "nodes": [ - { - "content": "func main() {\n\tvar a [5]int\n\tvar b [4]string\n\tvar c [3]bool\n\n\tfmt.Printf(\"%#v\\n\", a)\n\tfmt.Printf(\"%#v\\n\", b)\n\tfmt.Printf(\"%#v\\n\", c)\n}", - "file": "arrays_slices/src/zero/main.go", - "lang": "go", - "name": "main", - "start": 5, - "end": 16, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "run", - "." - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go run .", - "run": ".", - "src": "arrays_slices/src/zero" - }, - "expected_exit": 0, - "file": "arrays_slices", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\n[5]int{0, 0, 0, 0, 0}\n[4]string{\u0026#34;\u0026#34;, \u0026#34;\u0026#34;, \u0026#34;\u0026#34;, \u0026#34;\u0026#34;}\n[3]bool{false, false, false}", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/03-collections/arrays_slices/src/zero", - "stdout": "WzVdaW50ezAsIDAsIDAsIDAsIDB9Cls0XXN0cmluZ3siIiwgIiIsICIiLCAiIn0KWzNdYm9vbHtmYWxzZSwgZmFsc2UsIGZhbHNlfQ==", - "duration": 465934583, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\n[5]int{0, 0, 0, 0, 0}\n[4]string{\u0026#34;\u0026#34;, \u0026#34;\u0026#34;, \u0026#34;\u0026#34;, \u0026#34;\u0026#34;}\n[3]bool{false, false, false}", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/03-collections/arrays_slices/src/zero", - "stdout": "WzVdaW50ezAsIDAsIDAsIDAsIDB9Cls0XXN0cmluZ3siIiwgIiIsICIiLCAiIn0KWzNdYm9vbHtmYWxzZSwgZmFsc2UsIGZhbHNlfQ==", - "duration": 465934583, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "arrays_slices", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.6:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Array and slice zero values.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 6, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "arrays_slices.md", - "nodes": [ - { - "text": "In ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-6" - }, - "file": "arrays_slices.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-6" - }, - "nodes": [ - { - "text": "Listing 1.6", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-6" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": " we printed the several different arrays using the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "arrays_slices.md", - "nodes": [ - { - "text": "%#v", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " formatting verb. The ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "arrays_slices.md", - "nodes": [ - { - "text": "%#v", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " verb prints the Go-syntax representation of the value. For an array, this shows the type, the length, and the values, which in this case are all zero values.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "arrays_slices.md", - "level": 2, - "nodes": [ - { - "text": "Indexing Arrays and Slices", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "arrays_slices.md", - "nodes": [ - { - "text": "When attempting to access an array with a hard-coded index, the Go compiler will check to see if the index is out of bounds. If the index being accessed is out of bounds, the compiler will error, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-7" - }, - "file": "arrays_slices.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-7" - }, - "nodes": [ - { - "text": "Listing 1.7", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-7" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-7", - "type": "listing" - }, - "file": "arrays_slices.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "arrays_slices", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "snippet": "example", - "src": "arrays_slices/src/out-of-bounds/main.go" - }, - "lang": "go", - "nodes": [ - { - "content": "func main() {\n\tnames := [4]string{\"Kurt\", \"Janis\", \"Jimi\", \"Amy\"}\n\tfmt.Println(names[5])\n}", - "file": "arrays_slices/src/out-of-bounds/main.go", - "lang": "go", - "name": "example", - "start": 5, - "end": 11, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "build", - "." - ], - "atom": "cmd", - "attributes": { - "build": ".", - "data-go-version": "go1.21.5", - "exec": "go build .", - "exit": "-1", - "src": "arrays_slices/src/out-of-bounds" - }, - "expected_exit": -1, - "file": "arrays_slices", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go build .\n\n# demo\n./main.go:8:20: invalid argument: index 5 out of bounds [0:4]", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "build", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/03-collections/arrays_slices/src/out-of-bounds", - "err": { - "Stderr": null - }, - "exit": 1, - "stderr": "IyBkZW1vCi4vbWFpbi5nbzo4OjIwOiBpbnZhbGlkIGFyZ3VtZW50OiBpbmRleCA1IG91dCBvZiBib3VuZHMgWzA6NF0=", - "duration": 2377326458, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go build .\n\n# demo\n./main.go:8:20: invalid argument: index 5 out of bounds [0:4]", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "build", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/03-collections/arrays_slices/src/out-of-bounds", - "err": { - "Stderr": null - }, - "exit": 1, - "stderr": "IyBkZW1vCi4vbWFpbi5nbzo4OjIwOiBpbnZhbGlkIGFyZ3VtZW50OiBpbmRleCA1IG91dCBvZiBib3VuZHMgWzA6NF0=", - "duration": 2377326458, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "arrays_slices", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.7:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Indexing an array out of bounds.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 7, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "arrays_slices.md", - "nodes": [ - { - "text": "If, however, the index is a variable, or the type is a slice instead of an array, the compiler will not check for out-of-bounds errors. Instead, the Go runtime will raise a panic and possibly crash the program, as we see in ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-8" - }, - "file": "arrays_slices.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-8" - }, - "nodes": [ - { - "text": "Listing 1.8", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-8" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-8", - "type": "listing" - }, - "file": "arrays_slices.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "arrays_slices", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "snippet": "example", - "src": "arrays_slices/src/out-of-bounds-rt/main.go" - }, - "lang": "go", - "nodes": [ - { - "content": "func main() {\n\tnames := [4]string{\"Kurt\", \"Janis\", \"Jimi\", \"Amy\"}\n\n\ti := 5\n\tfmt.Println(names[i])\n}", - "file": "arrays_slices/src/out-of-bounds-rt/main.go", - "lang": "go", - "name": "example", - "start": 5, - "end": 13, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "run", - "." - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go run .", - "exit": "-1", - "run": ".", - "src": "arrays_slices/src/out-of-bounds-rt" - }, - "expected_exit": -1, - "file": "arrays_slices", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\npanic: runtime error: index out of range [5] with length 4\n\ngoroutine 1 [running]:\nmain.main()\n\t./main.go:10 +0x24\nexit status 2", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/03-collections/arrays_slices/src/out-of-bounds-rt", - "err": { - "Stderr": null - }, - "exit": 1, - "stderr": "cGFuaWM6IHJ1bnRpbWUgZXJyb3I6IGluZGV4IG91dCBvZiByYW5nZSBbNV0gd2l0aCBsZW5ndGggNAoKZ29yb3V0aW5lIDEgW3J1bm5pbmddOgptYWluLm1haW4oKQoJL1VzZXJzL21hcmtiYXRlcy9MaWJyYXJ5L0Nsb3VkU3RvcmFnZS9Ecm9wYm94L2Rldi9ndWlkZXMvY29udGVudC9ib29rL2NoYXB0ZXJzLzAzLWNvbGxlY3Rpb25zL2FycmF5c19zbGljZXMvc3JjL291dC1vZi1ib3VuZHMtcnQvbWFpbi5nbzoxMCArMHgyNApleGl0IHN0YXR1cyAy", - "duration": 3846997375, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\npanic: runtime error: index out of range [5] with length 4\n\ngoroutine 1 [running]:\nmain.main()\n\t./main.go:10 +0x24\nexit status 2", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/03-collections/arrays_slices/src/out-of-bounds-rt", - "err": { - "Stderr": null - }, - "exit": 1, - "stderr": "cGFuaWM6IHJ1bnRpbWUgZXJyb3I6IGluZGV4IG91dCBvZiByYW5nZSBbNV0gd2l0aCBsZW5ndGggNAoKZ29yb3V0aW5lIDEgW3J1bm5pbmddOgptYWluLm1haW4oKQoJL1VzZXJzL21hcmtiYXRlcy9MaWJyYXJ5L0Nsb3VkU3RvcmFnZS9Ecm9wYm94L2Rldi9ndWlkZXMvY29udGVudC9ib29rL2NoYXB0ZXJzLzAzLWNvbGxlY3Rpb25zL2FycmF5c19zbGljZXMvc3JjL291dC1vZi1ib3VuZHMtcnQvbWFpbi5nbzoxMCArMHgyNApleGl0IHN0YXR1cyAy", - "duration": 3846997375, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "arrays_slices", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.8:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Indexing an array out of bounds with a variable.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 8, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "arrays_slices.md", - "nodes": [ - { - "text": "We will discuss panicking later in this ", - "type": "hype.Text" - }, - { - "atom": "binding", - "attributes": { - "whole": "" - }, - "file": "arrays_slices.md", - "type": "*hype.Element" - }, - { - "text": " when we discuss errors, however, it is worth understanding that a panic ", - "type": "hype.Text" - }, - { - "atom": "strong", - "file": "arrays_slices.md", - "nodes": [ - { - "text": "will", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " crash your application if not careful.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "arrays_slices.md", - "level": 2, - "nodes": [ - { - "text": "Array and Slice Types", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "arrays_slices.md", - "nodes": [ - { - "text": "It's important to remember that arrays and slices can only hold values of the type they were declared to hold. For example, if you declare an array of strings, you can only store strings in the array. Attempting a different type will result in a either a compile-time error, or a runtime panic.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-9", - "type": "listing" - }, - "file": "arrays_slices.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "arrays_slices", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "snippet": "main", - "src": "arrays_slices/src/types/type/main.go" - }, - "lang": "go", - "nodes": [ - { - "content": "func main() {\n\tstrings := [4]string{\"one\", \"two\", \"three\", \"four\"}\n\tstrings[0] = 5 // can't put an int in a string array\n\n\tints := []int{1, 2, 3, 4}\n\tints[0] = \"five\" // can't put a string in an int slice\n\n\t// can't mix types during initialization\n\tmixed := []string{\"one\", 2, \"three\", \"four\"}\n}", - "file": "arrays_slices/src/types/type/main.go", - "lang": "go", - "name": "main", - "start": 3, - "end": 15, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "run", - "." - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go run .", - "exit": "-1", - "run": ".", - "src": "arrays_slices/src/types/type" - }, - "expected_exit": -1, - "file": "arrays_slices", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\n# demo\n./main.go:6:15: cannot use 5 (untyped int constant) as string value in assignment\n./main.go:9:12: cannot use \u0026#34;five\u0026#34; (untyped string constant) as int value in assignment\n./main.go:12:2: mixed declared and not used\n./main.go:12:27: cannot use 2 (untyped int constant) as string value in array or slice literal", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/03-collections/arrays_slices/src/types/type", - "err": { - "Stderr": null - }, - "exit": 1, - "stderr": "IyBkZW1vCi4vbWFpbi5nbzo2OjE1OiBjYW5ub3QgdXNlIDUgKHVudHlwZWQgaW50IGNvbnN0YW50KSBhcyBzdHJpbmcgdmFsdWUgaW4gYXNzaWdubWVudAouL21haW4uZ286OToxMjogY2Fubm90IHVzZSAiZml2ZSIgKHVudHlwZWQgc3RyaW5nIGNvbnN0YW50KSBhcyBpbnQgdmFsdWUgaW4gYXNzaWdubWVudAouL21haW4uZ286MTI6MjogbWl4ZWQgZGVjbGFyZWQgYW5kIG5vdCB1c2VkCi4vbWFpbi5nbzoxMjoyNzogY2Fubm90IHVzZSAyICh1bnR5cGVkIGludCBjb25zdGFudCkgYXMgc3RyaW5nIHZhbHVlIGluIGFycmF5IG9yIHNsaWNlIGxpdGVyYWw=", - "duration": 1150702709, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\n# demo\n./main.go:6:15: cannot use 5 (untyped int constant) as string value in assignment\n./main.go:9:12: cannot use \u0026#34;five\u0026#34; (untyped string constant) as int value in assignment\n./main.go:12:2: mixed declared and not used\n./main.go:12:27: cannot use 2 (untyped int constant) as string value in array or slice literal", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/03-collections/arrays_slices/src/types/type", - "err": { - "Stderr": null - }, - "exit": 1, - "stderr": "IyBkZW1vCi4vbWFpbi5nbzo2OjE1OiBjYW5ub3QgdXNlIDUgKHVudHlwZWQgaW50IGNvbnN0YW50KSBhcyBzdHJpbmcgdmFsdWUgaW4gYXNzaWdubWVudAouL21haW4uZ286OToxMjogY2Fubm90IHVzZSAiZml2ZSIgKHVudHlwZWQgc3RyaW5nIGNvbnN0YW50KSBhcyBpbnQgdmFsdWUgaW4gYXNzaWdubWVudAouL21haW4uZ286MTI6MjogbWl4ZWQgZGVjbGFyZWQgYW5kIG5vdCB1c2VkCi4vbWFpbi5nbzoxMjoyNzogY2Fubm90IHVzZSAyICh1bnR5cGVkIGludCBjb25zdGFudCkgYXMgc3RyaW5nIHZhbHVlIGluIGFycmF5IG9yIHNsaWNlIGxpdGVyYWw=", - "duration": 1150702709, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "arrays_slices", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.9:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Mixing types within an array or slice is not allowed.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 9, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "arrays_slices.md", - "level": 2, - "nodes": [ - { - "text": "Array and Slice Type Definitions", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "arrays_slices.md", - "nodes": [ - { - "text": "When we have variables that been assigned to arrays and slices, those variables have a type associated with them. This type is called the type definition.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "arrays_slices.md", - "nodes": [ - { - "text": "Because arrays are of fixed length the type definition for an array is comprised of both the declared length of the array and the type it will store. For example, in ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-10" - }, - "file": "arrays_slices.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-10" - }, - "nodes": [ - { - "text": "Listing 1.10", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-10" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", the type for the array, ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "arrays_slices.md", - "nodes": [ - { - "text": "[2]string{\"one\", \"two\"}", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ", is ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "arrays_slices.md", - "nodes": [ - { - "text": "[2]string", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-10", - "type": "listing" - }, - "file": "arrays_slices.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "arrays_slices", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "snippet": "arrays", - "src": "arrays_slices/src/types/arrays/main.go" - }, - "lang": "go", - "nodes": [ - { - "content": "func main() {\n\ta1 := [2]string{\"one\", \"two\"} // type: [2]string\n\tvar a2 [2]string // type: [2]string\n\ta3 := [3]string{} // type: [3]string\n\n\ta2 = a1\n\n\tfmt.Println(a2)\n\n\t// this can't be done, as it is not of the same type:\n\ta3 = a2\n}", - "file": "arrays_slices/src/types/arrays/main.go", - "lang": "go", - "name": "arrays", - "start": 5, - "end": 19, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "run", - "." - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go run .", - "exit": "-1", - "run": ".", - "src": "arrays_slices/src/types/arrays" - }, - "expected_exit": -1, - "file": "arrays_slices", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\n# demo\n./main.go:9:2: a3 declared and not used\n./main.go:16:7: cannot use a2 (variable of type [2]string) as [3]string value in assignment", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/03-collections/arrays_slices/src/types/arrays", - "err": { - "Stderr": null - }, - "exit": 1, - "stderr": "IyBkZW1vCi4vbWFpbi5nbzo5OjI6IGEzIGRlY2xhcmVkIGFuZCBub3QgdXNlZAouL21haW4uZ286MTY6NzogY2Fubm90IHVzZSBhMiAodmFyaWFibGUgb2YgdHlwZSBbMl1zdHJpbmcpIGFzIFszXXN0cmluZyB2YWx1ZSBpbiBhc3NpZ25tZW50", - "duration": 799927291, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\n# demo\n./main.go:9:2: a3 declared and not used\n./main.go:16:7: cannot use a2 (variable of type [2]string) as [3]string value in assignment", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/03-collections/arrays_slices/src/types/arrays", - "err": { - "Stderr": null - }, - "exit": 1, - "stderr": "IyBkZW1vCi4vbWFpbi5nbzo5OjI6IGEzIGRlY2xhcmVkIGFuZCBub3QgdXNlZAouL21haW4uZ286MTY6NzogY2Fubm90IHVzZSBhMiAodmFyaWFibGUgb2YgdHlwZSBbMl1zdHJpbmcpIGFzIFszXXN0cmluZyB2YWx1ZSBpbiBhc3NpZ25tZW50", - "duration": 799927291, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "arrays_slices", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.10:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Length of the array is part of its type definition.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 10, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "arrays_slices.md", - "nodes": [ - { - "text": "Slices, are not fixed length, so a slices type is comprised of just the type it will store. For example, in ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-11" - }, - "file": "arrays_slices.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-11" - }, - "nodes": [ - { - "text": "Listing 1.11", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-11" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", the type for slice, ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "arrays_slices.md", - "nodes": [ - { - "text": "[]string{\"one\", \"two\"}", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ", is ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "arrays_slices.md", - "nodes": [ - { - "text": "[]string", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-11", - "type": "listing" - }, - "file": "arrays_slices.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "arrays_slices", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "snippet": "slices", - "src": "arrays_slices/src/types/slice/main.go" - }, - "lang": "go", - "nodes": [ - { - "content": "func main() {\n\ts1 := []string{\"one\", \"two\"} // Type: []string\n\tvar s2 []string\n\ts3 := []int{}\n\n\ts2 = s1\n\n\tfmt.Println(s2)\n\n\t// this can't be done, as it is not of the same type\n\ts3 = s2\n}", - "file": "arrays_slices/src/types/slice/main.go", - "lang": "go", - "name": "slices", - "start": 5, - "end": 19, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "run", - "." - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go run .", - "exit": "-1", - "run": ".", - "src": "arrays_slices/src/types/slice" - }, - "expected_exit": -1, - "file": "arrays_slices", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\n# demo\n./main.go:9:2: s3 declared and not used\n./main.go:16:7: cannot use s2 (variable of type []string) as []int value in assignment", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/03-collections/arrays_slices/src/types/slice", - "err": { - "Stderr": null - }, - "exit": 1, - "stderr": "IyBkZW1vCi4vbWFpbi5nbzo5OjI6IHMzIGRlY2xhcmVkIGFuZCBub3QgdXNlZAouL21haW4uZ286MTY6NzogY2Fubm90IHVzZSBzMiAodmFyaWFibGUgb2YgdHlwZSBbXXN0cmluZykgYXMgW11pbnQgdmFsdWUgaW4gYXNzaWdubWVudA==", - "duration": 1138427792, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\n# demo\n./main.go:9:2: s3 declared and not used\n./main.go:16:7: cannot use s2 (variable of type []string) as []int value in assignment", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/03-collections/arrays_slices/src/types/slice", - "err": { - "Stderr": null - }, - "exit": 1, - "stderr": "IyBkZW1vCi4vbWFpbi5nbzo5OjI6IHMzIGRlY2xhcmVkIGFuZCBub3QgdXNlZAouL21haW4uZ286MTY6NzogY2Fubm90IHVzZSBzMiAodmFyaWFibGUgb2YgdHlwZSBbXXN0cmluZykgYXMgW11pbnQgdmFsdWUgaW4gYXNzaWdubWVudA==", - "duration": 1138427792, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "arrays_slices", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.11:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Length is not part of of a slice's type definition.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 11, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "arrays_slices.md", - "level": 2, - "nodes": [ - { - "text": "Setting Array and Slice Values", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "arrays_slices.md", - "nodes": [ - { - "text": "If you create two like arrays, and then set the value of one array to the other, they still continue to have their own memory space. In ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-12" - }, - "file": "arrays_slices.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-12" - }, - "nodes": [ - { - "text": "Listing 1.12", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-12" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": " when ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "arrays_slices.md", - "nodes": [ - { - "text": "a1", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " is assigned to ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "arrays_slices.md", - "nodes": [ - { - "text": "a2", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ", array receives copies of the values in ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "arrays_slices.md", - "nodes": [ - { - "text": "a1", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ". Changing what value is in ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "arrays_slices.md", - "nodes": [ - { - "text": "a1[0]", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " does not affect the previous value that was there, so ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "arrays_slices.md", - "nodes": [ - { - "text": "a2[0]", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " will still be able to access the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "arrays_slices.md", - "nodes": [ - { - "text": "\"one\"", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " string.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-12", - "type": "listing" - }, - "file": "arrays_slices.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "arrays_slices", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "snippet": "main", - "src": "arrays_slices/src/copy/main.go" - }, - "lang": "go", - "nodes": [ - { - "content": "func main() {\n\ta1 := [2]string{\"one\", \"two\"}\n\ta2 := [2]string{}\n\n\ta2 = a1\n\n\tfmt.Println(\"a1:\", a1)\n\tfmt.Println(\"a2:\", a2)\n\n\ta1[0] = \"three\"\n\n\tfmt.Println(\"a1:\", a1)\n\tfmt.Println(\"a2:\", a2)\n}", - "file": "arrays_slices/src/copy/main.go", - "lang": "go", - "name": "main", - "start": 5, - "end": 21, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "run", - "." - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go run .", - "run": ".", - "src": "arrays_slices/src/copy" - }, - "expected_exit": 0, - "file": "arrays_slices", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\na1: [one two]\na2: [one two]\na1: [three two]\na2: [one two]", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/03-collections/arrays_slices/src/copy", - "stdout": "YTE6IFtvbmUgdHdvXQphMjogW29uZSB0d29dCmExOiBbdGhyZWUgdHdvXQphMjogW29uZSB0d29d", - "duration": 1189342500, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\na1: [one two]\na2: [one two]\na1: [three two]\na2: [one two]", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/03-collections/arrays_slices/src/copy", - "stdout": "YTE6IFtvbmUgdHdvXQphMjogW29uZSB0d29dCmExOiBbdGhyZWUgdHdvXQphMjogW29uZSB0d29d", - "duration": 1189342500, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "arrays_slices", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.12:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Arrays, and slices, have separate memory spaces, but can share the same values.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 12, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "arrays_slices.md", - "level": 2, - "nodes": [ - { - "text": "Appending To Slices", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "arrays_slices.md", - "nodes": [ - { - "text": "Unlike object oriented languages, slices and arrays don't have functions on them to allow you to append, remove, index, or otherwise manipulate the values in the array or slice. Instead, it is expected that those functions can be implemented by the end user. With the introduction of Generics in Go 1.18, there is much more flexibility in how these functions can be implemented.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "arrays_slices.md", - "nodes": [ - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "builtin#append", - "href": "https://pkg.go.dev/builtin#append", - "target": "_blank" - }, - "file": "arrays_slices.md", - "nodes": [ - { - "atom": "code", - "file": "arrays_slices.md", - "nodes": [ - { - "text": "append", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/builtin#append" - } - ], - { - "text": " function, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-13" - }, - "file": "arrays_slices.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-13" - }, - "nodes": [ - { - "text": "Listing 1.13", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-13" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", can be used to append values to a slice. While appending only works with slices, we will see later how an array can be coerced into a slice.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-13", - "type": "listing" - }, - "file": "arrays_slices.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "doc", - "builtin.append" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "doc": "builtin.append", - "exec": "go doc builtin.append" - }, - "expected_exit": 0, - "file": "arrays_slices", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc builtin.append\n\npackage builtin // import \u0026#34;builtin\u0026#34;\n\nfunc append(slice []Type, elems ...Type) []Type\n The append built-in function appends elements to the end of a slice.\n If it has sufficient capacity, the destination is resliced to accommodate\n the new elements. If it does not, a new underlying array will be allocated.\n Append returns the updated slice. It is therefore necessary to store the\n result of append, often in the variable holding the slice itself:\n\n slice = append(slice, elem1, elem2)\n slice = append(slice, anotherSlice...)\n\n As a special case, it is legal to append a string to a byte slice, like\n this:\n\n slice = append([]byte(\u0026#34;hello \u0026#34;), \u0026#34;world\u0026#34;...)", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "builtin.append" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBidWlsdGluIC8vIGltcG9ydCAiYnVpbHRpbiIKCmZ1bmMgYXBwZW5kKHNsaWNlIFtdVHlwZSwgZWxlbXMgLi4uVHlwZSkgW11UeXBlCiAgICBUaGUgYXBwZW5kIGJ1aWx0LWluIGZ1bmN0aW9uIGFwcGVuZHMgZWxlbWVudHMgdG8gdGhlIGVuZCBvZiBhIHNsaWNlLgogICAgSWYgaXQgaGFzIHN1ZmZpY2llbnQgY2FwYWNpdHksIHRoZSBkZXN0aW5hdGlvbiBpcyByZXNsaWNlZCB0byBhY2NvbW1vZGF0ZQogICAgdGhlIG5ldyBlbGVtZW50cy4gSWYgaXQgZG9lcyBub3QsIGEgbmV3IHVuZGVybHlpbmcgYXJyYXkgd2lsbCBiZSBhbGxvY2F0ZWQuCiAgICBBcHBlbmQgcmV0dXJucyB0aGUgdXBkYXRlZCBzbGljZS4gSXQgaXMgdGhlcmVmb3JlIG5lY2Vzc2FyeSB0byBzdG9yZSB0aGUKICAgIHJlc3VsdCBvZiBhcHBlbmQsIG9mdGVuIGluIHRoZSB2YXJpYWJsZSBob2xkaW5nIHRoZSBzbGljZSBpdHNlbGY6CgogICAgICAgIHNsaWNlID0gYXBwZW5kKHNsaWNlLCBlbGVtMSwgZWxlbTIpCiAgICAgICAgc2xpY2UgPSBhcHBlbmQoc2xpY2UsIGFub3RoZXJTbGljZS4uLikKCiAgICBBcyBhIHNwZWNpYWwgY2FzZSwgaXQgaXMgbGVnYWwgdG8gYXBwZW5kIGEgc3RyaW5nIHRvIGEgYnl0ZSBzbGljZSwgbGlrZQogICAgdGhpczoKCiAgICAgICAgc2xpY2UgPSBhcHBlbmQoW11ieXRlKCJoZWxsbyAiKSwgIndvcmxkIi4uLik=", - "duration": 2161911333, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc builtin.append\n\npackage builtin // import \u0026#34;builtin\u0026#34;\n\nfunc append(slice []Type, elems ...Type) []Type\n The append built-in function appends elements to the end of a slice.\n If it has sufficient capacity, the destination is resliced to accommodate\n the new elements. If it does not, a new underlying array will be allocated.\n Append returns the updated slice. It is therefore necessary to store the\n result of append, often in the variable holding the slice itself:\n\n slice = append(slice, elem1, elem2)\n slice = append(slice, anotherSlice...)\n\n As a special case, it is legal to append a string to a byte slice, like\n this:\n\n slice = append([]byte(\u0026#34;hello \u0026#34;), \u0026#34;world\u0026#34;...)", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "builtin.append" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBidWlsdGluIC8vIGltcG9ydCAiYnVpbHRpbiIKCmZ1bmMgYXBwZW5kKHNsaWNlIFtdVHlwZSwgZWxlbXMgLi4uVHlwZSkgW11UeXBlCiAgICBUaGUgYXBwZW5kIGJ1aWx0LWluIGZ1bmN0aW9uIGFwcGVuZHMgZWxlbWVudHMgdG8gdGhlIGVuZCBvZiBhIHNsaWNlLgogICAgSWYgaXQgaGFzIHN1ZmZpY2llbnQgY2FwYWNpdHksIHRoZSBkZXN0aW5hdGlvbiBpcyByZXNsaWNlZCB0byBhY2NvbW1vZGF0ZQogICAgdGhlIG5ldyBlbGVtZW50cy4gSWYgaXQgZG9lcyBub3QsIGEgbmV3IHVuZGVybHlpbmcgYXJyYXkgd2lsbCBiZSBhbGxvY2F0ZWQuCiAgICBBcHBlbmQgcmV0dXJucyB0aGUgdXBkYXRlZCBzbGljZS4gSXQgaXMgdGhlcmVmb3JlIG5lY2Vzc2FyeSB0byBzdG9yZSB0aGUKICAgIHJlc3VsdCBvZiBhcHBlbmQsIG9mdGVuIGluIHRoZSB2YXJpYWJsZSBob2xkaW5nIHRoZSBzbGljZSBpdHNlbGY6CgogICAgICAgIHNsaWNlID0gYXBwZW5kKHNsaWNlLCBlbGVtMSwgZWxlbTIpCiAgICAgICAgc2xpY2UgPSBhcHBlbmQoc2xpY2UsIGFub3RoZXJTbGljZS4uLikKCiAgICBBcyBhIHNwZWNpYWwgY2FzZSwgaXQgaXMgbGVnYWwgdG8gYXBwZW5kIGEgc3RyaW5nIHRvIGEgYnl0ZSBzbGljZSwgbGlrZQogICAgdGhpczoKCiAgICAgICAgc2xpY2UgPSBhcHBlbmQoW11ieXRlKCJoZWxsbyAiKSwgIndvcmxkIi4uLik=", - "duration": 2161911333, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "arrays_slices", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.13:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "builtin#append", - "href": "https://pkg.go.dev/builtin#append", - "target": "_blank" - }, - "file": "arrays_slices", - "nodes": [ - [ - { - "atom": "code", - "file": "arrays_slices", - "nodes": [ - { - "text": "append", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/builtin#append" - } - ], - { - "text": " function.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 13, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "arrays_slices.md", - "nodes": [ - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "builtin#append", - "href": "https://pkg.go.dev/builtin#append", - "target": "_blank" - }, - "file": "arrays_slices.md", - "nodes": [ - { - "atom": "code", - "file": "arrays_slices.md", - "nodes": [ - { - "text": "append", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/builtin#append" - } - ], - { - "text": " function takes a slice and zero or more values to append to the slice. The return value is a new slice with the values appended to the original slice. All values being appended must be of the same type as the slice being appended to.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-14", - "type": "listing" - }, - "file": "arrays_slices.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "arrays_slices", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "snippet": "example", - "src": "arrays_slices/src/append/slice/append/main.go" - }, - "lang": "go", - "nodes": [ - { - "content": "func main() {\n\t// create a slice of strings\n\tvar names []string\n\n\t// append a name to the slice\n\tnames = append(names, \"Kris\")\n\n\tfmt.Println(names)\n\n\t// append multiple names to the slice\n\tnames = append(names, \"Janis\", \"Jimi\")\n\n\tfmt.Println(names)\n}", - "file": "arrays_slices/src/append/slice/append/main.go", - "lang": "go", - "name": "example", - "start": 5, - "end": 21, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "run", - "." - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go run .", - "run": ".", - "src": "arrays_slices/src/append/slice/append" - }, - "expected_exit": 0, - "file": "arrays_slices", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\n[Kris]\n[Kris Janis Jimi]", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/03-collections/arrays_slices/src/append/slice/append", - "stdout": "W0tyaXNdCltLcmlzIEphbmlzIEppbWld", - "duration": 1912039459, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\n[Kris]\n[Kris Janis Jimi]", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/03-collections/arrays_slices/src/append/slice/append", - "stdout": "W0tyaXNdCltLcmlzIEphbmlzIEppbWld", - "duration": 1912039459, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "arrays_slices", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.14:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Appending to a slice.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 14, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "arrays_slices.md", - "level": 2, - "nodes": [ - { - "text": "Appending Slices to Slices", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "arrays_slices.md", - "nodes": [ - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "builtin#append", - "href": "https://pkg.go.dev/builtin#append", - "target": "_blank" - }, - "file": "arrays_slices.md", - "nodes": [ - { - "atom": "code", - "file": "arrays_slices.md", - "nodes": [ - { - "text": "append", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/builtin#append" - } - ], - { - "text": " function, as previously, mentioned can take zero or more values to append to a slice. All values being appended must be of the same type as the slice being appended to. This means that we can not use a slice as the second argument to ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "builtin#append", - "href": "https://pkg.go.dev/builtin#append", - "target": "_blank" - }, - "file": "arrays_slices.md", - "nodes": [ - { - "atom": "code", - "file": "arrays_slices.md", - "nodes": [ - { - "text": "append", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/builtin#append" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-15", - "type": "listing" - }, - "file": "arrays_slices.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "arrays_slices", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "arrays_slices/src/append/slice/bad/main.go#example" - }, - "lang": "go", - "nodes": [ - { - "content": "func main() {\n\t// create a slice of strings\n\tvar names []string\n\n\t// append a name to the slice\n\tnames = append(names, \"Kris\")\n\n\tfmt.Println(names)\n\n\t// create another slice of strings\n\tmore := []string{\"Janis\", \"Jimi\"}\n\n\t// append multiple names to the slice\n\tnames = append(names, more)\n\n\tfmt.Println(names)\n}", - "file": "arrays_slices/src/append/slice/bad/main.go", - "lang": "go", - "name": "example", - "start": 5, - "end": 24, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "run", - "." - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go run .", - "exit": "-1", - "run": ".", - "src": "arrays_slices/src/append/slice/bad" - }, - "expected_exit": -1, - "file": "arrays_slices", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\n# demo\n./main.go:19:24: cannot use more (variable of type []string) as string value in argument to append", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/03-collections/arrays_slices/src/append/slice/bad", - "err": { - "Stderr": null - }, - "exit": 1, - "stderr": "IyBkZW1vCi4vbWFpbi5nbzoxOToyNDogY2Fubm90IHVzZSBtb3JlICh2YXJpYWJsZSBvZiB0eXBlIFtdc3RyaW5nKSBhcyBzdHJpbmcgdmFsdWUgaW4gYXJndW1lbnQgdG8gYXBwZW5k", - "duration": 1466208500, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\n# demo\n./main.go:19:24: cannot use more (variable of type []string) as string value in argument to append", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/03-collections/arrays_slices/src/append/slice/bad", - "err": { - "Stderr": null - }, - "exit": 1, - "stderr": "IyBkZW1vCi4vbWFpbi5nbzoxOToyNDogY2Fubm90IHVzZSBtb3JlICh2YXJpYWJsZSBvZiB0eXBlIFtdc3RyaW5nKSBhcyBzdHJpbmcgdmFsdWUgaW4gYXJndW1lbnQgdG8gYXBwZW5k", - "duration": 1466208500, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "arrays_slices", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.15:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Error attempting to append two slices together.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 15, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "arrays_slices.md", - "nodes": [ - { - "text": "Consider ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-15" - }, - "file": "arrays_slices.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-15" - }, - "nodes": [ - { - "text": "Listing 1.15", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-15" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ". When trying to pass a second slice to the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "builtin#append", - "href": "https://pkg.go.dev/builtin#append", - "target": "_blank" - }, - "file": "arrays_slices.md", - "nodes": [ - { - "atom": "code", - "file": "arrays_slices.md", - "nodes": [ - { - "text": "append", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/builtin#append" - } - ], - { - "text": " function, we get a compilation error, or a runtime panic.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "arrays_slices.md", - "nodes": [ - { - "text": "The reason for this error is that the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "builtin#append", - "href": "https://pkg.go.dev/builtin#append", - "target": "_blank" - }, - "file": "arrays_slices.md", - "nodes": [ - { - "atom": "code", - "file": "arrays_slices.md", - "nodes": [ - { - "text": "append", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/builtin#append" - } - ], - { - "text": " function expects values to be of the same type as the slice being appended to. In short the type ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "arrays_slices.md", - "nodes": [ - { - "text": "[]string", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " is not the same type as ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "arrays_slices.md", - "nodes": [ - { - "text": "string", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "arrays_slices.md", - "nodes": [ - { - "text": "In order to append the second slice to the first we need to pass the individual values of the second slice to the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "builtin#append", - "href": "https://pkg.go.dev/builtin#append", - "target": "_blank" - }, - "file": "arrays_slices.md", - "nodes": [ - { - "atom": "code", - "file": "arrays_slices.md", - "nodes": [ - { - "text": "append", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/builtin#append" - } - ], - { - "text": " function. One way to do this would be to use a loop to iterate over the values in the second slice and append them to the first slice, as seen in ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-16" - }, - "file": "arrays_slices.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-16" - }, - "nodes": [ - { - "text": "Listing 1.16", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-16" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ". Iteration will be discussed later in ", - "type": "hype.Text" - }, - { - "atom": "binding", - "attributes": { - "part": "maps-control" - }, - "file": "arrays_slices.md", - "type": "*hype.Element" - }, - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-16", - "type": "listing" - }, - "file": "arrays_slices.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "arrays_slices", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "snippet": "example", - "src": "arrays_slices/src/append/slice/for/main.go" - }, - "lang": "go", - "nodes": [ - { - "content": "func main() {\n\t// create a slice of strings\n\tvar names []string\n\n\t// append a name to the slice\n\tnames = append(names, \"Kris\")\n\n\tfmt.Println(names)\n\n\t// create another slice of strings\n\tmore := []string{\"Janis\", \"Jimi\"}\n\n\t// loop through the additional names\n\tfor _, name := range more {\n\n\t\t// append each name to the slice\n\t\tnames = append(names, name)\n\t}\n\n\tfmt.Println(names)\n}", - "file": "arrays_slices/src/append/slice/for/main.go", - "lang": "go", - "name": "example", - "start": 7, - "end": 30, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "run", - "." - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go run .", - "run": ".", - "src": "arrays_slices/src/append/slice/for" - }, - "expected_exit": 0, - "file": "arrays_slices", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\n[Kris]\n[Kris Janis Jimi]", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/03-collections/arrays_slices/src/append/slice/for", - "stdout": "W0tyaXNdCltLcmlzIEphbmlzIEppbWld", - "duration": 1438718583, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\n[Kris]\n[Kris Janis Jimi]", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/03-collections/arrays_slices/src/append/slice/for", - "stdout": "W0tyaXNdCltLcmlzIEphbmlzIEppbWld", - "duration": 1438718583, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "arrays_slices", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.16:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Appending two slices using a ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "arrays_slices", - "nodes": [ - { - "text": "for", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " loop.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 16, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "arrays_slices.md", - "nodes": [ - { - "text": "While using a loop will work, it is not the most efficient way to append a slice to a slice. Functions in Go, as we will see later in this ", - "type": "hype.Text" - }, - { - "atom": "binding", - "attributes": { - "whole": "" - }, - "file": "arrays_slices.md", - "type": "*hype.Element" - }, - { - "text": ", accept ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "href": "https://en.wikipedia.org/wiki/Variadic_function", - "target": "_blank" - }, - "file": "arrays_slices.md", - "nodes": [ - { - "text": "variadic arguments", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "https://en.wikipedia.org/wiki/Variadic_function" - } - ], - { - "text": ". Variadic functions accept zero or more arguments of the same type through the use of the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "arrays_slices.md", - "nodes": [ - { - "text": "...", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " operator.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "arrays_slices.md", - "nodes": [ - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "builtin#append", - "href": "https://pkg.go.dev/builtin#append", - "target": "_blank" - }, - "file": "arrays_slices.md", - "nodes": [ - { - "atom": "code", - "file": "arrays_slices.md", - "nodes": [ - { - "text": "append", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/builtin#append" - } - ], - { - "text": " function, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-17" - }, - "file": "arrays_slices.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-17" - }, - "nodes": [ - { - "text": "Listing 1.17", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-17" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": " accepts a variadic argument, and will accept any number of values of the same type as the slice being appended to.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-17", - "type": "listing" - }, - "file": "arrays_slices.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "doc", - "builtin.append" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "doc": "builtin.append", - "exec": "go doc builtin.append" - }, - "expected_exit": 0, - "file": "arrays_slices", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc builtin.append\n\npackage builtin // import \u0026#34;builtin\u0026#34;\n\nfunc append(slice []Type, elems ...Type) []Type\n The append built-in function appends elements to the end of a slice.\n If it has sufficient capacity, the destination is resliced to accommodate\n the new elements. If it does not, a new underlying array will be allocated.\n Append returns the updated slice. It is therefore necessary to store the\n result of append, often in the variable holding the slice itself:\n\n slice = append(slice, elem1, elem2)\n slice = append(slice, anotherSlice...)\n\n As a special case, it is legal to append a string to a byte slice, like\n this:\n\n slice = append([]byte(\u0026#34;hello \u0026#34;), \u0026#34;world\u0026#34;...)", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "builtin.append" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBidWlsdGluIC8vIGltcG9ydCAiYnVpbHRpbiIKCmZ1bmMgYXBwZW5kKHNsaWNlIFtdVHlwZSwgZWxlbXMgLi4uVHlwZSkgW11UeXBlCiAgICBUaGUgYXBwZW5kIGJ1aWx0LWluIGZ1bmN0aW9uIGFwcGVuZHMgZWxlbWVudHMgdG8gdGhlIGVuZCBvZiBhIHNsaWNlLgogICAgSWYgaXQgaGFzIHN1ZmZpY2llbnQgY2FwYWNpdHksIHRoZSBkZXN0aW5hdGlvbiBpcyByZXNsaWNlZCB0byBhY2NvbW1vZGF0ZQogICAgdGhlIG5ldyBlbGVtZW50cy4gSWYgaXQgZG9lcyBub3QsIGEgbmV3IHVuZGVybHlpbmcgYXJyYXkgd2lsbCBiZSBhbGxvY2F0ZWQuCiAgICBBcHBlbmQgcmV0dXJucyB0aGUgdXBkYXRlZCBzbGljZS4gSXQgaXMgdGhlcmVmb3JlIG5lY2Vzc2FyeSB0byBzdG9yZSB0aGUKICAgIHJlc3VsdCBvZiBhcHBlbmQsIG9mdGVuIGluIHRoZSB2YXJpYWJsZSBob2xkaW5nIHRoZSBzbGljZSBpdHNlbGY6CgogICAgICAgIHNsaWNlID0gYXBwZW5kKHNsaWNlLCBlbGVtMSwgZWxlbTIpCiAgICAgICAgc2xpY2UgPSBhcHBlbmQoc2xpY2UsIGFub3RoZXJTbGljZS4uLikKCiAgICBBcyBhIHNwZWNpYWwgY2FzZSwgaXQgaXMgbGVnYWwgdG8gYXBwZW5kIGEgc3RyaW5nIHRvIGEgYnl0ZSBzbGljZSwgbGlrZQogICAgdGhpczoKCiAgICAgICAgc2xpY2UgPSBhcHBlbmQoW11ieXRlKCJoZWxsbyAiKSwgIndvcmxkIi4uLik=", - "duration": 874853042, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc builtin.append\n\npackage builtin // import \u0026#34;builtin\u0026#34;\n\nfunc append(slice []Type, elems ...Type) []Type\n The append built-in function appends elements to the end of a slice.\n If it has sufficient capacity, the destination is resliced to accommodate\n the new elements. If it does not, a new underlying array will be allocated.\n Append returns the updated slice. It is therefore necessary to store the\n result of append, often in the variable holding the slice itself:\n\n slice = append(slice, elem1, elem2)\n slice = append(slice, anotherSlice...)\n\n As a special case, it is legal to append a string to a byte slice, like\n this:\n\n slice = append([]byte(\u0026#34;hello \u0026#34;), \u0026#34;world\u0026#34;...)", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "builtin.append" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBidWlsdGluIC8vIGltcG9ydCAiYnVpbHRpbiIKCmZ1bmMgYXBwZW5kKHNsaWNlIFtdVHlwZSwgZWxlbXMgLi4uVHlwZSkgW11UeXBlCiAgICBUaGUgYXBwZW5kIGJ1aWx0LWluIGZ1bmN0aW9uIGFwcGVuZHMgZWxlbWVudHMgdG8gdGhlIGVuZCBvZiBhIHNsaWNlLgogICAgSWYgaXQgaGFzIHN1ZmZpY2llbnQgY2FwYWNpdHksIHRoZSBkZXN0aW5hdGlvbiBpcyByZXNsaWNlZCB0byBhY2NvbW1vZGF0ZQogICAgdGhlIG5ldyBlbGVtZW50cy4gSWYgaXQgZG9lcyBub3QsIGEgbmV3IHVuZGVybHlpbmcgYXJyYXkgd2lsbCBiZSBhbGxvY2F0ZWQuCiAgICBBcHBlbmQgcmV0dXJucyB0aGUgdXBkYXRlZCBzbGljZS4gSXQgaXMgdGhlcmVmb3JlIG5lY2Vzc2FyeSB0byBzdG9yZSB0aGUKICAgIHJlc3VsdCBvZiBhcHBlbmQsIG9mdGVuIGluIHRoZSB2YXJpYWJsZSBob2xkaW5nIHRoZSBzbGljZSBpdHNlbGY6CgogICAgICAgIHNsaWNlID0gYXBwZW5kKHNsaWNlLCBlbGVtMSwgZWxlbTIpCiAgICAgICAgc2xpY2UgPSBhcHBlbmQoc2xpY2UsIGFub3RoZXJTbGljZS4uLikKCiAgICBBcyBhIHNwZWNpYWwgY2FzZSwgaXQgaXMgbGVnYWwgdG8gYXBwZW5kIGEgc3RyaW5nIHRvIGEgYnl0ZSBzbGljZSwgbGlrZQogICAgdGhpczoKCiAgICAgICAgc2xpY2UgPSBhcHBlbmQoW11ieXRlKCJoZWxsbyAiKSwgIndvcmxkIi4uLik=", - "duration": 874853042, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "arrays_slices", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.17:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "builtin#append", - "href": "https://pkg.go.dev/builtin#append", - "target": "_blank" - }, - "file": "arrays_slices", - "nodes": [ - [ - { - "atom": "code", - "file": "arrays_slices", - "nodes": [ - { - "text": "append", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/builtin#append" - } - ], - { - "text": " function with variadic arguments.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 17, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "arrays_slices.md", - "nodes": [ - { - "text": "While we can use variadic arguments to accept multiple arguments of the same type, the reverse is also true. In ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-18" - }, - "file": "arrays_slices.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-18" - }, - "nodes": [ - { - "text": "Listing 1.18", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-18" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": " the variadic operator, ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "arrays_slices.md", - "nodes": [ - { - "text": "...", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ", is used to take the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "arrays_slices.md", - "nodes": [ - { - "text": "more", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " slice and append it to the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "arrays_slices.md", - "nodes": [ - { - "text": "names", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " slice.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-18", - "type": "listing" - }, - "file": "arrays_slices.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "arrays_slices", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "snippet": "example", - "src": "arrays_slices/src/append/slice/variadic/main.go" - }, - "lang": "go", - "nodes": [ - { - "content": "func main() {\n\t// create a slice of strings\n\tvar names []string\n\n\t// append a name to the slice\n\tnames = append(names, \"Kris\")\n\n\tfmt.Println(names)\n\n\t// create another slice of strings\n\tmore := []string{\"Janis\", \"Jimi\"}\n\n\t// use variadic operator to append more to names\n\tnames = append(names, more...)\n\n\t// equivalent to:\n\t// names = append(names, \"Janis\", \"Jimi\")\n\n\tfmt.Println(names)\n}", - "file": "arrays_slices/src/append/slice/variadic/main.go", - "lang": "go", - "name": "example", - "start": 7, - "end": 29, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "run", - "." - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go run .", - "run": ".", - "src": "arrays_slices/src/append/slice/variadic" - }, - "expected_exit": 0, - "file": "arrays_slices", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\n[Kris]\n[Kris Janis Jimi]", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/03-collections/arrays_slices/src/append/slice/variadic", - "stdout": "W0tyaXNdCltLcmlzIEphbmlzIEppbWld", - "duration": 2061193042, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\n[Kris]\n[Kris Janis Jimi]", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/03-collections/arrays_slices/src/append/slice/variadic", - "stdout": "W0tyaXNdCltLcmlzIEphbmlzIEppbWld", - "duration": 2061193042, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "arrays_slices", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.18:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Appending two slices using the variadic operator.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 18, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "title": "List Types: Arrays and Slices", - "type": "*hype.Page" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "type": "*hype.Include" - } - ], - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "include", - "attributes": { - "src": "internals/internals.md" - }, - "dir": "internals", - "file": "module.md", - "nodes": [ - [ - { - "atom": "page", - "file": "internals.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "h1", - "file": "internals.md", - "level": 1, - "nodes": [ - { - "text": "How Slices Work", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "internals.md", - "nodes": [ - { - "text": "While arrays are very straightforward to understand, they can hold a fixed number things, slices are a bit more complex. Slices can grow as needed to store as many values as needed.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "internals.md", - "nodes": [ - { - "text": "To help understand how slices work, let's examine slices a bit further. In ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-19" - }, - "file": "internals.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-19" - }, - "nodes": [ - { - "text": "Listing 1.19", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-19" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": " we see that a slice has three parts; length, capacity, and pointer to an underlying array.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-19", - "type": "listing" - }, - "file": "internals.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "internals", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "snippet": "example", - "src": "internals/src/internal/main.go" - }, - "lang": "go", - "nodes": [ - { - "content": "type Slice struct {\n\t// N: the number of actual values in the array\n\tLength int\n\t// 10: the maximum number of values that can be stored in the array\n\tCapacity int\n\t// [\"a\", \"b\", \"c\"]: the actual values stored in the array\n\tArray [10]string\n}", - "file": "internals/src/internal/main.go", - "lang": "go", - "name": "example", - "start": 5, - "end": 15, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "ul", - "file": "internals", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "li", - "file": "internals", - "list-type": "ul", - "nodes": [ - { - "text": "Length - How many values are in the slice", - "type": "hype.Text" - } - ], - "type": "*hype.LI" - } - ], - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "li", - "file": "internals", - "list-type": "ul", - "nodes": [ - { - "text": "Capacity - How many values can be stored in the slice", - "type": "hype.Text" - } - ], - "type": "*hype.LI" - } - ], - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "li", - "file": "internals", - "list-type": "ul", - "nodes": [ - { - "text": "Pointer to the underlying array - Where the values are actually stored", - "type": "hype.Text" - } - ], - "type": "*hype.LI" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "type": "*hype.UL" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "internals", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.19:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Theoretical representation of slice internals.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 19, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "internals.md", - "nodes": [ - { - "text": "It's important to note that this definition of a slice, is purely an academic representation of how slices are implemented in Go.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "internals.md", - "level": 2, - "nodes": [ - { - "text": "Length And Capacity", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "internals.md", - "nodes": [ - { - "text": "While writing programs, we often to need to know how many values are in a collection type, such as an array or slice. Go provides a built-in function to do exactly this, called ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "builtin#len", - "href": "https://pkg.go.dev/builtin#len", - "target": "_blank" - }, - "file": "internals.md", - "nodes": [ - { - "atom": "code", - "file": "internals.md", - "nodes": [ - { - "text": "len", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/builtin#len" - } - ], - { - "text": ". The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "builtin#len", - "href": "https://pkg.go.dev/builtin#len", - "target": "_blank" - }, - "file": "internals.md", - "nodes": [ - { - "atom": "code", - "file": "internals.md", - "nodes": [ - { - "text": "len", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/builtin#len" - } - ], - { - "text": " function tells us how many elements the collection ", - "type": "hype.Text" - }, - { - "atom": "em", - "file": "internals.md", - "nodes": [ - { - "text": "actually", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " has.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-20", - "type": "listing" - }, - "file": "internals.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "doc", - "builtin.len" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "doc": "builtin.len", - "exec": "go doc builtin.len", - "src": "internals/src/cap" - }, - "expected_exit": 0, - "file": "internals", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc builtin.len\n\npackage builtin // import \u0026#34;builtin\u0026#34;\n\nfunc len(v Type) int\n The len built-in function returns the length of v, according to its type:\n\n Array: the number of elements in v.\n Pointer to array: the number of elements in *v (even if v is nil).\n Slice, or map: the number of elements in v; if v is nil, len(v) is zero.\n String: the number of bytes in v.\n Channel: the number of elements queued (unread) in the channel buffer;\n if v is nil, len(v) is zero.\n\n For some arguments, such as a string literal or a simple array expression,\n the result can be a constant. See the Go language specification\u0026#39;s \u0026#34;Length\n and capacity\u0026#34; section for details.", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "builtin.len" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/03-collections/internals/src/cap", - "stdout": "cGFja2FnZSBidWlsdGluIC8vIGltcG9ydCAiYnVpbHRpbiIKCmZ1bmMgbGVuKHYgVHlwZSkgaW50CiAgICBUaGUgbGVuIGJ1aWx0LWluIGZ1bmN0aW9uIHJldHVybnMgdGhlIGxlbmd0aCBvZiB2LCBhY2NvcmRpbmcgdG8gaXRzIHR5cGU6CgogICAgICAgIEFycmF5OiB0aGUgbnVtYmVyIG9mIGVsZW1lbnRzIGluIHYuCiAgICAgICAgUG9pbnRlciB0byBhcnJheTogdGhlIG51bWJlciBvZiBlbGVtZW50cyBpbiAqdiAoZXZlbiBpZiB2IGlzIG5pbCkuCiAgICAgICAgU2xpY2UsIG9yIG1hcDogdGhlIG51bWJlciBvZiBlbGVtZW50cyBpbiB2OyBpZiB2IGlzIG5pbCwgbGVuKHYpIGlzIHplcm8uCiAgICAgICAgU3RyaW5nOiB0aGUgbnVtYmVyIG9mIGJ5dGVzIGluIHYuCiAgICAgICAgQ2hhbm5lbDogdGhlIG51bWJlciBvZiBlbGVtZW50cyBxdWV1ZWQgKHVucmVhZCkgaW4gdGhlIGNoYW5uZWwgYnVmZmVyOwogICAgICAgICAgICAgICAgIGlmIHYgaXMgbmlsLCBsZW4odikgaXMgemVyby4KCiAgICBGb3Igc29tZSBhcmd1bWVudHMsIHN1Y2ggYXMgYSBzdHJpbmcgbGl0ZXJhbCBvciBhIHNpbXBsZSBhcnJheSBleHByZXNzaW9uLAogICAgdGhlIHJlc3VsdCBjYW4gYmUgYSBjb25zdGFudC4gU2VlIHRoZSBHbyBsYW5ndWFnZSBzcGVjaWZpY2F0aW9uJ3MgIkxlbmd0aAogICAgYW5kIGNhcGFjaXR5IiBzZWN0aW9uIGZvciBkZXRhaWxzLg==", - "duration": 2346175084, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc builtin.len\n\npackage builtin // import \u0026#34;builtin\u0026#34;\n\nfunc len(v Type) int\n The len built-in function returns the length of v, according to its type:\n\n Array: the number of elements in v.\n Pointer to array: the number of elements in *v (even if v is nil).\n Slice, or map: the number of elements in v; if v is nil, len(v) is zero.\n String: the number of bytes in v.\n Channel: the number of elements queued (unread) in the channel buffer;\n if v is nil, len(v) is zero.\n\n For some arguments, such as a string literal or a simple array expression,\n the result can be a constant. See the Go language specification\u0026#39;s \u0026#34;Length\n and capacity\u0026#34; section for details.", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "builtin.len" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/03-collections/internals/src/cap", - "stdout": "cGFja2FnZSBidWlsdGluIC8vIGltcG9ydCAiYnVpbHRpbiIKCmZ1bmMgbGVuKHYgVHlwZSkgaW50CiAgICBUaGUgbGVuIGJ1aWx0LWluIGZ1bmN0aW9uIHJldHVybnMgdGhlIGxlbmd0aCBvZiB2LCBhY2NvcmRpbmcgdG8gaXRzIHR5cGU6CgogICAgICAgIEFycmF5OiB0aGUgbnVtYmVyIG9mIGVsZW1lbnRzIGluIHYuCiAgICAgICAgUG9pbnRlciB0byBhcnJheTogdGhlIG51bWJlciBvZiBlbGVtZW50cyBpbiAqdiAoZXZlbiBpZiB2IGlzIG5pbCkuCiAgICAgICAgU2xpY2UsIG9yIG1hcDogdGhlIG51bWJlciBvZiBlbGVtZW50cyBpbiB2OyBpZiB2IGlzIG5pbCwgbGVuKHYpIGlzIHplcm8uCiAgICAgICAgU3RyaW5nOiB0aGUgbnVtYmVyIG9mIGJ5dGVzIGluIHYuCiAgICAgICAgQ2hhbm5lbDogdGhlIG51bWJlciBvZiBlbGVtZW50cyBxdWV1ZWQgKHVucmVhZCkgaW4gdGhlIGNoYW5uZWwgYnVmZmVyOwogICAgICAgICAgICAgICAgIGlmIHYgaXMgbmlsLCBsZW4odikgaXMgemVyby4KCiAgICBGb3Igc29tZSBhcmd1bWVudHMsIHN1Y2ggYXMgYSBzdHJpbmcgbGl0ZXJhbCBvciBhIHNpbXBsZSBhcnJheSBleHByZXNzaW9uLAogICAgdGhlIHJlc3VsdCBjYW4gYmUgYSBjb25zdGFudC4gU2VlIHRoZSBHbyBsYW5ndWFnZSBzcGVjaWZpY2F0aW9uJ3MgIkxlbmd0aAogICAgYW5kIGNhcGFjaXR5IiBzZWN0aW9uIGZvciBkZXRhaWxzLg==", - "duration": 2346175084, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "internals", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.20:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "builtin#len", - "href": "https://pkg.go.dev/builtin#len", - "target": "_blank" - }, - "file": "internals", - "nodes": [ - [ - { - "atom": "code", - "file": "internals", - "nodes": [ - { - "text": "len", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/builtin#len" - } - ], - { - "text": " function.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 20, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "internals.md", - "nodes": [ - { - "text": "Occasionally, we may need to know how many elements the collection can hold. This is called capacity. The built-in ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "builtin#cap", - "href": "https://pkg.go.dev/builtin#cap", - "target": "_blank" - }, - "file": "internals.md", - "nodes": [ - { - "atom": "code", - "file": "internals.md", - "nodes": [ - { - "text": "cap", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/builtin#cap" - } - ], - { - "text": " function tells us the capacity of the slice, or how many elements it ", - "type": "hype.Text" - }, - { - "atom": "em", - "file": "internals.md", - "nodes": [ - { - "text": "can", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " have.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-21", - "type": "listing" - }, - "file": "internals.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "doc", - "builtin.cap" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "doc": "builtin.cap", - "exec": "go doc builtin.cap", - "src": "internals/src/cap" - }, - "expected_exit": 0, - "file": "internals", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc builtin.cap\n\npackage builtin // import \u0026#34;builtin\u0026#34;\n\nfunc cap(v Type) int\n The cap built-in function returns the capacity of v, according to its type:\n\n Array: the number of elements in v (same as len(v)).\n Pointer to array: the number of elements in *v (same as len(v)).\n Slice: the maximum length the slice can reach when resliced;\n if v is nil, cap(v) is zero.\n Channel: the channel buffer capacity, in units of elements;\n if v is nil, cap(v) is zero.\n\n For some arguments, such as a simple array expression, the result can be a\n constant. See the Go language specification\u0026#39;s \u0026#34;Length and capacity\u0026#34; section\n for details.", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "builtin.cap" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/03-collections/internals/src/cap", - "stdout": "cGFja2FnZSBidWlsdGluIC8vIGltcG9ydCAiYnVpbHRpbiIKCmZ1bmMgY2FwKHYgVHlwZSkgaW50CiAgICBUaGUgY2FwIGJ1aWx0LWluIGZ1bmN0aW9uIHJldHVybnMgdGhlIGNhcGFjaXR5IG9mIHYsIGFjY29yZGluZyB0byBpdHMgdHlwZToKCiAgICAgICAgQXJyYXk6IHRoZSBudW1iZXIgb2YgZWxlbWVudHMgaW4gdiAoc2FtZSBhcyBsZW4odikpLgogICAgICAgIFBvaW50ZXIgdG8gYXJyYXk6IHRoZSBudW1iZXIgb2YgZWxlbWVudHMgaW4gKnYgKHNhbWUgYXMgbGVuKHYpKS4KICAgICAgICBTbGljZTogdGhlIG1heGltdW0gbGVuZ3RoIHRoZSBzbGljZSBjYW4gcmVhY2ggd2hlbiByZXNsaWNlZDsKICAgICAgICBpZiB2IGlzIG5pbCwgY2FwKHYpIGlzIHplcm8uCiAgICAgICAgQ2hhbm5lbDogdGhlIGNoYW5uZWwgYnVmZmVyIGNhcGFjaXR5LCBpbiB1bml0cyBvZiBlbGVtZW50czsKICAgICAgICBpZiB2IGlzIG5pbCwgY2FwKHYpIGlzIHplcm8uCgogICAgRm9yIHNvbWUgYXJndW1lbnRzLCBzdWNoIGFzIGEgc2ltcGxlIGFycmF5IGV4cHJlc3Npb24sIHRoZSByZXN1bHQgY2FuIGJlIGEKICAgIGNvbnN0YW50LiBTZWUgdGhlIEdvIGxhbmd1YWdlIHNwZWNpZmljYXRpb24ncyAiTGVuZ3RoIGFuZCBjYXBhY2l0eSIgc2VjdGlvbgogICAgZm9yIGRldGFpbHMu", - "duration": 2044123541, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc builtin.cap\n\npackage builtin // import \u0026#34;builtin\u0026#34;\n\nfunc cap(v Type) int\n The cap built-in function returns the capacity of v, according to its type:\n\n Array: the number of elements in v (same as len(v)).\n Pointer to array: the number of elements in *v (same as len(v)).\n Slice: the maximum length the slice can reach when resliced;\n if v is nil, cap(v) is zero.\n Channel: the channel buffer capacity, in units of elements;\n if v is nil, cap(v) is zero.\n\n For some arguments, such as a simple array expression, the result can be a\n constant. See the Go language specification\u0026#39;s \u0026#34;Length and capacity\u0026#34; section\n for details.", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "builtin.cap" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/03-collections/internals/src/cap", - "stdout": "cGFja2FnZSBidWlsdGluIC8vIGltcG9ydCAiYnVpbHRpbiIKCmZ1bmMgY2FwKHYgVHlwZSkgaW50CiAgICBUaGUgY2FwIGJ1aWx0LWluIGZ1bmN0aW9uIHJldHVybnMgdGhlIGNhcGFjaXR5IG9mIHYsIGFjY29yZGluZyB0byBpdHMgdHlwZToKCiAgICAgICAgQXJyYXk6IHRoZSBudW1iZXIgb2YgZWxlbWVudHMgaW4gdiAoc2FtZSBhcyBsZW4odikpLgogICAgICAgIFBvaW50ZXIgdG8gYXJyYXk6IHRoZSBudW1iZXIgb2YgZWxlbWVudHMgaW4gKnYgKHNhbWUgYXMgbGVuKHYpKS4KICAgICAgICBTbGljZTogdGhlIG1heGltdW0gbGVuZ3RoIHRoZSBzbGljZSBjYW4gcmVhY2ggd2hlbiByZXNsaWNlZDsKICAgICAgICBpZiB2IGlzIG5pbCwgY2FwKHYpIGlzIHplcm8uCiAgICAgICAgQ2hhbm5lbDogdGhlIGNoYW5uZWwgYnVmZmVyIGNhcGFjaXR5LCBpbiB1bml0cyBvZiBlbGVtZW50czsKICAgICAgICBpZiB2IGlzIG5pbCwgY2FwKHYpIGlzIHplcm8uCgogICAgRm9yIHNvbWUgYXJndW1lbnRzLCBzdWNoIGFzIGEgc2ltcGxlIGFycmF5IGV4cHJlc3Npb24sIHRoZSByZXN1bHQgY2FuIGJlIGEKICAgIGNvbnN0YW50LiBTZWUgdGhlIEdvIGxhbmd1YWdlIHNwZWNpZmljYXRpb24ncyAiTGVuZ3RoIGFuZCBjYXBhY2l0eSIgc2VjdGlvbgogICAgZm9yIGRldGFpbHMu", - "duration": 2044123541, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "internals", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.21:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "builtin#cap", - "href": "https://pkg.go.dev/builtin#cap", - "target": "_blank" - }, - "file": "internals", - "nodes": [ - [ - { - "atom": "code", - "file": "internals", - "nodes": [ - { - "text": "cap", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/builtin#cap" - } - ], - { - "text": " function.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 21, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "internals.md", - "level": 2, - "nodes": [ - { - "text": "Growing A Slice", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "internals.md", - "nodes": [ - { - "text": "Slices in Go are dynamically sized, the Go runtime will increase the capacity of the underlying slice as necessary. In ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-22" - }, - "file": "internals.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-22" - }, - "nodes": [ - { - "text": "Listing 1.22", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-22" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": " we the first few growth stages of a slice as new values are added.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-22", - "type": "listing" - }, - "file": "internals.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "internals", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "snippet": "example", - "src": "internals/src/cap/main.go" - }, - "lang": "go", - "nodes": [ - { - "content": "func main() {\n\tnames := []string{}\n\tfmt.Println(\"len:\", len(names)) // 0\n\tfmt.Println(\"cap:\", cap(names)) // 0\n\n\tnames = append(names, \"Kurt\")\n\tfmt.Println(\"len:\", len(names)) // 1\n\tfmt.Println(\"cap:\", cap(names)) // 1\n\n\tnames = append(names, \"Janis\")\n\tfmt.Println(\"len:\", len(names)) // 2\n\tfmt.Println(\"cap:\", cap(names)) // 2\n\n\tnames = append(names, \"Jimi\")\n\tfmt.Println(\"len:\", len(names)) // 3\n\tfmt.Println(\"cap:\", cap(names)) // 4\n\n\tnames = append(names, \"Amy\")\n\tfmt.Println(\"len:\", len(names)) // 4\n\tfmt.Println(\"cap:\", cap(names)) // 4\n\n\tnames = append(names, \"Brian\")\n\n\tfmt.Println(\"len:\", len(names)) // 5\n\tfmt.Println(\"cap:\", cap(names)) // 8\n}", - "file": "internals/src/cap/main.go", - "lang": "go", - "name": "example", - "start": 5, - "end": 33, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "internals", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.22:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "builtin#cap", - "href": "https://pkg.go.dev/builtin#cap", - "target": "_blank" - }, - "file": "internals", - "nodes": [ - [ - { - "atom": "code", - "file": "internals", - "nodes": [ - { - "text": "cap", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/builtin#cap" - } - ], - { - "text": " function.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 22, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "internals.md", - "nodes": [ - { - "text": "The rate of growth can change with each Go release as the Go team fine tunes the runtime. Growth rate can also be dependent of architecture and operating system.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "internals.md", - "nodes": [ - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-23" - }, - "file": "internals.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-23" - }, - "nodes": [ - { - "text": "Listing 1.23", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-23" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": " demonstrates growth rate over a large number of iterations. As the capacity of the slice changes it will print the previous capacity and the new capacity.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-23", - "type": "listing" - }, - "file": "internals.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "internals", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "snippet": "example", - "src": "internals/src/cap-printer/main.go" - }, - "lang": "go", - "nodes": [ - { - "content": "func main() {\n\tN := 100_000_000\n\n\tsl := make([]int, 0)\n\n\that := cap(sl)\n\tfor i := 0; i \u003c N; i++ {\n\t\tsl = append(sl, i)\n\t\tc := cap(sl)\n\t\tif c != hat {\n\t\t\tfmt.Println(hat, c)\n\t\t}\n\t\that = c\n\t}\n}", - "file": "internals/src/cap-printer/main.go", - "lang": "go", - "name": "example", - "start": 5, - "end": 22, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "run", - "." - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go run .", - "run": ".", - "src": "internals/src/cap-printer" - }, - "expected_exit": 0, - "file": "internals", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\n0 1\n1 2\n2 4\n4 8\n8 16\n16 32\n32 64\n64 128\n128 256\n256 512\n512 848\n848 1280\n1280 1792\n1792 2560\n2560 3408\n3408 5120\n5120 7168\n7168 9216\n9216 12288\n12288 16384\n16384 21504\n21504 27648\n27648 34816\n34816 44032\n44032 55296\n55296 69632\n69632 88064\n88064 110592\n110592 139264\n139264 175104\n175104 219136\n219136 274432\n274432 344064\n344064 431104\n431104 539648\n539648 674816\n674816 843776\n843776 1055744\n1055744 1319936\n1319936 1650688\n1650688 2064384\n2064384 2581504\n2581504 3227648\n3227648 4035584\n4035584 5045248\n5045248 6306816\n6306816 7883776\n7883776 9854976\n9854976 12319744\n12319744 15399936\n15399936 19250176\n19250176 24062976\n24062976 30078976\n30078976 37599232\n37599232 46999552\n46999552 58749952\n58749952 73438208\n73438208 91798528\n91798528 114748416", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/03-collections/internals/src/cap-printer", - "stdout": "MCAxCjEgMgoyIDQKNCA4CjggMTYKMTYgMzIKMzIgNjQKNjQgMTI4CjEyOCAyNTYKMjU2IDUxMgo1MTIgODQ4Cjg0OCAxMjgwCjEyODAgMTc5MgoxNzkyIDI1NjAKMjU2MCAzNDA4CjM0MDggNTEyMAo1MTIwIDcxNjgKNzE2OCA5MjE2CjkyMTYgMTIyODgKMTIyODggMTYzODQKMTYzODQgMjE1MDQKMjE1MDQgMjc2NDgKMjc2NDggMzQ4MTYKMzQ4MTYgNDQwMzIKNDQwMzIgNTUyOTYKNTUyOTYgNjk2MzIKNjk2MzIgODgwNjQKODgwNjQgMTEwNTkyCjExMDU5MiAxMzkyNjQKMTM5MjY0IDE3NTEwNAoxNzUxMDQgMjE5MTM2CjIxOTEzNiAyNzQ0MzIKMjc0NDMyIDM0NDA2NAozNDQwNjQgNDMxMTA0CjQzMTEwNCA1Mzk2NDgKNTM5NjQ4IDY3NDgxNgo2NzQ4MTYgODQzNzc2Cjg0Mzc3NiAxMDU1NzQ0CjEwNTU3NDQgMTMxOTkzNgoxMzE5OTM2IDE2NTA2ODgKMTY1MDY4OCAyMDY0Mzg0CjIwNjQzODQgMjU4MTUwNAoyNTgxNTA0IDMyMjc2NDgKMzIyNzY0OCA0MDM1NTg0CjQwMzU1ODQgNTA0NTI0OAo1MDQ1MjQ4IDYzMDY4MTYKNjMwNjgxNiA3ODgzNzc2Cjc4ODM3NzYgOTg1NDk3Ngo5ODU0OTc2IDEyMzE5NzQ0CjEyMzE5NzQ0IDE1Mzk5OTM2CjE1Mzk5OTM2IDE5MjUwMTc2CjE5MjUwMTc2IDI0MDYyOTc2CjI0MDYyOTc2IDMwMDc4OTc2CjMwMDc4OTc2IDM3NTk5MjMyCjM3NTk5MjMyIDQ2OTk5NTUyCjQ2OTk5NTUyIDU4NzQ5OTUyCjU4NzQ5OTUyIDczNDM4MjA4CjczNDM4MjA4IDkxNzk4NTI4CjkxNzk4NTI4IDExNDc0ODQxNg==", - "duration": 3246509833, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\n0 1\n1 2\n2 4\n4 8\n8 16\n16 32\n32 64\n64 128\n128 256\n256 512\n512 848\n848 1280\n1280 1792\n1792 2560\n2560 3408\n3408 5120\n5120 7168\n7168 9216\n9216 12288\n12288 16384\n16384 21504\n21504 27648\n27648 34816\n34816 44032\n44032 55296\n55296 69632\n69632 88064\n88064 110592\n110592 139264\n139264 175104\n175104 219136\n219136 274432\n274432 344064\n344064 431104\n431104 539648\n539648 674816\n674816 843776\n843776 1055744\n1055744 1319936\n1319936 1650688\n1650688 2064384\n2064384 2581504\n2581504 3227648\n3227648 4035584\n4035584 5045248\n5045248 6306816\n6306816 7883776\n7883776 9854976\n9854976 12319744\n12319744 15399936\n15399936 19250176\n19250176 24062976\n24062976 30078976\n30078976 37599232\n37599232 46999552\n46999552 58749952\n58749952 73438208\n73438208 91798528\n91798528 114748416", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/03-collections/internals/src/cap-printer", - "stdout": "MCAxCjEgMgoyIDQKNCA4CjggMTYKMTYgMzIKMzIgNjQKNjQgMTI4CjEyOCAyNTYKMjU2IDUxMgo1MTIgODQ4Cjg0OCAxMjgwCjEyODAgMTc5MgoxNzkyIDI1NjAKMjU2MCAzNDA4CjM0MDggNTEyMAo1MTIwIDcxNjgKNzE2OCA5MjE2CjkyMTYgMTIyODgKMTIyODggMTYzODQKMTYzODQgMjE1MDQKMjE1MDQgMjc2NDgKMjc2NDggMzQ4MTYKMzQ4MTYgNDQwMzIKNDQwMzIgNTUyOTYKNTUyOTYgNjk2MzIKNjk2MzIgODgwNjQKODgwNjQgMTEwNTkyCjExMDU5MiAxMzkyNjQKMTM5MjY0IDE3NTEwNAoxNzUxMDQgMjE5MTM2CjIxOTEzNiAyNzQ0MzIKMjc0NDMyIDM0NDA2NAozNDQwNjQgNDMxMTA0CjQzMTEwNCA1Mzk2NDgKNTM5NjQ4IDY3NDgxNgo2NzQ4MTYgODQzNzc2Cjg0Mzc3NiAxMDU1NzQ0CjEwNTU3NDQgMTMxOTkzNgoxMzE5OTM2IDE2NTA2ODgKMTY1MDY4OCAyMDY0Mzg0CjIwNjQzODQgMjU4MTUwNAoyNTgxNTA0IDMyMjc2NDgKMzIyNzY0OCA0MDM1NTg0CjQwMzU1ODQgNTA0NTI0OAo1MDQ1MjQ4IDYzMDY4MTYKNjMwNjgxNiA3ODgzNzc2Cjc4ODM3NzYgOTg1NDk3Ngo5ODU0OTc2IDEyMzE5NzQ0CjEyMzE5NzQ0IDE1Mzk5OTM2CjE1Mzk5OTM2IDE5MjUwMTc2CjE5MjUwMTc2IDI0MDYyOTc2CjI0MDYyOTc2IDMwMDc4OTc2CjMwMDc4OTc2IDM3NTk5MjMyCjM3NTk5MjMyIDQ2OTk5NTUyCjQ2OTk5NTUyIDU4NzQ5OTUyCjU4NzQ5OTUyIDczNDM4MjA4CjczNDM4MjA4IDkxNzk4NTI4CjkxNzk4NTI4IDExNDc0ODQxNg==", - "duration": 3246509833, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "internals", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.23:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Printing slice capacity of one million iterations.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 23, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "internals.md", - "level": 2, - "nodes": [ - { - "text": "Making A Slice", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "internals.md", - "nodes": [ - { - "text": "Slices can be declared in several different ways, including using the built-in ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "builtin#make", - "href": "https://pkg.go.dev/builtin#make", - "target": "_blank" - }, - "file": "internals.md", - "nodes": [ - { - "atom": "code", - "file": "internals.md", - "nodes": [ - { - "text": "make", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/builtin#make" - } - ], - { - "text": " function.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-24", - "type": "listing" - }, - "file": "internals.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "doc", - "builtin.make" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "doc": "builtin.make", - "exec": "go doc builtin.make", - "src": "internals/src/make" - }, - "expected_exit": 0, - "file": "internals", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc builtin.make\n\npackage builtin // import \u0026#34;builtin\u0026#34;\n\nfunc make(t Type, size ...IntegerType) Type\n The make built-in function allocates and initializes an object of type\n slice, map, or chan (only). Like new, the first argument is a type,\n not a value. Unlike new, make\u0026#39;s return type is the same as the type of its\n argument, not a pointer to it. The specification of the result depends on\n the type:\n\n Slice: The size specifies the length. The capacity of the slice is\n equal to its length. A second integer argument may be provided to\n specify a different capacity; it must be no smaller than the\n length. For example, make([]int, 0, 10) allocates an underlying array\n of size 10 and returns a slice of length 0 and capacity 10 that is\n backed by this underlying array.\n Map: An empty map is allocated with enough space to hold the\n specified number of elements. The size may be omitted, in which case\n a small starting size is allocated.\n Channel: The channel\u0026#39;s buffer is initialized with the specified\n buffer capacity. If zero, or the size is omitted, the channel is\n unbuffered.", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "builtin.make" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/03-collections/internals/src/make", - "stdout": "cGFja2FnZSBidWlsdGluIC8vIGltcG9ydCAiYnVpbHRpbiIKCmZ1bmMgbWFrZSh0IFR5cGUsIHNpemUgLi4uSW50ZWdlclR5cGUpIFR5cGUKICAgIFRoZSBtYWtlIGJ1aWx0LWluIGZ1bmN0aW9uIGFsbG9jYXRlcyBhbmQgaW5pdGlhbGl6ZXMgYW4gb2JqZWN0IG9mIHR5cGUKICAgIHNsaWNlLCBtYXAsIG9yIGNoYW4gKG9ubHkpLiBMaWtlIG5ldywgdGhlIGZpcnN0IGFyZ3VtZW50IGlzIGEgdHlwZSwKICAgIG5vdCBhIHZhbHVlLiBVbmxpa2UgbmV3LCBtYWtlJ3MgcmV0dXJuIHR5cGUgaXMgdGhlIHNhbWUgYXMgdGhlIHR5cGUgb2YgaXRzCiAgICBhcmd1bWVudCwgbm90IGEgcG9pbnRlciB0byBpdC4gVGhlIHNwZWNpZmljYXRpb24gb2YgdGhlIHJlc3VsdCBkZXBlbmRzIG9uCiAgICB0aGUgdHlwZToKCiAgICAgICAgU2xpY2U6IFRoZSBzaXplIHNwZWNpZmllcyB0aGUgbGVuZ3RoLiBUaGUgY2FwYWNpdHkgb2YgdGhlIHNsaWNlIGlzCiAgICAgICAgZXF1YWwgdG8gaXRzIGxlbmd0aC4gQSBzZWNvbmQgaW50ZWdlciBhcmd1bWVudCBtYXkgYmUgcHJvdmlkZWQgdG8KICAgICAgICBzcGVjaWZ5IGEgZGlmZmVyZW50IGNhcGFjaXR5OyBpdCBtdXN0IGJlIG5vIHNtYWxsZXIgdGhhbiB0aGUKICAgICAgICBsZW5ndGguIEZvciBleGFtcGxlLCBtYWtlKFtdaW50LCAwLCAxMCkgYWxsb2NhdGVzIGFuIHVuZGVybHlpbmcgYXJyYXkKICAgICAgICBvZiBzaXplIDEwIGFuZCByZXR1cm5zIGEgc2xpY2Ugb2YgbGVuZ3RoIDAgYW5kIGNhcGFjaXR5IDEwIHRoYXQgaXMKICAgICAgICBiYWNrZWQgYnkgdGhpcyB1bmRlcmx5aW5nIGFycmF5LgogICAgICAgIE1hcDogQW4gZW1wdHkgbWFwIGlzIGFsbG9jYXRlZCB3aXRoIGVub3VnaCBzcGFjZSB0byBob2xkIHRoZQogICAgICAgIHNwZWNpZmllZCBudW1iZXIgb2YgZWxlbWVudHMuIFRoZSBzaXplIG1heSBiZSBvbWl0dGVkLCBpbiB3aGljaCBjYXNlCiAgICAgICAgYSBzbWFsbCBzdGFydGluZyBzaXplIGlzIGFsbG9jYXRlZC4KICAgICAgICBDaGFubmVsOiBUaGUgY2hhbm5lbCdzIGJ1ZmZlciBpcyBpbml0aWFsaXplZCB3aXRoIHRoZSBzcGVjaWZpZWQKICAgICAgICBidWZmZXIgY2FwYWNpdHkuIElmIHplcm8sIG9yIHRoZSBzaXplIGlzIG9taXR0ZWQsIHRoZSBjaGFubmVsIGlzCiAgICAgICAgdW5idWZmZXJlZC4=", - "duration": 2542208458, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc builtin.make\n\npackage builtin // import \u0026#34;builtin\u0026#34;\n\nfunc make(t Type, size ...IntegerType) Type\n The make built-in function allocates and initializes an object of type\n slice, map, or chan (only). Like new, the first argument is a type,\n not a value. Unlike new, make\u0026#39;s return type is the same as the type of its\n argument, not a pointer to it. The specification of the result depends on\n the type:\n\n Slice: The size specifies the length. The capacity of the slice is\n equal to its length. A second integer argument may be provided to\n specify a different capacity; it must be no smaller than the\n length. For example, make([]int, 0, 10) allocates an underlying array\n of size 10 and returns a slice of length 0 and capacity 10 that is\n backed by this underlying array.\n Map: An empty map is allocated with enough space to hold the\n specified number of elements. The size may be omitted, in which case\n a small starting size is allocated.\n Channel: The channel\u0026#39;s buffer is initialized with the specified\n buffer capacity. If zero, or the size is omitted, the channel is\n unbuffered.", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "builtin.make" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/03-collections/internals/src/make", - "stdout": "cGFja2FnZSBidWlsdGluIC8vIGltcG9ydCAiYnVpbHRpbiIKCmZ1bmMgbWFrZSh0IFR5cGUsIHNpemUgLi4uSW50ZWdlclR5cGUpIFR5cGUKICAgIFRoZSBtYWtlIGJ1aWx0LWluIGZ1bmN0aW9uIGFsbG9jYXRlcyBhbmQgaW5pdGlhbGl6ZXMgYW4gb2JqZWN0IG9mIHR5cGUKICAgIHNsaWNlLCBtYXAsIG9yIGNoYW4gKG9ubHkpLiBMaWtlIG5ldywgdGhlIGZpcnN0IGFyZ3VtZW50IGlzIGEgdHlwZSwKICAgIG5vdCBhIHZhbHVlLiBVbmxpa2UgbmV3LCBtYWtlJ3MgcmV0dXJuIHR5cGUgaXMgdGhlIHNhbWUgYXMgdGhlIHR5cGUgb2YgaXRzCiAgICBhcmd1bWVudCwgbm90IGEgcG9pbnRlciB0byBpdC4gVGhlIHNwZWNpZmljYXRpb24gb2YgdGhlIHJlc3VsdCBkZXBlbmRzIG9uCiAgICB0aGUgdHlwZToKCiAgICAgICAgU2xpY2U6IFRoZSBzaXplIHNwZWNpZmllcyB0aGUgbGVuZ3RoLiBUaGUgY2FwYWNpdHkgb2YgdGhlIHNsaWNlIGlzCiAgICAgICAgZXF1YWwgdG8gaXRzIGxlbmd0aC4gQSBzZWNvbmQgaW50ZWdlciBhcmd1bWVudCBtYXkgYmUgcHJvdmlkZWQgdG8KICAgICAgICBzcGVjaWZ5IGEgZGlmZmVyZW50IGNhcGFjaXR5OyBpdCBtdXN0IGJlIG5vIHNtYWxsZXIgdGhhbiB0aGUKICAgICAgICBsZW5ndGguIEZvciBleGFtcGxlLCBtYWtlKFtdaW50LCAwLCAxMCkgYWxsb2NhdGVzIGFuIHVuZGVybHlpbmcgYXJyYXkKICAgICAgICBvZiBzaXplIDEwIGFuZCByZXR1cm5zIGEgc2xpY2Ugb2YgbGVuZ3RoIDAgYW5kIGNhcGFjaXR5IDEwIHRoYXQgaXMKICAgICAgICBiYWNrZWQgYnkgdGhpcyB1bmRlcmx5aW5nIGFycmF5LgogICAgICAgIE1hcDogQW4gZW1wdHkgbWFwIGlzIGFsbG9jYXRlZCB3aXRoIGVub3VnaCBzcGFjZSB0byBob2xkIHRoZQogICAgICAgIHNwZWNpZmllZCBudW1iZXIgb2YgZWxlbWVudHMuIFRoZSBzaXplIG1heSBiZSBvbWl0dGVkLCBpbiB3aGljaCBjYXNlCiAgICAgICAgYSBzbWFsbCBzdGFydGluZyBzaXplIGlzIGFsbG9jYXRlZC4KICAgICAgICBDaGFubmVsOiBUaGUgY2hhbm5lbCdzIGJ1ZmZlciBpcyBpbml0aWFsaXplZCB3aXRoIHRoZSBzcGVjaWZpZWQKICAgICAgICBidWZmZXIgY2FwYWNpdHkuIElmIHplcm8sIG9yIHRoZSBzaXplIGlzIG9taXR0ZWQsIHRoZSBjaGFubmVsIGlzCiAgICAgICAgdW5idWZmZXJlZC4=", - "duration": 2542208458, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "internals", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.24:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "builtin#make", - "href": "https://pkg.go.dev/builtin#make", - "target": "_blank" - }, - "file": "internals", - "nodes": [ - [ - { - "atom": "code", - "file": "internals", - "nodes": [ - { - "text": "make", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/builtin#make" - } - ], - { - "text": " function.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 24, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "internals.md", - "nodes": [ - { - "text": "In ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-25" - }, - "file": "internals.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-25" - }, - "nodes": [ - { - "text": "Listing 1.25", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-25" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": " we are declaring new variables of type ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "internals.md", - "nodes": [ - { - "text": "[]string", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " in several different ways. Functionally, each of these is equivalent. Each of these different ways to declare a slice has different advantages and disadvantages, and it is not uncommon to see these varies declaration styles in code.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-25", - "type": "listing" - }, - "file": "internals.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "internals", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "snippet": "example", - "src": "internals/src/make/main.go" - }, - "lang": "go", - "nodes": [ - { - "content": "func main() {\n\t// declare and initialize a slice of strings\n\t// with a length of 0 and capacity of 0\n\ta := []string{}\n\n\t// declare a variable of type slice of strings\n\t// with a length of 0 and capacity of 0\n\tvar b []string\n\n\t// declare and initialize a slice of strings\n\t// with a length of 0 and capacity of 0\n\tc := make([]string, 0)\n\n\tfmt.Println(a)\n\tfmt.Println(b)\n\tfmt.Println(c)\n}", - "file": "internals/src/make/main.go", - "lang": "go", - "name": "example", - "start": 5, - "end": 24, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "run", - "." - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go run .", - "run": ".", - "src": "internals/src/make" - }, - "expected_exit": 0, - "file": "internals", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\n[]\n[]\n[]", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/03-collections/internals/src/make", - "stdout": "W10KW10KW10=", - "duration": 950951583, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\n[]\n[]\n[]", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/03-collections/internals/src/make", - "stdout": "W10KW10KW10=", - "duration": 950951583, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "internals", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.25:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Declaring slices in several different ways.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 25, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "internals.md", - "level": 2, - "nodes": [ - { - "text": "Make With Length And Capacity", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "internals.md", - "nodes": [ - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "builtin#make", - "href": "https://pkg.go.dev/builtin#make", - "target": "_blank" - }, - "file": "internals.md", - "nodes": [ - { - "atom": "code", - "file": "internals.md", - "nodes": [ - { - "text": "make", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/builtin#make" - } - ], - { - "text": " function allows us to define the starting \"length\" of the slice, and optionally, the starting \"capacity\" of the slice.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-26", - "type": "listing" - }, - "file": "internals.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "internals", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "snippet": "example", - "src": "internals/src/make-cap/main.go" - }, - "lang": "go", - "nodes": [ - { - "content": "func main() {\n\ta := make([]string, 1, 3)\n\n\tfmt.Println(a) // []\n\tfmt.Println(len(a)) // 1\n\tfmt.Println(cap(a)) // 3\n}", - "file": "internals/src/make-cap/main.go", - "lang": "go", - "name": "example", - "start": 5, - "end": 14, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "run", - "." - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go run .", - "run": ".", - "src": "internals/src/make-cap" - }, - "expected_exit": 0, - "file": "internals", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\n[]\n1\n3", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/03-collections/internals/src/make-cap", - "stdout": "W10KMQoz", - "duration": 2680555416, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\n[]\n1\n3", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/03-collections/internals/src/make-cap", - "stdout": "W10KMQoz", - "duration": 2680555416, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "internals", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.26:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Using ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "builtin#make", - "href": "https://pkg.go.dev/builtin#make", - "target": "_blank" - }, - "file": "internals", - "nodes": [ - [ - { - "atom": "code", - "file": "internals", - "nodes": [ - { - "text": "make", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/builtin#make" - } - ], - { - "text": " to define the starting length and capacity of a slice.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 26, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "internals.md", - "nodes": [ - { - "text": "It's important to remember that even though you \"allocated\" extra capacity, you can't access that capacity until you assign a value to it.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "internals.md", - "level": 2, - "nodes": [ - { - "text": "Make And Append", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "internals.md", - "nodes": [ - { - "text": "Be careful when using both ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "builtin#make", - "href": "https://pkg.go.dev/builtin#make", - "target": "_blank" - }, - "file": "internals.md", - "nodes": [ - { - "atom": "code", - "file": "internals.md", - "nodes": [ - { - "text": "make", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/builtin#make" - } - ], - { - "text": " and ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "builtin#append", - "href": "https://pkg.go.dev/builtin#append", - "target": "_blank" - }, - "file": "internals.md", - "nodes": [ - { - "atom": "code", - "file": "internals.md", - "nodes": [ - { - "text": "append", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/builtin#append" - } - ], - { - "text": ", as you may inadvertently create ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "internals.md", - "nodes": [ - { - "text": "zero", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " values in your slice.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-27", - "type": "listing" - }, - "file": "internals.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "internals", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "snippet": "example", - "src": "internals/src/make-append/main.go" - }, - "lang": "go", - "nodes": [ - { - "content": "func main() {\n\ta := make([]string, 2)\n\ta = append(a, \"foo\", \"bar\")\n\n\tfmt.Printf(\"%q\", a)\n}", - "file": "internals/src/make-append/main.go", - "lang": "go", - "name": "example", - "start": 5, - "end": 13, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "run", - "." - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go run .", - "run": ".", - "src": "internals/src/make-append" - }, - "expected_exit": 0, - "file": "internals", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\n[\u0026#34;\u0026#34; \u0026#34;\u0026#34; \u0026#34;foo\u0026#34; \u0026#34;bar\u0026#34;]", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/03-collections/internals/src/make-append", - "stdout": "WyIiICIiICJmb28iICJiYXIiXQ==", - "duration": 2732979500, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\n[\u0026#34;\u0026#34; \u0026#34;\u0026#34; \u0026#34;foo\u0026#34; \u0026#34;bar\u0026#34;]", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/03-collections/internals/src/make-append", - "stdout": "WyIiICIiICJmb28iICJiYXIiXQ==", - "duration": 2732979500, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "internals", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.27:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Using ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "builtin#make", - "href": "https://pkg.go.dev/builtin#make", - "target": "_blank" - }, - "file": "internals", - "nodes": [ - [ - { - "atom": "code", - "file": "internals", - "nodes": [ - { - "text": "make", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/builtin#make" - } - ], - { - "text": " and ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "builtin#append", - "href": "https://pkg.go.dev/builtin#append", - "target": "_blank" - }, - "file": "internals", - "nodes": [ - [ - { - "atom": "code", - "file": "internals", - "nodes": [ - { - "text": "append", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/builtin#append" - } - ], - { - "text": " can be problematic.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 27, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "internals.md", - "level": 2, - "nodes": [ - { - "text": "What Happens When A Slice Grows", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "internals.md", - "nodes": [ - { - "text": "Slices, as we have seen, are comprised of three parts, length, capacity, and pointer to an underlying array. In ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-28" - }, - "file": "internals.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-28" - }, - "nodes": [ - { - "text": "Listing 1.28", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-28" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": " we see a theoretical representation of the internals of the slice, ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "internals.md", - "nodes": [ - { - "text": "[]string{\"A\", \"B\", \"C\", \"D\"}", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-28", - "type": "listing" - }, - "file": "internals.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "internals", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-text", - "language": "text" - }, - "file": "internals", - "lang": "text", - "nodes": [ - { - "text": "┌────────────────────────────────────────────────┐\n│ Slice │\n├────────────────────────────────────────────────┤\n│ Len -\u003e 4 │\n│ │\n│ Cap -\u003e 4 │\n│ ┌─────────────────┐ │\n│ Arr -\u003e Array Pointer -\u003e │Underlying Array │ │\n│ │ │ │\n│ │┌─┬─┬─┬─┐ │ │\n│ ││A│B│C│D│ │ │\n│ │└─┴─┴─┴─┘ │ │\n│ └─────────────────┘ │\n└────────────────────────────────────────────────┘\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "internals", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.28:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Theoretical representation of a slice.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 28, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "internals.md", - "nodes": [ - { - "text": "If we append the values ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "internals.md", - "nodes": [ - { - "text": "E", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ", ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "internals.md", - "nodes": [ - { - "text": "F", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ", and ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "internals.md", - "nodes": [ - { - "text": "G", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ", it will force the slice to expand, as it currently has no capacity for the new values. Go will create a new underlying array, copy the original values into the new one, and add the new values as seen in ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-29" - }, - "file": "internals.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-29" - }, - "nodes": [ - { - "text": "Listing 1.29", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-29" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-29", - "type": "listing" - }, - "file": "internals.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "internals", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-text", - "language": "text" - }, - "file": "internals", - "lang": "text", - "nodes": [ - { - "text": "┌────────────────────────────────────────────────┐\n│ append(slice, \"E\", \"F\", \"G\") │\n├────────────────────────────────────────────────┤\n│ │\n│ ┌─────────────────┐ ┌─────────────────┐ │\n│ │Original Array │ │New Array │ │\n│ │ │ │ │ │\n│ │┌─┬─┬─┬─┐ │───────\u003e│┌─┬─┬─┬─┬─┬─┬─┬─┐│ │\n│ ││A│B│C│D│ │ ││A│B│C│D│E│F│G│ ││ │\n│ │└─┴─┴─┴─┘ │ │└─┴─┴─┴─┴─┴─┴─┴─┘│ │\n│ └─────────────────┘ └─────────────────┘ │\n│ │\n└────────────────────────────────────────────────┘\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "internals", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.29:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "When full a new array is created and values are copied over.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 29, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "internals.md", - "nodes": [ - { - "text": "In ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-30" - }, - "file": "internals.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-30" - }, - "nodes": [ - { - "text": "Listing 1.30", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-30" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", we see the final representation of the slice after the new values have been appended.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-30", - "type": "listing" - }, - "file": "internals.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "internals", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-text", - "language": "text" - }, - "file": "internals", - "lang": "text", - "nodes": [ - { - "text": "┌────────────────────────────────────────────────┐\n│ Slice │\n├────────────────────────────────────────────────┤\n│ Len -\u003e 7 │\n│ │\n│ Cap -\u003e 8 │\n│ ┌─────────────────┐ │\n│ Arr -\u003e Array Pointer -\u003e │Underlying Array │ │\n│ │ │ │\n│ │┌─┬─┬─┬─┬─┬─┬─┬─┐│ │\n│ ││A│B│C│D│E│F│G│ ││ │\n│ │└─┴─┴─┴─┴─┴─┴─┴─┘│ │\n│ └─────────────────┘ │\n└────────────────────────────────────────────────┘\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "internals", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.30:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The final slice representation after appending.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 30, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "internals.md", - "nodes": [ - { - "text": "If the original underlying array is not reference by any other part of the program, it will be marked for garbage collection.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "internals.md", - "level": 2, - "nodes": [ - { - "text": "Slice Subsets", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "internals.md", - "nodes": [ - { - "text": "Subsets of a slice (or a slice of a slice) allow us to work with just section of a slice. To obtain a subset of a slice, we need to specify the starting index and ending index of the subset. In ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-31" - }, - "file": "internals.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-31" - }, - "nodes": [ - { - "text": "Listing 1.31", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-31" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": " when we ask for ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "internals.md", - "nodes": [ - { - "text": "letters[2:5]", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ", we get a slice of the original slice, ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "internals.md", - "nodes": [ - { - "text": "letters", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ", containing elements from index ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "internals.md", - "nodes": [ - { - "text": "2", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " up to, but not including, index ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "internals.md", - "nodes": [ - { - "text": "5", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ". In this case, the slice returned is ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "internals.md", - "nodes": [ - { - "text": "{\"c\", \"d\", \"e\"}", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-31", - "type": "listing" - }, - "file": "internals.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "internals", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "snippet": "example", - "src": "internals/src/subset/main.go" - }, - "lang": "go", - "nodes": [ - { - "content": "func main() {\n\tletters := []string{\"a\", \"b\", \"c\", \"d\", \"e\", \"f\", \"g\"}\n\n\tfmt.Println(letters) // [a b c d e f g]\n\n\t// Get 3 elements starting with the third element\n\tfmt.Println(letters[2:5]) // [c d e]\n\n\t// functionally equivalent\n\tfmt.Println(letters[4:len(letters)]) // [e f g]\n\tfmt.Println(letters[4:]) // [e f g]\n\n\t// functionally equivalent\n\tfmt.Println(letters[0:4]) // [a b c d]\n\tfmt.Println(letters[:4]) // [a b c d]\n}", - "file": "internals/src/subset/main.go", - "lang": "go", - "name": "example", - "start": 7, - "end": 25, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "run", - "." - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go run .", - "run": ".", - "src": "internals/src/subset" - }, - "expected_exit": 0, - "file": "internals", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\n[a b c d e f g]\n[c d e]\n[e f g]\n[e f g]\n[a b c d]\n[a b c d]", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/03-collections/internals/src/subset", - "stdout": "W2EgYiBjIGQgZSBmIGddCltjIGQgZV0KW2UgZiBnXQpbZSBmIGddClthIGIgYyBkXQpbYSBiIGMgZF0=", - "duration": 3269876791, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\n[a b c d e f g]\n[c d e]\n[e f g]\n[e f g]\n[a b c d]\n[a b c d]", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/03-collections/internals/src/subset", - "stdout": "W2EgYiBjIGQgZSBmIGddCltjIGQgZV0KW2UgZiBnXQpbZSBmIGddClthIGIgYyBkXQpbYSBiIGMgZF0=", - "duration": 3269876791, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "internals", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.31:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Obtaining subsets of a slice.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 31, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "internals.md", - "nodes": [ - { - "text": "When asking for a subset of a slice that starts at index ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "internals.md", - "nodes": [ - { - "text": "0", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ", or that ends at the last index, we can omit the starting or ending index. In ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-31" - }, - "file": "internals.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-31" - }, - "nodes": [ - { - "text": "Listing 1.31", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-31" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", we ask for ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "internals.md", - "nodes": [ - { - "text": "letters[:4]", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ", which returns a slice of the original slice, ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "internals.md", - "nodes": [ - { - "text": "letters", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ", containing elements from index ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "internals.md", - "nodes": [ - { - "text": "0", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " up to, but not including, index ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "internals.md", - "nodes": [ - { - "text": "4", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ". In this case, the slice returned is ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "internals.md", - "nodes": [ - { - "text": "{\"a\", \"b\", \"c\", \"d\"}", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "internals.md", - "level": 2, - "nodes": [ - { - "text": "Mutating Slice Subsets", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "internals.md", - "nodes": [ - { - "text": "It is important to remember that when using a subset of a slice, you are just working with a reference to the original slice. Modifications to the subset will affect the original slice.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-32", - "type": "listing" - }, - "file": "internals.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "internals", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "snippet": "example", - "src": "internals/src/subset-mutation/main.go" - }, - "lang": "go", - "nodes": [ - { - "content": "func main() {\n\tnames := []string{\"Kurt\", \"Janis\", \"Jimi\", \"Amy\"}\n\n\t// print the names slice\n\tfmt.Println(names)\n\n\t// get the first three elements of the `names` slice\n\tsubset := names[:3]\n\n\t// print out the subset slice\n\tfmt.Println(subset)\n\n\t// loop over the subset slice\n\tfor i, g := range subset {\n\t\t// uppercase each string\n\t\t// and replace the value in\n\t\t// the subset slice\n\t\tsubset[i] = strings.ToUpper(g)\n\t}\n\n\t// print out the subset slice, again\n\tfmt.Println(subset)\n\n\t// print out the original names slice\n\tfmt.Println(names)\n}", - "file": "internals/src/subset-mutation/main.go", - "lang": "go", - "name": "example", - "start": 8, - "end": 36, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "run", - "." - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go run .", - "run": ".", - "src": "internals/src/subset-mutation" - }, - "expected_exit": 0, - "file": "internals", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\n[Kurt Janis Jimi Amy]\n[Kurt Janis Jimi]\n[KURT JANIS JIMI]\n[KURT JANIS JIMI Amy]", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/03-collections/internals/src/subset-mutation", - "stdout": "W0t1cnQgSmFuaXMgSmltaSBBbXldCltLdXJ0IEphbmlzIEppbWldCltLVVJUIEpBTklTIEpJTUldCltLVVJUIEpBTklTIEpJTUkgQW15XQ==", - "duration": 2405555792, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\n[Kurt Janis Jimi Amy]\n[Kurt Janis Jimi]\n[KURT JANIS JIMI]\n[KURT JANIS JIMI Amy]", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/03-collections/internals/src/subset-mutation", - "stdout": "W0t1cnQgSmFuaXMgSmltaSBBbXldCltLdXJ0IEphbmlzIEppbWldCltLVVJUIEpBTklTIEpJTUldCltLVVJUIEpBTklTIEpJTUkgQW15XQ==", - "duration": 2405555792, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - null, - [ - { - "atom": "figcaption", - "file": "internals", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.32:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Mutating subsets of a slice affects the original.", - "type": "hype.Text" - }, - null, - { - "text": "\n\n", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 32, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "internals.md", - "nodes": [ - { - "text": "In ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-32" - }, - "file": "internals.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-32" - }, - "nodes": [ - { - "text": "Listing 1.32", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-32" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": " we see that if we modify the subset, but upper-casing its values, the original slice will also contain uppercase values.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "internals.md", - "level": 2, - "nodes": [ - { - "text": "Copying Slices", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "internals.md", - "nodes": [ - { - "text": "When a separate, independent copy of a slice is needed, the built-in ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "builtin#copy", - "href": "https://pkg.go.dev/builtin#copy", - "target": "_blank" - }, - "file": "internals.md", - "nodes": [ - { - "atom": "code", - "file": "internals.md", - "nodes": [ - { - "text": "copy", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/builtin#copy" - } - ], - { - "text": " function can be used.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-33", - "type": "listing" - }, - "file": "internals.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "doc", - "builtin.copy" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "doc": "builtin.copy", - "exec": "go doc builtin.copy" - }, - "expected_exit": 0, - "file": "internals", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc builtin.copy\n\npackage builtin // import \u0026#34;builtin\u0026#34;\n\nfunc copy(dst, src []Type) int\n The copy built-in function copies elements from a source slice into a\n destination slice. (As a special case, it also will copy bytes from a string\n to a slice of bytes.) The source and destination may overlap. Copy returns\n the number of elements copied, which will be the minimum of len(src) and\n len(dst).", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "builtin.copy" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBidWlsdGluIC8vIGltcG9ydCAiYnVpbHRpbiIKCmZ1bmMgY29weShkc3QsIHNyYyBbXVR5cGUpIGludAogICAgVGhlIGNvcHkgYnVpbHQtaW4gZnVuY3Rpb24gY29waWVzIGVsZW1lbnRzIGZyb20gYSBzb3VyY2Ugc2xpY2UgaW50byBhCiAgICBkZXN0aW5hdGlvbiBzbGljZS4gKEFzIGEgc3BlY2lhbCBjYXNlLCBpdCBhbHNvIHdpbGwgY29weSBieXRlcyBmcm9tIGEgc3RyaW5nCiAgICB0byBhIHNsaWNlIG9mIGJ5dGVzLikgVGhlIHNvdXJjZSBhbmQgZGVzdGluYXRpb24gbWF5IG92ZXJsYXAuIENvcHkgcmV0dXJucwogICAgdGhlIG51bWJlciBvZiBlbGVtZW50cyBjb3BpZWQsIHdoaWNoIHdpbGwgYmUgdGhlIG1pbmltdW0gb2YgbGVuKHNyYykgYW5kCiAgICBsZW4oZHN0KS4=", - "duration": 2080774375, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc builtin.copy\n\npackage builtin // import \u0026#34;builtin\u0026#34;\n\nfunc copy(dst, src []Type) int\n The copy built-in function copies elements from a source slice into a\n destination slice. (As a special case, it also will copy bytes from a string\n to a slice of bytes.) The source and destination may overlap. Copy returns\n the number of elements copied, which will be the minimum of len(src) and\n len(dst).", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "builtin.copy" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBidWlsdGluIC8vIGltcG9ydCAiYnVpbHRpbiIKCmZ1bmMgY29weShkc3QsIHNyYyBbXVR5cGUpIGludAogICAgVGhlIGNvcHkgYnVpbHQtaW4gZnVuY3Rpb24gY29waWVzIGVsZW1lbnRzIGZyb20gYSBzb3VyY2Ugc2xpY2UgaW50byBhCiAgICBkZXN0aW5hdGlvbiBzbGljZS4gKEFzIGEgc3BlY2lhbCBjYXNlLCBpdCBhbHNvIHdpbGwgY29weSBieXRlcyBmcm9tIGEgc3RyaW5nCiAgICB0byBhIHNsaWNlIG9mIGJ5dGVzLikgVGhlIHNvdXJjZSBhbmQgZGVzdGluYXRpb24gbWF5IG92ZXJsYXAuIENvcHkgcmV0dXJucwogICAgdGhlIG51bWJlciBvZiBlbGVtZW50cyBjb3BpZWQsIHdoaWNoIHdpbGwgYmUgdGhlIG1pbmltdW0gb2YgbGVuKHNyYykgYW5kCiAgICBsZW4oZHN0KS4=", - "duration": 2080774375, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "internals", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.33:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The built-in ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "builtin#copy", - "href": "https://pkg.go.dev/builtin#copy", - "target": "_blank" - }, - "file": "internals", - "nodes": [ - [ - { - "atom": "code", - "file": "internals", - "nodes": [ - { - "text": "copy", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/builtin#copy" - } - ], - { - "text": " function.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 33, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "internals.md", - "nodes": [ - { - "text": "In ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-34" - }, - "file": "internals.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-34" - }, - "nodes": [ - { - "text": "Listing 1.34", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-34" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": " we are using the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "builtin#copy", - "href": "https://pkg.go.dev/builtin#copy", - "target": "_blank" - }, - "file": "internals.md", - "nodes": [ - { - "atom": "code", - "file": "internals.md", - "nodes": [ - { - "text": "copy", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/builtin#copy" - } - ], - { - "text": " function instead of getting a subset of a slice. We are able to create a new slice that is independent of the original. The new slice can now be modified independently of the original.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-34", - "type": "listing" - }, - "file": "internals.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "internals", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "snippet": "example", - "src": "internals/src/copy/main.go" - }, - "lang": "go", - "nodes": [ - { - "content": "func main() {\n\tnames := []string{\"Kurt\", \"Janis\", \"Jimi\", \"Amy\"}\n\n\t// print the names slice\n\tfmt.Println(names)\n\n\t// make a new slice with\n\t// the correct length and\n\t// capacity to hold the subset\n\tsubset := make([]string, 3)\n\n\t// copy the first three elements\n\t// of the names slice into the\n\t// subset slice\n\tcopy(subset, names[:3])\n\n\t// print out the subset slice\n\tfmt.Println(subset)\n\n\t// loop over the subset slice\n\tfor i, g := range subset {\n\t\t// uppercase each string\n\t\t// and replace the value in\n\t\t// the subset slice\n\t\tsubset[i] = strings.ToUpper(g)\n\t}\n\n\t// print out the subset slice, again\n\tfmt.Println(subset)\n\n\t// print out the original names slice\n\tfmt.Println(names)\n}", - "file": "internals/src/copy/main.go", - "lang": "go", - "name": "example", - "start": 8, - "end": 43, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "run", - "." - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go run .", - "run": ".", - "src": "internals/src/copy" - }, - "expected_exit": 0, - "file": "internals", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\n[Kurt Janis Jimi Amy]\n[Kurt Janis Jimi]\n[KURT JANIS JIMI]\n[Kurt Janis Jimi Amy]", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/03-collections/internals/src/copy", - "stdout": "W0t1cnQgSmFuaXMgSmltaSBBbXldCltLdXJ0IEphbmlzIEppbWldCltLVVJUIEpBTklTIEpJTUldCltLdXJ0IEphbmlzIEppbWkgQW15XQ==", - "duration": 2346031542, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\n[Kurt Janis Jimi Amy]\n[Kurt Janis Jimi]\n[KURT JANIS JIMI]\n[Kurt Janis Jimi Amy]", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/03-collections/internals/src/copy", - "stdout": "W0t1cnQgSmFuaXMgSmltaSBBbXldCltLdXJ0IEphbmlzIEppbWldCltLVVJUIEpBTklTIEpJTUldCltLdXJ0IEphbmlzIEppbWkgQW15XQ==", - "duration": 2346031542, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "internals", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.34:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Copying a slice.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 34, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "internals.md", - "level": 2, - "nodes": [ - { - "text": "Converting an Array to a Slice", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "internals.md", - "nodes": [ - { - "text": "When writing functions, or using most Go libraries, you will usually be working with slices. Because slices are more flexible than arrays, it is often easier to work with slices.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "internals.md", - "nodes": [ - { - "text": "Consider the function defined in ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-35" - }, - "file": "internals.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-35" - }, - "nodes": [ - { - "text": "Listing 1.35", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-35" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ". This function takes a slice of strings and prints out the values in the slice.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-35", - "type": "listing" - }, - "file": "internals.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "internals", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "snippet": "func", - "src": "internals/src/convert/bad/main.go" - }, - "lang": "go", - "nodes": [ - { - "content": "func slicesOnly(names []string) {\n\tfor _, name := range names {\n\t\tfmt.Println(name)\n\t}\n}", - "file": "internals/src/convert/bad/main.go", - "lang": "go", - "name": "func", - "start": 16, - "end": 23, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "internals", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.35:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "A function that accepts a slice.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 35, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "internals.md", - "nodes": [ - { - "text": "If we were to try and call the function with an array, we would get a compilation error as seen in ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-36" - }, - "file": "internals.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-36" - }, - "nodes": [ - { - "text": "Listing 1.36", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-36" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-36", - "type": "listing" - }, - "file": "internals.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "internals", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "snippet": "example", - "src": "internals/src/convert/bad/main.go" - }, - "lang": "go", - "nodes": [ - { - "content": "func main() {\n\t// array of four strings\n\tnames := [4]string{\"Kurt\", \"Janis\", \"Jimi\", \"Amy\"}\n\n\t// arrays can not be type cast to slices\n\tslicesOnly(names)\n}", - "file": "internals/src/convert/bad/main.go", - "lang": "go", - "name": "example", - "start": 5, - "end": 14, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "run", - "." - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go run .", - "exit": "-1", - "run": ".", - "src": "internals/src/convert/bad" - }, - "expected_exit": -1, - "file": "internals", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\n# demo\n./main.go:11:13: cannot use names (variable of type [4]string) as []string value in argument to slicesOnly", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/03-collections/internals/src/convert/bad", - "err": { - "Stderr": null - }, - "exit": 1, - "stderr": "IyBkZW1vCi4vbWFpbi5nbzoxMToxMzogY2Fubm90IHVzZSBuYW1lcyAodmFyaWFibGUgb2YgdHlwZSBbNF1zdHJpbmcpIGFzIFtdc3RyaW5nIHZhbHVlIGluIGFyZ3VtZW50IHRvIHNsaWNlc09ubHk=", - "duration": 1884794041, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\n# demo\n./main.go:11:13: cannot use names (variable of type [4]string) as []string value in argument to slicesOnly", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/03-collections/internals/src/convert/bad", - "err": { - "Stderr": null - }, - "exit": 1, - "stderr": "IyBkZW1vCi4vbWFpbi5nbzoxMToxMzogY2Fubm90IHVzZSBuYW1lcyAodmFyaWFibGUgb2YgdHlwZSBbNF1zdHJpbmcpIGFzIFtdc3RyaW5nIHZhbHVlIGluIGFyZ3VtZW50IHRvIHNsaWNlc09ubHk=", - "duration": 1884794041, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "internals", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.36:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Compilation error using an array instead of a slice.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 36, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "internals.md", - "nodes": [ - { - "text": "We have seen that Go can cast types like ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "internals.md", - "nodes": [ - { - "text": "int64", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " to ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "internals.md", - "nodes": [ - { - "text": "int", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ", but it is not possible to cast an array to a slice. If we were to try and cast an array to a slice, we would get a compilation error.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-37", - "type": "listing" - }, - "file": "internals.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "internals", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "snippet": "example", - "src": "internals/src/convert/cast/main.go" - }, - "lang": "go", - "nodes": [ - { - "content": "func main() {\n\t// array of four strings\n\tnames := [4]string{\"Kurt\", \"Janis\", \"Jimi\", \"Amy\"}\n\n\t// try to cast array to slice\n\tslicesOnly([]string(names))\n}", - "file": "internals/src/convert/cast/main.go", - "lang": "go", - "name": "example", - "start": 5, - "end": 14, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "run", - "." - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go run .", - "exit": "-1", - "run": ".", - "src": "internals/src/convert/cast" - }, - "expected_exit": -1, - "file": "internals", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\n# demo\n./main.go:11:22: cannot convert names (variable of type [4]string) to type []string", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/03-collections/internals/src/convert/cast", - "err": { - "Stderr": null - }, - "exit": 1, - "stderr": "IyBkZW1vCi4vbWFpbi5nbzoxMToyMjogY2Fubm90IGNvbnZlcnQgbmFtZXMgKHZhcmlhYmxlIG9mIHR5cGUgWzRdc3RyaW5nKSB0byB0eXBlIFtdc3RyaW5n", - "duration": 2172791208, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\n# demo\n./main.go:11:22: cannot convert names (variable of type [4]string) to type []string", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/03-collections/internals/src/convert/cast", - "err": { - "Stderr": null - }, - "exit": 1, - "stderr": "IyBkZW1vCi4vbWFpbi5nbzoxMToyMjogY2Fubm90IGNvbnZlcnQgbmFtZXMgKHZhcmlhYmxlIG9mIHR5cGUgWzRdc3RyaW5nKSB0byB0eXBlIFtdc3RyaW5n", - "duration": 2172791208, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "internals", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.37:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "An array can not be cast to a slice.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 37, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "internals.md", - "nodes": [ - { - "text": "We can convert our array to a slice by asking for a subset of the array. Like slices, subsets of arrays can be created with the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "internals.md", - "nodes": [ - { - "text": "[low:high]", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " syntax. For example, ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "internals.md", - "nodes": [ - { - "text": "names[0:2]", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " would create a slice of the first two elements of the array.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "internals.md", - "nodes": [ - { - "text": "In ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-38" - }, - "file": "internals.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-38" - }, - "nodes": [ - { - "text": "Listing 1.38", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-38" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", we use the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "internals.md", - "nodes": [ - { - "text": "[:]", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " syntax. This will return a slice of the entire array. With this new slice, we can now properly call our function.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-38", - "type": "listing" - }, - "file": "internals.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "internals", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "snippet": "example", - "src": "internals/src/convert/fixed/main.go" - }, - "lang": "go", - "nodes": [ - { - "content": "func main() {\n\t// array of four strings\n\tnames := [4]string{\"Kurt\", \"Janis\", \"Jimi\", \"Amy\"}\n\n\t// convert to slice of strings\n\t// using the `array[:]` syntax\n\tslicesOnly(names[:])\n}", - "file": "internals/src/convert/fixed/main.go", - "lang": "go", - "name": "example", - "start": 5, - "end": 15, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "run", - "." - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go run .", - "run": ".", - "src": "internals/src/convert/fixed" - }, - "expected_exit": 0, - "file": "internals", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\nKurt\nJanis\nJimi\nAmy", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/03-collections/internals/src/convert/fixed", - "stdout": "S3VydApKYW5pcwpKaW1pCkFteQ==", - "duration": 2418446458, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\nKurt\nJanis\nJimi\nAmy", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/03-collections/internals/src/convert/fixed", - "stdout": "S3VydApKYW5pcwpKaW1pCkFteQ==", - "duration": 2418446458, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "internals", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.38:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Using a slice of the entire array.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 38, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "title": "How Slices Work", - "type": "*hype.Page" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "type": "*hype.Include" - } - ], - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "include", - "attributes": { - "src": "iteration/iteration.md" - }, - "dir": "iteration", - "file": "module.md", - "nodes": [ - [ - { - "atom": "page", - "file": "iteration.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "h1", - "file": "iteration.md", - "level": 1, - "nodes": [ - { - "text": "Iteration", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "iteration.md", - "level": 2, - "nodes": [ - { - "text": "The \"for\" Loop", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "iteration.md", - "nodes": [ - { - "text": "In Go there is only ", - "type": "hype.Text" - }, - { - "atom": "strong", - "file": "iteration.md", - "nodes": [ - { - "text": "one", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " looping construct; the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "iteration.md", - "nodes": [ - { - "text": "for", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " loop. The ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "iteration.md", - "nodes": [ - { - "text": "for", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " loop is very versatile and can be used to implement patterns such as: ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "iteration.md", - "nodes": [ - { - "text": "for", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ", ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "iteration.md", - "nodes": [ - { - "text": "while", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ", ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "iteration.md", - "nodes": [ - { - "text": "do while", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ", and ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "iteration.md", - "nodes": [ - { - "text": "do until", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-39", - "type": "listing" - }, - "file": "iteration.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "iteration", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go" - }, - "file": "iteration", - "lang": "go", - "nodes": [ - { - "text": "for i := 0; i \u0026lt; N; i++ {\n // do work until i equals N\n}\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "iteration", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.39:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "A ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "iteration", - "nodes": [ - { - "text": "for", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " loop in Go.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 39, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "iteration.md", - "level": 2, - "nodes": [ - { - "text": "Iterating Over Arrays and Slices", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "iteration.md", - "nodes": [ - { - "text": "Iterating over arrays, slices, and maps are done using the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "iteration.md", - "nodes": [ - { - "text": "for", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " loop. In ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-40" - }, - "file": "iteration.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-40" - }, - "nodes": [ - { - "text": "Listing 1.40", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-40" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": " the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "builtin#len", - "href": "https://pkg.go.dev/builtin#len", - "target": "_blank" - }, - "file": "iteration.md", - "nodes": [ - { - "atom": "code", - "file": "iteration.md", - "nodes": [ - { - "text": "len", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/builtin#len" - } - ], - { - "text": " function is used to return the length of the array, ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "iteration.md", - "nodes": [ - { - "text": "4", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ", so the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "iteration.md", - "nodes": [ - { - "text": "for", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " loop will stop when ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "iteration.md", - "nodes": [ - { - "text": "i", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " reaches ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "iteration.md", - "nodes": [ - { - "text": "4", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-40", - "type": "listing" - }, - "file": "iteration.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "iteration", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "iteration/src/array-iteration/main.go#example" - }, - "lang": "go", - "nodes": [ - { - "content": "func main() {\n\tnames := [4]string{\"Kurt\", \"Janis\", \"Jimi\", \"Amy\"}\n\n\t// iterate over the array using a for loop\n\tfor i := 0; i \u003c len(names); i++ {\n\t\tfmt.Println(names[i])\n\t}\n}", - "file": "iteration/src/array-iteration/main.go", - "lang": "go", - "name": "example", - "start": 5, - "end": 15, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "atom": "hr", - "file": "iteration", - "type": "*hype.Element" - }, - [ - { - "args": [ - "go", - "run", - "." - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go run .", - "run": ".", - "src": "iteration/src/array-iteration" - }, - "expected_exit": 0, - "file": "iteration", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\nKurt\nJanis\nJimi\nAmy", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/03-collections/iteration/src/array-iteration", - "stdout": "S3VydApKYW5pcwpKaW1pCkFteQ==", - "duration": 2382195625, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\nKurt\nJanis\nJimi\nAmy", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/03-collections/iteration/src/array-iteration", - "stdout": "S3VydApKYW5pcwpKaW1pCkFteQ==", - "duration": 2382195625, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "iteration", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.40:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Iterating over an array.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 40, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "iteration.md", - "level": 2, - "nodes": [ - { - "text": "The \"range\" Keyword", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "iteration.md", - "nodes": [ - { - "text": "Previously we used a \"classic\" ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "iteration.md", - "nodes": [ - { - "text": "for", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " loop for iteration. Looping over collection types is common in Go that the language offers the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "iteration.md", - "nodes": [ - { - "text": "range", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " keyword to simplify this code.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-41", - "type": "listing" - }, - "file": "iteration.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "iteration", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "iteration/src/array-range/main.go#example" - }, - "lang": "go", - "nodes": [ - { - "content": "names := [4]string{\"Kurt\", \"Janis\", \"Jimi\", \"Amy\"}\n\nfor i, n := range names {\n\tfmt.Printf(\"%d %s\\n\", i, n)\n}", - "file": "iteration/src/array-range/main.go", - "lang": "go", - "name": "example", - "start": 6, - "end": 12, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "atom": "hr", - "file": "iteration", - "type": "*hype.Element" - }, - [ - { - "args": [ - "go", - "run", - "." - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go run .", - "run": ".", - "src": "iteration/src/array-range" - }, - "expected_exit": 0, - "file": "iteration", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\n0 Kurt\n1 Janis\n2 Jimi\n3 Amy", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/03-collections/iteration/src/array-range", - "stdout": "MCBLdXJ0CjEgSmFuaXMKMiBKaW1pCjMgQW15", - "duration": 4317042417, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\n0 Kurt\n1 Janis\n2 Jimi\n3 Amy", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/03-collections/iteration/src/array-range", - "stdout": "MCBLdXJ0CjEgSmFuaXMKMiBKaW1pCjMgQW15", - "duration": 4317042417, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "iteration", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.41:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Using the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "iteration", - "nodes": [ - { - "text": "range", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " keyword to iterate over an array.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 41, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "iteration.md", - "nodes": [ - { - "text": "Range returns the index and the value of each item in the array or slice. If only the index of the loop is needed, and not the value, using only a single variable in the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "iteration.md", - "nodes": [ - { - "text": "for", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " loop with ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "iteration.md", - "nodes": [ - { - "text": "range", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " will return the index of each loop.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-42", - "type": "listing" - }, - "file": "iteration.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "iteration", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "iteration/src/array-range-index/main.go#example" - }, - "lang": "go", - "nodes": [ - { - "content": "func main() {\n\tnames := [4]string{\"Kurt\", \"Janis\", \"Jimi\", \"Amy\"}\n\n\tfor i := range names {\n\t\tfmt.Printf(\"%d %s\\n\", i, names[i])\n\t}\n}", - "file": "iteration/src/array-range-index/main.go", - "lang": "go", - "name": "example", - "start": 5, - "end": 14, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "atom": "hr", - "file": "iteration", - "type": "*hype.Element" - }, - [ - { - "args": [ - "go", - "run", - "." - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go run .", - "run": ".", - "src": "iteration/src/array-range-index" - }, - "expected_exit": 0, - "file": "iteration", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\n0 Kurt\n1 Janis\n2 Jimi\n3 Amy", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/03-collections/iteration/src/array-range-index", - "stdout": "MCBLdXJ0CjEgSmFuaXMKMiBKaW1pCjMgQW15", - "duration": 676792334, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\n0 Kurt\n1 Janis\n2 Jimi\n3 Amy", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/03-collections/iteration/src/array-range-index", - "stdout": "MCBLdXJ0CjEgSmFuaXMKMiBKaW1pCjMgQW15", - "duration": 676792334, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "iteration", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.42:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Using the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "iteration", - "nodes": [ - { - "text": "range", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " keyword to iterate over an array, only returning the index.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 42, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "iteration.md", - "nodes": [ - { - "text": "A lot of languages expose an interface, or similar mechanism, that can be implemented to allow for custom iterable types. Go does not provide any such interface. Only the built-in collection types, and a few other built-in types to be discussed later, are supported with the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "iteration.md", - "nodes": [ - { - "text": "range", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " keyword.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "iteration.md", - "level": 2, - "nodes": [ - { - "text": "Controlling Loops", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "iteration.md", - "nodes": [ - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "iteration.md", - "nodes": [ - { - "text": "continue", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " keyword allows us to go back to the start of the loop and stop executing the rest of the code in the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "iteration.md", - "nodes": [ - { - "text": "for", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " block.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-43", - "type": "listing" - }, - "file": "iteration.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "iteration", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "snippet": "continue", - "src": "iteration/src/control/main.go" - }, - "lang": "go", - "nodes": [ - { - "content": "if i == 3 {\n\t// go to the start of the loop\n\tcontinue\n}", - "file": "iteration/src/control/main.go", - "lang": "go", - "name": "continue", - "start": 16, - "end": 21, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "iteration", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.43:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Using the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "iteration", - "nodes": [ - { - "text": "continue", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " keyword.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 43, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "iteration.md", - "nodes": [ - { - "text": "This does not stop the loop from executing, but rather ends that particular run of the loop.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "iteration.md", - "nodes": [ - { - "text": "To stop execution of a loop we can use the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "iteration.md", - "nodes": [ - { - "text": "break", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " keyword.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-44", - "type": "listing" - }, - "file": "iteration.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "iteration", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "snippet": "break", - "src": "iteration/src/control/main.go" - }, - "lang": "go", - "nodes": [ - { - "content": "if i == 10 {\n\t// stops the loop\n\tbreak\n}", - "file": "iteration/src/control/main.go", - "lang": "go", - "name": "break", - "start": 23, - "end": 28, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "iteration", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.44:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Using the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "iteration", - "nodes": [ - { - "text": "break", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " keyword.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 44, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "iteration.md", - "nodes": [ - { - "text": "Using the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "iteration.md", - "nodes": [ - { - "text": "continue", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " and ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "iteration.md", - "nodes": [ - { - "text": "break", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " keywords we can control a ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "iteration.md", - "nodes": [ - { - "text": "for", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " loops execution to deliver the results we want.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-45", - "type": "listing" - }, - "file": "iteration.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "iteration", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "iteration/src/control/main.go#example" - }, - "lang": "go", - "nodes": [ - { - "content": "func main() {\n\n\t// create a variable to act as an index\n\tvar i int\n\n\t// create an infinite loop\n\tfor {\n\t\t// increment the index\n\t\ti++\n\n\t\tif i == 3 {\n\t\t\t// go to the start of the loop\n\t\t\tcontinue\n\t\t}\n\n\t\tif i == 10 {\n\t\t\t// stops the loop\n\t\t\tbreak\n\t\t}\n\n\t\tfmt.Println(i)\n\n\t}\n\n\tfmt.Println(\"finished\")\n}", - "file": "iteration/src/control/main.go", - "lang": "go", - "name": "example", - "start": 5, - "end": 37, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "atom": "hr", - "file": "iteration", - "type": "*hype.Element" - }, - [ - { - "args": [ - "go", - "run", - "." - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go run .", - "run": ".", - "src": "iteration/src/control" - }, - "expected_exit": 0, - "file": "iteration", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\n1\n2\n4\n5\n6\n7\n8\n9\nfinished", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/03-collections/iteration/src/control", - "stdout": "MQoyCjQKNQo2CjcKOAo5CmZpbmlzaGVk", - "duration": 2378566750, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\n1\n2\n4\n5\n6\n7\n8\n9\nfinished", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/03-collections/iteration/src/control", - "stdout": "MQoyCjQKNQo2CjcKOAo5CmZpbmlzaGVk", - "duration": 2378566750, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "iteration", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.45:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Using the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "iteration", - "nodes": [ - { - "text": "continue", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " and ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "iteration", - "nodes": [ - { - "text": "break", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " keywords.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 45, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "iteration.md", - "level": 2, - "nodes": [ - { - "text": "Do While Loop", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "iteration.md", - "nodes": [ - { - "text": "A ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "iteration.md", - "nodes": [ - { - "text": "do while", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " loop is used in a situation where you want the loop to run at least ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "iteration.md", - "nodes": [ - { - "text": "1", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " iteration, regardless of the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "iteration.md", - "nodes": [ - { - "text": "condition", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "iteration.md", - "nodes": [ - { - "text": "A C/Java-style example would look something like ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-46" - }, - "file": "iteration.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-46" - }, - "nodes": [ - { - "text": "Listing 1.46", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-46" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-46", - "type": "listing" - }, - "file": "iteration.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "iteration", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-java", - "language": "java", - "src": "iteration/src/do-while/main.java#loop" - }, - "lang": "java", - "nodes": [ - { - "content": "do {\n\n // increment the index\n i++;\n\n // do the task\n task();\n\n // while the index is\n // less than N, continue\n} while (i \u003c N);", - "file": "iteration/src/do-while/main.java", - "lang": "java", - "name": "loop", - "start": 8, - "end": 20, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "iteration", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.46:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "A C/Java-style ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "iteration", - "nodes": [ - { - "text": "do while", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " loop.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 46, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "iteration.md", - "nodes": [ - { - "text": "To create a ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "iteration.md", - "nodes": [ - { - "text": "do while", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " style loop in Go a combination of an infinite loop and the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "iteration.md", - "nodes": [ - { - "text": "break", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " keyword can be used as in ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-47" - }, - "file": "iteration.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-47" - }, - "nodes": [ - { - "text": "Listing 1.47", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-47" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-47", - "type": "listing" - }, - "file": "iteration.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "iteration", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "snippet": "do", - "src": "iteration/src/do-while/main.go" - }, - "lang": "go", - "nodes": [ - { - "content": "// declare an index variable (0)\nvar i int\n\n// use an infinite loop\n// this ensures the first\n// iteration is always executed\nfor {\n\t// increment the index\n\ti++\n\n\t// do the task\n\ttask()\n\n\t// while the index is\n\t// less than N, continue\n\tif i \u003c N {\n\n\t\t// index is N or greater\n\t\t// break the loop\n\t\tbreak\n\t}\n\n}", - "file": "iteration/src/do-while/main.go", - "lang": "go", - "name": "do", - "start": 7, - "end": 32, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "iteration", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.47:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "A ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "iteration", - "nodes": [ - { - "text": "do while", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " loop in Go.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 47, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "title": "Iteration", - "type": "*hype.Page" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "type": "*hype.Include" - } - ], - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "page", - "file": "module.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "h1", - "file": "module.md", - "level": 1, - "nodes": [ - { - "text": "Summary", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "module.md", - "nodes": [ - { - "text": "In this ", - "type": "hype.Text" - }, - { - "atom": "binding", - "attributes": { - "part": "" - }, - "file": "module.md", - "type": "*hype.Element" - }, - { - "text": " we examined the differences between arrays and slices, the two basic list types in Go. We saw that slices are more flexible than arrays. Arrays are fixed length, and slices are dynamic. As a result, slices are more often used than arrays in Go.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "module.md", - "nodes": [ - { - "text": "We learned how to use built-in functions, such ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "builtin#append", - "href": "https://pkg.go.dev/builtin#append", - "target": "_blank" - }, - "file": "module.md", - "nodes": [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "append", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/builtin#append" - } - ], - { - "text": ", ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "builtin#len", - "href": "https://pkg.go.dev/builtin#len", - "target": "_blank" - }, - "file": "module.md", - "nodes": [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "len", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/builtin#len" - } - ], - { - "text": ", and ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "builtin#cap", - "href": "https://pkg.go.dev/builtin#cap", - "target": "_blank" - }, - "file": "module.md", - "nodes": [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "cap", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/builtin#cap" - } - ], - { - "text": ", to manipulate arrays and slices. We also learned how to use the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "builtin#make", - "href": "https://pkg.go.dev/builtin#make", - "target": "_blank" - }, - "file": "module.md", - "nodes": [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "make", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/builtin#make" - } - ], - { - "text": " function to create slices with specific capacities and lengths for efficiency.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "module.md", - "nodes": [ - { - "text": "Finally, in this ", - "type": "hype.Text" - }, - { - "atom": "binding", - "attributes": { - "part": "" - }, - "file": "module.md", - "type": "*hype.Element" - }, - { - "text": ", we covered iteration in Go using the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "for", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " keyword. We learned how to use the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "range", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " keyword to simplify iteration.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "title": "Summary", - "type": "*hype.Page" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "type": "*hype.Body" - } - ] - ], - "type": "*hype.Element" - } - ], - "type": "*hype.Element" - } - ], - "parser": { - "type": "*hype.Parser", - "root": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/03-collections", - "section": 1, - "snippets": {} - }, - "root": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/03-collections", - "section_id": 1, - "snippets": {}, - "title": "Arrays, Slices, and Iteration", - "type": "*hype.Document", - "filename": "module.md" -} \ No newline at end of file diff --git a/src/testdata/channels.json b/src/testdata/channels.json deleted file mode 100644 index 19e80fe..0000000 --- a/src/testdata/channels.json +++ /dev/null @@ -1,14379 +0,0 @@ -{ - "nodes": [ - { - "file": "module.md", - "nodes": [ - { - "atom": "html", - "file": "module.md", - "nodes": [ - { - "atom": "head", - "file": "module.md", - "type": "*hype.Element" - }, - [ - { - "atom": "body", - "file": "module.md", - "nodes": [ - [ - { - "atom": "page", - "file": "module.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "h1", - "file": "module.md", - "level": 1, - "nodes": [ - { - "text": "Channels", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "module.md", - "nodes": [ - { - "text": "In this ", - "type": "hype.Text" - }, - { - "atom": "binding", - "attributes": { - "part": "" - }, - "file": "module.md", - "type": "*hype.Element" - }, - { - "text": " we will start exploring concurrency in Go. We will start by discussing the difference between concurrency and parallelism. We learn about goroutines, what they are and how they behave. Finally, we will learn about channels and how they can be used to communicate between go routines as well as control them.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "module.md", - "level": 2, - "nodes": [ - { - "text": "Channels - Some Wisdom", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "module.md", - "nodes": [ - { - "text": "Before we get too far into concurrency and channels, there are some quotes about them that may help guide you in their usage:", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-1", - "type": "listing" - }, - "file": "module.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "blockquote", - "nodes": [ - { - "text": "\nI can’t tell you how many times I start with channels, and by the time I’m done, I’ve completely optimized them out. -- Cory LaNou\nWhen I first learned about channels, I wanted use them everywhere. Now, I rarely use them at all. -- Mat Ryer\n", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.1:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Quotes about Channels.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 1, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "module.md", - "nodes": [ - { - "text": "The quotes in, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-1" - }, - "file": "module.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-1" - }, - "nodes": [ - { - "text": "Listing 1.1", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-1" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", are not intended to steer you away from using channels, but more to think about do you in fact need a channel? It is common for developers new to Go to overuse channels, which leads to unnecessary code complexity with no benefit to program performance.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "title": "Channels", - "type": "*hype.Page" - } - ], - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "include", - "attributes": { - "src": "parallelism.md" - }, - "dir": ".", - "file": "module.md", - "nodes": [ - [ - { - "atom": "page", - "file": "parallelism.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "h1", - "file": "parallelism.md", - "level": 1, - "nodes": [ - { - "text": "Concurrency and Parallelism", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - { - "atom": "blockquote", - "file": "parallelism.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "parallelism.md", - "nodes": [ - { - "text": "\"According to ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "href": "https://en.wikipedia.org/wiki/Rob_Pike", - "target": "_blank" - }, - "file": "parallelism.md", - "nodes": [ - { - "text": "Rob Pike", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "https://en.wikipedia.org/wiki/Rob_Pike" - } - ], - { - "text": ", ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "href": "https://bit.ly/3GwX4V6", - "target": "_blank" - }, - "file": "parallelism.md", - "nodes": [ - { - "text": "concurrency", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "https://bit.ly/3GwX4V6" - } - ], - { - "text": " is the composition of independently executing computations, and concurrency is not parallelism: concurrency is about dealing with lots of things at once but parallelism is about doing lots of things at once. Concurrency is about structure, parallelism is about execution, concurrency provides a way to structure a solution to solve a problem that may (but not necessarily) be parallelizable.\"", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "parallelism.md", - "level": 2, - "nodes": [ - { - "text": "Concurrency is not Parallelism", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "parallelism.md", - "nodes": [ - { - "text": "Concurrency is not parallelism, although it enables parallelism.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "ul", - "file": "parallelism.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "li", - "file": "parallelism.md", - "list-type": "ul", - "nodes": [ - { - "text": "Concurrency is about dealing with a lot of things at once.", - "type": "hype.Text" - } - ], - "type": "*hype.LI" - } - ], - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "li", - "file": "parallelism.md", - "list-type": "ul", - "nodes": [ - { - "text": "Parallelism is about doing a lot of things at once.", - "type": "hype.Text" - } - ], - "type": "*hype.LI" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "type": "*hype.UL" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - { - "atom": "em", - "file": "parallelism.md", - "nodes": [ - { - "text": "If you have only one processor, your program can still be concurrent but it cannot be parallel.", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "parallelism.md", - "nodes": [ - { - "text": "If you have a single resource, and multiple tasks, you can share your time across those tasks, thus work on all tasks concurrently. However, to work on all tasks in parallel, you need need more than one resource.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "parallelism.md", - "level": 2, - "nodes": [ - { - "text": "Understanding Concurrency", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "parallelism.md", - "nodes": [ - { - "text": "Consider the task of feeding a dog, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-2" - }, - "file": "parallelism.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-2" - }, - "nodes": [ - { - "text": "Listing 1.2", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-2" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ". The dog is hungry, needs to be fed, and the treats are in a box. To feed the dog, you need to open the box, take a treat out of the box, carry the treat in your hand, and then feed the dog the treat.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-2", - "type": "listing" - }, - "file": "parallelism.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "img", - "attributes": { - "src": "assets/dog/the-problem.png", - "width": "100%" - }, - "file": ".", - "type": "*hype.Image" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": ".", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.2:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Feeding one dog, one treat, with one hand.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 2, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h3", - "file": "parallelism.md", - "level": 3, - "nodes": [ - { - "text": "Adding Dogs", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "parallelism.md", - "nodes": [ - { - "text": "In ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-3" - }, - "file": "parallelism.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-3" - }, - "nodes": [ - { - "text": "Listing 1.3", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-3" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": " a second dog also needs to be fed a treat. However, there is a resource constraint of just one hand. With one hand, you can only carry one treat at a time, and thus feed only one dog at a time.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-3", - "type": "listing" - }, - "file": "parallelism.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "img", - "attributes": { - "src": "assets/dog/two-dogs.png", - "width": "100%" - }, - "file": ".", - "type": "*hype.Image" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": ".", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.3:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Feeding two dogs, one treat, with one hand.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 3, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "parallelism.md", - "nodes": [ - { - "text": "To feed both dogs, you have to feed a treat to one dog, then take another treat from the box in your hand, and then feed a treat to the other dog. It's important to note now that because you can only feed one dog at a time, the other dog is waiting.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "parallelism.md", - "nodes": [ - { - "text": "This is a ", - "type": "hype.Text" - }, - { - "atom": "strong", - "file": "parallelism.md", - "nodes": [ - { - "text": "concurrent", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " operation.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "parallelism.md", - "nodes": [ - { - "text": "It is important to note that concurrency takes advantage of tasks in a \"waiting\" state. Instead of waiting for the first dog to finish the treat before going to the second dog and feeding it a treat, we immediately started the second dog on the task of eating a treat while the first dog was busy.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h3", - "file": "parallelism.md", - "level": 3, - "nodes": [ - { - "text": "More Hands", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "parallelism.md", - "nodes": [ - { - "text": "The one hand resource constraint can be lifted by using your other hand, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-4" - }, - "file": "parallelism.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-4" - }, - "nodes": [ - { - "text": "Listing 1.4", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-4" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ". With two hands, you can carry two treats at a time, and thus feed two dogs at a time. However, only one hand at a time can be placed into the box to retrieve a treat. This is a ", - "type": "hype.Text" - }, - { - "atom": "strong", - "file": "parallelism.md", - "nodes": [ - { - "text": "serial", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " operation and requires the scheduling of one had at a time to retrieve a treat.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-4", - "type": "listing" - }, - "file": "parallelism.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "img", - "attributes": { - "src": "assets/dog/two-dogs-two-hands.png", - "width": "100%" - }, - "file": ".", - "type": "*hype.Image" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": ".", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.4:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Feeding two dogs, two treats, with two hands.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 4, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "parallelism.md", - "nodes": [ - { - "text": "Feeding the dogs is a ", - "type": "hype.Text" - }, - { - "atom": "strong", - "file": "parallelism.md", - "nodes": [ - { - "text": "concurrent", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": ", not ", - "type": "hype.Text" - }, - { - "atom": "strong", - "file": "parallelism.md", - "nodes": [ - { - "text": "parallel", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " operation. Even though there are enough hands to feed both dogs, only one hand can retrieve a treat at a time.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h3", - "file": "parallelism.md", - "level": 3, - "nodes": [ - { - "text": "More Scenarios", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "parallelism.md", - "nodes": [ - { - "text": "If more treat boxes and dogs are added, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-5" - }, - "file": "parallelism.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-5" - }, - "nodes": [ - { - "text": "Listing 1.5", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-5" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", there are still only two hands. While this may allow for a faster concurrent operation (less waiting to get the treats as there is less contention with scheduling), there is always at least one dog waiting for a treat. This is one of many common design challenges that software engineers need to solve for when creating concurrent solutions", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-5", - "type": "listing" - }, - "file": "parallelism.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "img", - "attributes": { - "src": "assets/dog/advanced.png", - "width": "100%" - }, - "file": ".", - "type": "*hype.Image" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": ".", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.5:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Feeding multiple dogs, from multiple boxes, with two hands.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 5, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "title": "Concurrency and Parallelism", - "type": "*hype.Page" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "type": "*hype.Include" - } - ], - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "include", - "attributes": { - "src": "concurrency.md" - }, - "dir": ".", - "file": "module.md", - "nodes": [ - [ - { - "atom": "page", - "file": "concurrency.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "h1", - "file": "concurrency.md", - "level": 1, - "nodes": [ - { - "text": "Go's Concurrency Model", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "concurrency.md", - "nodes": [ - { - "text": "In a lot of languages concurrency is achieved through the use of creating heavy weight ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "href": "https://bit.ly/3Cu5NVB", - "target": "_blank" - }, - "file": "concurrency.md", - "nodes": [ - { - "text": "system processes", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "https://bit.ly/3Cu5NVB" - } - ], - { - "text": ", kernel threads, third party libraries, or other means. There are mechanics for joining threads, managing threads, implementing thread interfaces and more.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "concurrency.md", - "nodes": [ - { - "text": "In Go, concurrency is built directly into the language without the need for third party libraries, system processes, or kernel threads.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "concurrency.md", - "level": 2, - "nodes": [ - { - "text": "Goroutines", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "concurrency.md", - "nodes": [ - { - "text": "Go uses the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "href": "https://en.wikipedia.org/wiki/Coroutine", - "target": "_blank" - }, - "file": "concurrency.md", - "nodes": [ - { - "text": "coroutine", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "https://en.wikipedia.org/wiki/Coroutine" - } - ], - { - "text": " model to achieve concurrency. In Go we call these coroutine functions, \"goroutines\".", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "concurrency.md", - "nodes": [ - { - "text": "Simply put, a goroutine is an independent function, launched by a ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "concurrency.md", - "nodes": [ - { - "text": "go", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " statement, capable of being run concurrently with other goroutines. See ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-6" - }, - "file": "concurrency.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-6" - }, - "nodes": [ - { - "text": "Listing 1.6", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-6" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": " for examples of creating goroutines.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-6", - "type": "listing" - }, - "file": "concurrency.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": ".", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go" - }, - "file": ".", - "lang": "go", - "nodes": [ - { - "text": "go someFunction()\n\ngo func() {\n // do something\n}()\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": ".", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.6:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Examples of launching goroutines.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 6, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "concurrency.md", - "nodes": [ - { - "text": "A goroutine is ", - "type": "hype.Text" - }, - { - "atom": "em", - "file": "concurrency.md", - "nodes": [ - { - "text": "NOT", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " a system thread or process. It is a lightweight thread of execution that is managed by the Go runtime scheduler.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - { - "atom": "em", - "file": "concurrency.md", - "nodes": [ - { - "text": "…But if it helps you to think of a goroutine as a very cheap thread, you won't be far off…", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "concurrency.md", - "level": 2, - "nodes": [ - { - "text": "Goroutine Memory", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "concurrency.md", - "nodes": [ - { - "text": "Goroutines have their own memory call stack which will start with a small amount of memory and will grow as needed. The amount of memory each goroutine starts with can change with releases based on changes to the Go runtime, garbage collector, and language.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - { - "atom": "blockquote", - "file": "concurrency.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "concurrency.md", - "nodes": [ - { - "text": "Go does not allow developers to control the amount of memory allocated to a goroutine.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "concurrency.md", - "nodes": [ - { - "text": "Because goroutines are cheap and easy to use, it is not uncommon to have hundreds, thousands, or even millions of goroutines running at once.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "concurrency.md", - "level": 2, - "nodes": [ - { - "text": "The Go Scheduler", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "concurrency.md", - "nodes": [ - { - "text": "The scheduler in Go is responsible for distributing the runnable goroutines over multiple OS threads that run on one or more processors.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - { - "atom": "blockquote", - "file": "concurrency.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "concurrency.md", - "nodes": [ - { - "text": "Go does not allow developers to control the scheduling of goroutines.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "concurrency.md", - "nodes": [ - { - "text": "Goroutines are created in code and are then scheduled by the Go runtime scheduler, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-7" - }, - "file": "concurrency.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-7" - }, - "nodes": [ - { - "text": "Listing 1.7", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-7" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ". The scheduler is then responsible to managing those goroutines across multiple OS threads.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-7", - "type": "listing" - }, - "file": "concurrency.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "img", - "attributes": { - "src": "assets/goroutines.svg", - "width": "100%" - }, - "file": ".", - "type": "*hype.Image" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": ".", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.7:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The Go runtime scheduler.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 7, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "concurrency.md", - "level": 2, - "nodes": [ - { - "text": "Work Sharing and Stealing", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "concurrency.md", - "nodes": [ - { - "text": "Go uses a dual model of \"work sharing\" and ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "href": "https://en.wikipedia.org/wiki/Work_stealing", - "target": "_blank" - }, - "file": "concurrency.md", - "nodes": [ - { - "text": "\"work stealing\"", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "https://en.wikipedia.org/wiki/Work_stealing" - } - ], - { - "text": " to manage goroutines.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h3", - "file": "concurrency.md", - "level": 3, - "nodes": [ - { - "text": "Work Sharing", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "concurrency.md", - "nodes": [ - { - "text": "With work sharing the scheduler will try to distribute the work to the available processes. This will make better use of the available CPUs.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-8", - "type": "listing" - }, - "file": "concurrency.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": ".", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-text", - "language": "text" - }, - "file": ".", - "lang": "text", - "nodes": [ - { - "text": "CPU1: A B C D E F G\nCPU2: H I\nCPU3: J K\nCPU4:\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": ".", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.8:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "CPU load before work sharing.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 8, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "concurrency.md", - "nodes": [ - { - "text": "In ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-8" - }, - "file": "concurrency.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-8" - }, - "nodes": [ - { - "text": "Listing 1.8", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-8" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": " we see an uneven distribution of goroutines across the CPUs. Work sharing will make sure that the goroutines are distributed evenly across the available CPUs, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-9" - }, - "file": "concurrency.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-9" - }, - "nodes": [ - { - "text": "Listing 1.9", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-9" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-9", - "type": "listing" - }, - "file": "concurrency.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": ".", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-text", - "language": "text" - }, - "file": ".", - "lang": "text", - "nodes": [ - { - "text": "CPU1: A B C\nCPU2: D E F\nCPU3: G H I\nCPU4: J K\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": ".", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.9:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "CPU load after work sharing.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 9, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h3", - "file": "concurrency.md", - "level": 3, - "nodes": [ - { - "text": "Work Stealing", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "concurrency.md", - "nodes": [ - { - "text": "Unlike work sharing, work stealing works from the other-side of the scheduler. An underutilized process in the scheduler will attempt to steal work from an another process.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-10", - "type": "listing" - }, - "file": "concurrency.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": ".", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-text", - "language": "text" - }, - "file": ".", - "lang": "text", - "nodes": [ - { - "text": "CPU1: A B C D E F G\nCPU2: H I\nCPU3: J K\nCPU4:\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": ".", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.10:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "CPU load before work stealing.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 10, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "concurrency.md", - "nodes": [ - { - "text": "In ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-10" - }, - "file": "concurrency.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-10" - }, - "nodes": [ - { - "text": "Listing 1.10", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-10" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": " we see an uneven distribution of goroutines across the CPUs. Work stealing will steal work from the other CPUs, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-11" - }, - "file": "concurrency.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-11" - }, - "nodes": [ - { - "text": "Listing 1.11", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-11" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", to make the distribution even.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-11", - "type": "listing" - }, - "file": "concurrency.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": ".", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-text", - "language": "text" - }, - "file": ".", - "lang": "text", - "nodes": [ - { - "text": "CPU1: A C D E F G\nCPU2: H I\nCPU3: J K\nCPU4: B\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": ".", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.11:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "CPU load after work stealing.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 11, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "concurrency.md", - "level": 2, - "nodes": [ - { - "text": "Don't Worry About the Scheduler", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "concurrency.md", - "nodes": [ - { - "text": "Go offers little to developers in the way of managing, controlling, or tuning the scheduler. Each release of Go makes subtle, sometimes large, and sometimes non-obvious changes to the scheduler and garbage collector. Because of this, there is little point to worrying about the inner workings of the scheduler on a daily basis.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "concurrency.md", - "nodes": [ - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "runtime", - "href": "https://pkg.go.dev/runtime", - "target": "_blank" - }, - "file": "concurrency.md", - "nodes": [ - { - "atom": "code", - "file": "concurrency.md", - "nodes": [ - { - "text": "runtime", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/runtime" - } - ], - { - "text": " package provides a number of functions that can be used to query, and make small changes, to the Go runtime. One of the most useful functions is ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "runtime#GOMAXPROCS", - "href": "https://pkg.go.dev/runtime#GOMAXPROCS", - "target": "_blank" - }, - "file": "concurrency.md", - "nodes": [ - { - "atom": "code", - "file": "concurrency.md", - "nodes": [ - { - "text": "runtime.GOMAXPROCS", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/runtime#GOMAXPROCS" - } - ], - { - "text": ", ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-12" - }, - "file": "concurrency.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-12" - }, - "nodes": [ - { - "text": "Listing 1.12", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-12" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", which allows you to set the number of OS threads that the Go runtime will use.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-12", - "type": "listing" - }, - "file": "concurrency.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "doc", - "runtime.GOMAXPROCS" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "doc": "runtime.GOMAXPROCS", - "exec": "go doc runtime.GOMAXPROCS" - }, - "expected_exit": 0, - "file": ".", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc runtime.GOMAXPROCS\n\npackage runtime // import \u0026#34;runtime\u0026#34;\n\nfunc GOMAXPROCS(n int) int\n GOMAXPROCS sets the maximum number of CPUs that can be executing\n simultaneously and returns the previous setting. It defaults to the value of\n runtime.NumCPU. If n \u0026lt; 1, it does not change the current setting. This call\n will go away when the scheduler improves.", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "runtime.GOMAXPROCS" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBydW50aW1lIC8vIGltcG9ydCAicnVudGltZSIKCmZ1bmMgR09NQVhQUk9DUyhuIGludCkgaW50CiAgICBHT01BWFBST0NTIHNldHMgdGhlIG1heGltdW0gbnVtYmVyIG9mIENQVXMgdGhhdCBjYW4gYmUgZXhlY3V0aW5nCiAgICBzaW11bHRhbmVvdXNseSBhbmQgcmV0dXJucyB0aGUgcHJldmlvdXMgc2V0dGluZy4gSXQgZGVmYXVsdHMgdG8gdGhlIHZhbHVlIG9mCiAgICBydW50aW1lLk51bUNQVS4gSWYgbiA8IDEsIGl0IGRvZXMgbm90IGNoYW5nZSB0aGUgY3VycmVudCBzZXR0aW5nLiBUaGlzIGNhbGwKICAgIHdpbGwgZ28gYXdheSB3aGVuIHRoZSBzY2hlZHVsZXIgaW1wcm92ZXMu", - "duration": 203788708, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc runtime.GOMAXPROCS\n\npackage runtime // import \u0026#34;runtime\u0026#34;\n\nfunc GOMAXPROCS(n int) int\n GOMAXPROCS sets the maximum number of CPUs that can be executing\n simultaneously and returns the previous setting. It defaults to the value of\n runtime.NumCPU. If n \u0026lt; 1, it does not change the current setting. This call\n will go away when the scheduler improves.", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "runtime.GOMAXPROCS" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBydW50aW1lIC8vIGltcG9ydCAicnVudGltZSIKCmZ1bmMgR09NQVhQUk9DUyhuIGludCkgaW50CiAgICBHT01BWFBST0NTIHNldHMgdGhlIG1heGltdW0gbnVtYmVyIG9mIENQVXMgdGhhdCBjYW4gYmUgZXhlY3V0aW5nCiAgICBzaW11bHRhbmVvdXNseSBhbmQgcmV0dXJucyB0aGUgcHJldmlvdXMgc2V0dGluZy4gSXQgZGVmYXVsdHMgdG8gdGhlIHZhbHVlIG9mCiAgICBydW50aW1lLk51bUNQVS4gSWYgbiA8IDEsIGl0IGRvZXMgbm90IGNoYW5nZSB0aGUgY3VycmVudCBzZXR0aW5nLiBUaGlzIGNhbGwKICAgIHdpbGwgZ28gYXdheSB3aGVuIHRoZSBzY2hlZHVsZXIgaW1wcm92ZXMu", - "duration": 203788708, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": ".", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.12:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "runtime#GOMAXPROCS", - "href": "https://pkg.go.dev/runtime#GOMAXPROCS", - "target": "_blank" - }, - "file": ".", - "nodes": [ - [ - { - "atom": "code", - "file": ".", - "nodes": [ - { - "text": "runtime.GOMAXPROCS", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/runtime#GOMAXPROCS" - } - ], - { - "text": " function.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 12, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "concurrency.md", - "level": 2, - "nodes": [ - { - "text": "Goroutine Example", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "concurrency.md", - "nodes": [ - { - "text": "Consider the program in ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-13" - }, - "file": "concurrency.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-13" - }, - "nodes": [ - { - "text": "Listing 1.13", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-13" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ". This program should be familiar to you, it is a basic \"Hello, World\" program. The difference is that it uses a goroutine to print the message.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-13", - "type": "listing" - }, - "file": "concurrency.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": ".", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "src/concurrency/first/main.go" - }, - "lang": "go", - "nodes": [ - { - "text": "package main\n\nimport \u0026#34;fmt\u0026#34;\n\nfunc main() {\n\tgo fmt.Println(\u0026#34;Hello, World!\u0026#34;)\n}\n", - "type": "hype.Text" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": ".", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.13:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Using a goroutine to print ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": ".", - "nodes": [ - { - "text": "Hello, World!", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 13, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "concurrency.md", - "nodes": [ - { - "text": "When this code is run, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-14" - }, - "file": "concurrency.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-14" - }, - "nodes": [ - { - "text": "Listing 1.14", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-14" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", no message will be printed out. The reason is the before the scheduler has a chance to run the goroutine, the program has exited. Later, in this ", - "type": "hype.Text" - }, - { - "atom": "binding", - "attributes": { - "whole": "" - }, - "file": "concurrency.md", - "type": "*hype.Element" - }, - { - "text": " we will learn how to prevent premature exiting from a program before the scheduler has a chance to run its goroutines. We will also learn how to let our running goroutines know when it is time for them to stop.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-14", - "type": "listing" - }, - "file": "concurrency.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "run", - "." - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go run .", - "run": ".", - "src": "src/concurrency/first" - }, - "expected_exit": 0, - "file": ".", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/11-channels/src/concurrency/first", - "duration": 935353042, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/11-channels/src/concurrency/first", - "duration": 935353042, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": ".", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.14:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The goroutine was never run.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 14, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "title": "Go's Concurrency Model", - "type": "*hype.Page" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "type": "*hype.Include" - } - ], - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "include", - "attributes": { - "src": "channels.md" - }, - "dir": ".", - "file": "module.md", - "nodes": [ - [ - { - "atom": "page", - "file": "channels.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "h1", - "file": "channels.md", - "level": 1, - "nodes": [ - { - "text": "Channels", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "channels.md", - "nodes": [ - { - "text": "Channels are a conduit in Go used to communicate between goroutines. This section covers basic channel usage along with the corresponding patterns for each. We will find out the difference between a buffered and un-buffered channel, and when to use them. We will also learn how to use channels for signaling for concepts such as graceful application shutdown. Finally, we will learn how to spot common concurrency pitfalls and how to properly structure your concurrent code for to avoid them.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "channels.md", - "level": 2, - "nodes": [ - { - "text": "What are Channels?", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "channels.md", - "nodes": [ - { - "text": "Channels are a typed conduit through which you can send and receive values. All channels have the characteristics defined in ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-15" - }, - "file": "channels.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-15" - }, - "nodes": [ - { - "text": "Listing 1.15", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-15" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-15", - "type": "listing" - }, - "file": "channels.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "h3", - "file": ".", - "level": 3, - "nodes": [ - { - "text": "Characteristics of Channels", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "ul", - "file": ".", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "li", - "file": ".", - "list-type": "ul", - "nodes": [ - { - "text": "The are typed. You can only send and receive values of the same type. Ex. You can't send a string and an int over the same channel.", - "type": "hype.Text" - } - ], - "type": "*hype.LI" - } - ], - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "li", - "file": ".", - "list-type": "ul", - "nodes": [ - { - "text": "The values are transmitted/received in a synchronous manner. The sender and receiver must wait for the other to finish before sending or receiving.", - "type": "hype.Text" - } - ], - "type": "*hype.LI" - } - ], - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "li", - "file": ".", - "list-type": "ul", - "nodes": [ - { - "text": "The values are transmitted/received in a FIFO manner. The first value sent is the first value received.", - "type": "hype.Text" - } - ], - "type": "*hype.LI" - } - ], - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "li", - "file": ".", - "list-type": "ul", - "nodes": [ - { - "text": "They are either un-buffered or buffered. A buffered channel will hold a limited number of values. When the channel is full, the sender will block until a value is received. When the channel is empty, the receiver will block until a value is sent.", - "type": "hype.Text" - } - ], - "type": "*hype.LI" - } - ], - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "li", - "file": ".", - "list-type": "ul", - "nodes": [ - { - "text": "They are directional. Channels can either be bi-directional or uni-directional. A bi-directional channel can be used to send and receive values. A uni-directional channel can only be used to send or receive values.", - "type": "hype.Text" - } - ], - "type": "*hype.LI" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "type": "*hype.UL" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": ".", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.15:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Characteristics of Channels.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 15, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "channels.md", - "level": 2, - "nodes": [ - { - "text": "Understanding Channel Blocking/Unblocking", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "channels.md", - "nodes": [ - { - "text": "To understand channels you need to understand when they block and when they unblock. Consider the idea of a making a phone call. When you call someone you are blocked until they pickup the call. Once connected you are unblocked and can start bi-directional communication, in this case audio can now be exchanged back and forth between yourself and the person you are calling. The channel type would be ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "channels.md", - "nodes": [ - { - "text": "audio", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " and you would not be able to pass each other a ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "channels.md", - "nodes": [ - { - "text": "fruit", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " over the phone line.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-16", - "type": "listing" - }, - "file": "channels.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "table", - "file": ".", - "nodes": [ - { - "text": "\n ", - "type": "hype.Text" - }, - { - "atom": "tbody", - "file": ".", - "nodes": [ - { - "text": "\n ", - "type": "hype.Text" - }, - [ - { - "atom": "tr", - "file": ".", - "nodes": [ - { - "text": "\n ", - "type": "hype.Text" - }, - [ - { - "atom": "td", - "file": ".", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "img", - "attributes": { - "src": "assets/blocking.png", - "style": "width: 100%; object-fit: contain;" - }, - "file": ".", - "type": "*hype.Image" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "type": "*hype.TD" - } - ], - { - "text": "\n ", - "type": "hype.Text" - }, - [ - { - "atom": "td", - "file": ".", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "img", - "attributes": { - "src": "assets/unblocked.png", - "style": "width: 100%; object-fit: contain;" - }, - "file": ".", - "type": "*hype.Image" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "type": "*hype.TD" - } - ], - { - "text": "\n ", - "type": "hype.Text" - } - ], - "type": "*hype.TR" - } - ], - { - "text": "\n ", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": "\n", - "type": "hype.Text" - } - ], - "type": "*hype.Table" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": ".", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.16:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Blocking and Unblocking for a telephone call.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 16, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "channels.md", - "nodes": [ - { - "text": "In ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-16" - }, - "file": "channels.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-16" - }, - "nodes": [ - { - "text": "Listing 1.16", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-16" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": " we see the caller is blocked until the receiver picks up the call. Once the receiver picks up the phone, the call is unblocked and can start bi-directional communication. In this scenario, a phone call is a bi-directional channel. A phone call is an un-buffered channel. The caller and receiver are both blocked until the other unblocks them. Finally, the channel would have a type of ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "channels.md", - "nodes": [ - { - "text": "audio", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "ul", - "file": "channels.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "li", - "file": "channels.md", - "list-type": "ul", - "nodes": [ - { - "text": "A bi-directional channel.", - "type": "hype.Text" - } - ], - "type": "*hype.LI" - } - ], - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "li", - "file": "channels.md", - "list-type": "ul", - "nodes": [ - { - "text": "An un-buffered channel.", - "type": "hype.Text" - } - ], - "type": "*hype.LI" - } - ], - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "li", - "file": "channels.md", - "list-type": "ul", - "nodes": [ - { - "text": "Its type is ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "channels.md", - "nodes": [ - { - "text": "audio", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.LI" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "type": "*hype.UL" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "channels.md", - "level": 2, - "nodes": [ - { - "text": "Creating Channels", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "channels.md", - "nodes": [ - { - "text": "Channels are indicated by the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "channels.md", - "nodes": [ - { - "text": "chan", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " keyword followed by the type of the channel. For example, ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "channels.md", - "nodes": [ - { - "text": "chan string", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " indicates a channel of strings, ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "channels.md", - "nodes": [ - { - "text": "chan int", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " indicates a channel of integers, and so on.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "channels.md", - "nodes": [ - { - "text": "New channels are created with the builtin, ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "builtin#make", - "href": "https://pkg.go.dev/builtin#make", - "target": "_blank" - }, - "file": "channels.md", - "nodes": [ - { - "atom": "code", - "file": "channels.md", - "nodes": [ - { - "text": "make", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/builtin#make" - } - ], - { - "text": " function, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-17" - }, - "file": "channels.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-17" - }, - "nodes": [ - { - "text": "Listing 1.17", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-17" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ". For example, ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "channels.md", - "nodes": [ - { - "text": "make(chan string)", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " creates a channel of strings.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-17", - "type": "listing" - }, - "file": "channels.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "doc", - "builtin.make" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "doc": "builtin.make", - "exec": "go doc builtin.make" - }, - "expected_exit": 0, - "file": ".", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc builtin.make\n\npackage builtin // import \u0026#34;builtin\u0026#34;\n\nfunc make(t Type, size ...IntegerType) Type\n The make built-in function allocates and initializes an object of type\n slice, map, or chan (only). Like new, the first argument is a type,\n not a value. Unlike new, make\u0026#39;s return type is the same as the type of its\n argument, not a pointer to it. The specification of the result depends on\n the type:\n\n Slice: The size specifies the length. The capacity of the slice is\n equal to its length. A second integer argument may be provided to\n specify a different capacity; it must be no smaller than the\n length. For example, make([]int, 0, 10) allocates an underlying array\n of size 10 and returns a slice of length 0 and capacity 10 that is\n backed by this underlying array.\n Map: An empty map is allocated with enough space to hold the\n specified number of elements. The size may be omitted, in which case\n a small starting size is allocated.\n Channel: The channel\u0026#39;s buffer is initialized with the specified\n buffer capacity. If zero, or the size is omitted, the channel is\n unbuffered.", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "builtin.make" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBidWlsdGluIC8vIGltcG9ydCAiYnVpbHRpbiIKCmZ1bmMgbWFrZSh0IFR5cGUsIHNpemUgLi4uSW50ZWdlclR5cGUpIFR5cGUKICAgIFRoZSBtYWtlIGJ1aWx0LWluIGZ1bmN0aW9uIGFsbG9jYXRlcyBhbmQgaW5pdGlhbGl6ZXMgYW4gb2JqZWN0IG9mIHR5cGUKICAgIHNsaWNlLCBtYXAsIG9yIGNoYW4gKG9ubHkpLiBMaWtlIG5ldywgdGhlIGZpcnN0IGFyZ3VtZW50IGlzIGEgdHlwZSwKICAgIG5vdCBhIHZhbHVlLiBVbmxpa2UgbmV3LCBtYWtlJ3MgcmV0dXJuIHR5cGUgaXMgdGhlIHNhbWUgYXMgdGhlIHR5cGUgb2YgaXRzCiAgICBhcmd1bWVudCwgbm90IGEgcG9pbnRlciB0byBpdC4gVGhlIHNwZWNpZmljYXRpb24gb2YgdGhlIHJlc3VsdCBkZXBlbmRzIG9uCiAgICB0aGUgdHlwZToKCiAgICAgICAgU2xpY2U6IFRoZSBzaXplIHNwZWNpZmllcyB0aGUgbGVuZ3RoLiBUaGUgY2FwYWNpdHkgb2YgdGhlIHNsaWNlIGlzCiAgICAgICAgZXF1YWwgdG8gaXRzIGxlbmd0aC4gQSBzZWNvbmQgaW50ZWdlciBhcmd1bWVudCBtYXkgYmUgcHJvdmlkZWQgdG8KICAgICAgICBzcGVjaWZ5IGEgZGlmZmVyZW50IGNhcGFjaXR5OyBpdCBtdXN0IGJlIG5vIHNtYWxsZXIgdGhhbiB0aGUKICAgICAgICBsZW5ndGguIEZvciBleGFtcGxlLCBtYWtlKFtdaW50LCAwLCAxMCkgYWxsb2NhdGVzIGFuIHVuZGVybHlpbmcgYXJyYXkKICAgICAgICBvZiBzaXplIDEwIGFuZCByZXR1cm5zIGEgc2xpY2Ugb2YgbGVuZ3RoIDAgYW5kIGNhcGFjaXR5IDEwIHRoYXQgaXMKICAgICAgICBiYWNrZWQgYnkgdGhpcyB1bmRlcmx5aW5nIGFycmF5LgogICAgICAgIE1hcDogQW4gZW1wdHkgbWFwIGlzIGFsbG9jYXRlZCB3aXRoIGVub3VnaCBzcGFjZSB0byBob2xkIHRoZQogICAgICAgIHNwZWNpZmllZCBudW1iZXIgb2YgZWxlbWVudHMuIFRoZSBzaXplIG1heSBiZSBvbWl0dGVkLCBpbiB3aGljaCBjYXNlCiAgICAgICAgYSBzbWFsbCBzdGFydGluZyBzaXplIGlzIGFsbG9jYXRlZC4KICAgICAgICBDaGFubmVsOiBUaGUgY2hhbm5lbCdzIGJ1ZmZlciBpcyBpbml0aWFsaXplZCB3aXRoIHRoZSBzcGVjaWZpZWQKICAgICAgICBidWZmZXIgY2FwYWNpdHkuIElmIHplcm8sIG9yIHRoZSBzaXplIGlzIG9taXR0ZWQsIHRoZSBjaGFubmVsIGlzCiAgICAgICAgdW5idWZmZXJlZC4=", - "duration": 330847125, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc builtin.make\n\npackage builtin // import \u0026#34;builtin\u0026#34;\n\nfunc make(t Type, size ...IntegerType) Type\n The make built-in function allocates and initializes an object of type\n slice, map, or chan (only). Like new, the first argument is a type,\n not a value. Unlike new, make\u0026#39;s return type is the same as the type of its\n argument, not a pointer to it. The specification of the result depends on\n the type:\n\n Slice: The size specifies the length. The capacity of the slice is\n equal to its length. A second integer argument may be provided to\n specify a different capacity; it must be no smaller than the\n length. For example, make([]int, 0, 10) allocates an underlying array\n of size 10 and returns a slice of length 0 and capacity 10 that is\n backed by this underlying array.\n Map: An empty map is allocated with enough space to hold the\n specified number of elements. The size may be omitted, in which case\n a small starting size is allocated.\n Channel: The channel\u0026#39;s buffer is initialized with the specified\n buffer capacity. If zero, or the size is omitted, the channel is\n unbuffered.", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "builtin.make" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBidWlsdGluIC8vIGltcG9ydCAiYnVpbHRpbiIKCmZ1bmMgbWFrZSh0IFR5cGUsIHNpemUgLi4uSW50ZWdlclR5cGUpIFR5cGUKICAgIFRoZSBtYWtlIGJ1aWx0LWluIGZ1bmN0aW9uIGFsbG9jYXRlcyBhbmQgaW5pdGlhbGl6ZXMgYW4gb2JqZWN0IG9mIHR5cGUKICAgIHNsaWNlLCBtYXAsIG9yIGNoYW4gKG9ubHkpLiBMaWtlIG5ldywgdGhlIGZpcnN0IGFyZ3VtZW50IGlzIGEgdHlwZSwKICAgIG5vdCBhIHZhbHVlLiBVbmxpa2UgbmV3LCBtYWtlJ3MgcmV0dXJuIHR5cGUgaXMgdGhlIHNhbWUgYXMgdGhlIHR5cGUgb2YgaXRzCiAgICBhcmd1bWVudCwgbm90IGEgcG9pbnRlciB0byBpdC4gVGhlIHNwZWNpZmljYXRpb24gb2YgdGhlIHJlc3VsdCBkZXBlbmRzIG9uCiAgICB0aGUgdHlwZToKCiAgICAgICAgU2xpY2U6IFRoZSBzaXplIHNwZWNpZmllcyB0aGUgbGVuZ3RoLiBUaGUgY2FwYWNpdHkgb2YgdGhlIHNsaWNlIGlzCiAgICAgICAgZXF1YWwgdG8gaXRzIGxlbmd0aC4gQSBzZWNvbmQgaW50ZWdlciBhcmd1bWVudCBtYXkgYmUgcHJvdmlkZWQgdG8KICAgICAgICBzcGVjaWZ5IGEgZGlmZmVyZW50IGNhcGFjaXR5OyBpdCBtdXN0IGJlIG5vIHNtYWxsZXIgdGhhbiB0aGUKICAgICAgICBsZW5ndGguIEZvciBleGFtcGxlLCBtYWtlKFtdaW50LCAwLCAxMCkgYWxsb2NhdGVzIGFuIHVuZGVybHlpbmcgYXJyYXkKICAgICAgICBvZiBzaXplIDEwIGFuZCByZXR1cm5zIGEgc2xpY2Ugb2YgbGVuZ3RoIDAgYW5kIGNhcGFjaXR5IDEwIHRoYXQgaXMKICAgICAgICBiYWNrZWQgYnkgdGhpcyB1bmRlcmx5aW5nIGFycmF5LgogICAgICAgIE1hcDogQW4gZW1wdHkgbWFwIGlzIGFsbG9jYXRlZCB3aXRoIGVub3VnaCBzcGFjZSB0byBob2xkIHRoZQogICAgICAgIHNwZWNpZmllZCBudW1iZXIgb2YgZWxlbWVudHMuIFRoZSBzaXplIG1heSBiZSBvbWl0dGVkLCBpbiB3aGljaCBjYXNlCiAgICAgICAgYSBzbWFsbCBzdGFydGluZyBzaXplIGlzIGFsbG9jYXRlZC4KICAgICAgICBDaGFubmVsOiBUaGUgY2hhbm5lbCdzIGJ1ZmZlciBpcyBpbml0aWFsaXplZCB3aXRoIHRoZSBzcGVjaWZpZWQKICAgICAgICBidWZmZXIgY2FwYWNpdHkuIElmIHplcm8sIG9yIHRoZSBzaXplIGlzIG9taXR0ZWQsIHRoZSBjaGFubmVsIGlzCiAgICAgICAgdW5idWZmZXJlZC4=", - "duration": 330847125, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": ".", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.17:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "builtin#make", - "href": "https://pkg.go.dev/builtin#make", - "target": "_blank" - }, - "file": ".", - "nodes": [ - [ - { - "atom": "code", - "file": ".", - "nodes": [ - { - "text": "make", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/builtin#make" - } - ], - { - "text": " function.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 17, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "channels.md", - "level": 2, - "nodes": [ - { - "text": "Sending and Receiving Values", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "channels.md", - "nodes": [ - { - "text": "In Go, the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "channels.md", - "nodes": [ - { - "text": "\u0026lt;-", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " operator is used to indicate sending or receiving information on a channel. At first it can be difficult to remember where the arrow goes and what the arrow indicates.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "channels.md", - "nodes": [ - { - "text": "When working with channels the arrow, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-18" - }, - "file": "channels.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-18" - }, - "nodes": [ - { - "text": "Listing 1.18", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-18" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", points in the direction the data is traveling in regards to the channel.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-18", - "type": "listing" - }, - "file": "channels.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": ".", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go" - }, - "file": ".", - "lang": "go", - "nodes": [ - { - "text": "ch \u0026lt;- // data is going into the channel\n\u0026lt;- ch // data is coming out of the channel\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": ".", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.18:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Arrows indicating sending and receiving data.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 18, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "channels.md", - "nodes": [ - { - "text": "Consider the following code. The first line blocks trying to send, ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "channels.md", - "nodes": [ - { - "text": "Hello, Janis!", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ", to the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "channels.md", - "nodes": [ - { - "text": "phone", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " channel, ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "channels.md", - "nodes": [ - { - "text": "phone \u0026lt;- \"Hello, Janis!\"", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ". This line will only unblock when someone else is ready to receive the message. Once the message is sent and received the application is unblocked and may continue to run.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "channels.md", - "nodes": [ - { - "text": "The second line will block trying to receive a message from the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "channels.md", - "nodes": [ - { - "text": "phone", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " channel, ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "channels.md", - "nodes": [ - { - "text": "msg := \u0026lt;-phone", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ". This line will only unblock when someone else is ready to send the message. Once the message is sent and received the application is unblocked and may continue to run.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-19", - "type": "listing" - }, - "file": "channels.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": ".", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "src/channels/simple/main.go#blocking" - }, - "lang": "go", - "nodes": [ - { - "content": "// This line blocks until there is a line of code ready to\n// read from the channel.\nphone \u003c- \"Hello, Janis!\"\n\n// This line blocks until there is a line of code ready to\n// send a message down the channel.\nmsg := \u003c-phone", - "file": "src/channels/simple/main.go", - "lang": "go", - "name": "blocking", - "start": 31, - "end": 39, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": ".", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.19:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "A simple example of blocking and unblocking.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 19, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "channels.md", - "level": 2, - "nodes": [ - { - "text": "A Simple Channel Example", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "channels.md", - "nodes": [ - { - "text": "Consider the example in ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-20" - }, - "file": "channels.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-20" - }, - "nodes": [ - { - "text": "Listing 1.20", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-20" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ". In this example, the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "channels.md", - "nodes": [ - { - "text": "Janis", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function is running as a goroutine. Because it is in a goroutine it can be blocked waiting to send/receive messages on a channel and not impact the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "channels.md", - "nodes": [ - { - "text": "main", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-20", - "type": "listing" - }, - "file": "channels.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": ".", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "src/channels/simple/main.go" - }, - "lang": "go", - "nodes": [ - { - "text": "package main\n\nimport \u0026#34;fmt\u0026#34;\n\nfunc Janis(ch chan string) {\n\t// This line blocks until a message is sent to the channel\n\tmsg := \u0026lt;-ch\n\n\tfmt.Println(\u0026#34;Jimi said:\u0026#34;, msg)\n\n\t// This line blocks until the channel is read from\n\tch \u0026lt;- \u0026#34;Hello, Jimi!\u0026#34;\n}\n\nfunc main() {\n\n\t// make a new channel of type string\n\t// and assign it to the phone variable\n\tphone := make(chan string)\n\n\t// Close the channel to signal that no more messages will be sent/received.\n\tdefer close(phone)\n\n\t// Launch the Janis function as a goroutine.\n\t// This will run concurrently with the main function.\n\tgo Janis(phone)\n\n\t// This line blocks until there is a line of code ready to\n\t// read from the channel.\n\tphone \u0026lt;- \u0026#34;Hello, Janis!\u0026#34;\n\n\t// This line blocks until there is a line of code ready to\n\t// send a message down the channel.\n\tmsg := \u0026lt;-phone\n\n\tfmt.Println(\u0026#34;Janis said:\u0026#34;, msg)\n\n}\n\n", - "type": "hype.Text" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "atom": "hr", - "file": ".", - "type": "*hype.Element" - }, - [ - { - "args": [ - "go", - "run", - "." - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go run .", - "run": ".", - "src": "src/channels/simple" - }, - "expected_exit": 0, - "file": ".", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\nJimi said: Hello, Janis!\nJanis said: Hello, Jimi!", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/11-channels/src/channels/simple", - "stdout": "SmltaSBzYWlkOiBIZWxsbywgSmFuaXMhCkphbmlzIHNhaWQ6IEhlbGxvLCBKaW1pIQ==", - "duration": 344968750, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\nJimi said: Hello, Janis!\nJanis said: Hello, Jimi!", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/11-channels/src/channels/simple", - "stdout": "SmltaSBzYWlkOiBIZWxsbywgSmFuaXMhCkphbmlzIHNhaWQ6IEhlbGxvLCBKaW1pIQ==", - "duration": 344968750, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": ".", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.20:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "A simple example of a channel.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 20, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "channels.md", - "nodes": [ - { - "text": "If we were to stop using a goroutine for the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "channels.md", - "nodes": [ - { - "text": "Janis", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-21" - }, - "file": "channels.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-21" - }, - "nodes": [ - { - "text": "Listing 1.21", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-21" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", and instead, ran the function serially in the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "channels.md", - "nodes": [ - { - "text": "main", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function, the application would deadlock and crash. This is because the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "channels.md", - "nodes": [ - { - "text": "Janis", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " is blocking waiting for a message on the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "channels.md", - "nodes": [ - { - "text": "phone", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " channel, but the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "channels.md", - "nodes": [ - { - "text": "main", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function is unable to send a message on the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "channels.md", - "nodes": [ - { - "text": "phone", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " channel because ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "channels.md", - "nodes": [ - { - "text": "Janis", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " is blocked.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-21", - "type": "listing" - }, - "file": "channels.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": ".", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "src/channels/simple-broken/main.go#example" - }, - "lang": "go", - "nodes": [ - { - "content": "func main() {\n\n\t// make a new channel of type string\n\t// and assign it to the phone variable\n\tphone := make(chan string)\n\n\t// Close the channel to signal that no more messages will be sent/received.\n\tdefer close(phone)\n\n\t// Run the Amy serially instead of concurrently with a goroutine.\n\tAmy(phone)\n\n\t// This line blocks until Amy is ready to read from the channel.\n\tphone \u003c- \"Hello, Amy!\"\n\n\t// This line blocks until Amy sends a message back down the channel.\n\tmsg := \u003c-phone\n\n\tfmt.Println(\"Amy said:\", msg)\n\n}", - "file": "src/channels/simple-broken/main.go", - "lang": "go", - "name": "example", - "start": 15, - "end": 42, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "atom": "hr", - "file": ".", - "type": "*hype.Element" - }, - [ - { - "args": [ - "go", - "run", - "." - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go run .", - "exit": "-1", - "run": ".", - "src": "src/channels/simple-broken" - }, - "expected_exit": -1, - "file": ".", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\nfatal error: all goroutines are asleep - deadlock!\n\ngoroutine 1 [chan receive]:\nmain.Amy(0x1400009c058?)\n\t./main.go:7 +0x28\nmain.main()\n\t./main.go:28 +0x60\nexit status 2", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/11-channels/src/channels/simple-broken", - "err": { - "Stderr": null - }, - "exit": 1, - "stderr": "ZmF0YWwgZXJyb3I6IGFsbCBnb3JvdXRpbmVzIGFyZSBhc2xlZXAgLSBkZWFkbG9jayEKCmdvcm91dGluZSAxIFtjaGFuIHJlY2VpdmVdOgptYWluLkFteSgweDE0MDAwMDljMDU4PykKCS9Vc2Vycy9tYXJrYmF0ZXMvTGlicmFyeS9DbG91ZFN0b3JhZ2UvRHJvcGJveC9kZXYvZ3VpZGVzL2NvbnRlbnQvYm9vay9jaGFwdGVycy8xMS1jaGFubmVscy9zcmMvY2hhbm5lbHMvc2ltcGxlLWJyb2tlbi9tYWluLmdvOjcgKzB4MjgKbWFpbi5tYWluKCkKCS9Vc2Vycy9tYXJrYmF0ZXMvTGlicmFyeS9DbG91ZFN0b3JhZ2UvRHJvcGJveC9kZXYvZ3VpZGVzL2NvbnRlbnQvYm9vay9jaGFwdGVycy8xMS1jaGFubmVscy9zcmMvY2hhbm5lbHMvc2ltcGxlLWJyb2tlbi9tYWluLmdvOjI4ICsweDYwCmV4aXQgc3RhdHVzIDI=", - "duration": 1066615709, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\nfatal error: all goroutines are asleep - deadlock!\n\ngoroutine 1 [chan receive]:\nmain.Amy(0x1400009c058?)\n\t./main.go:7 +0x28\nmain.main()\n\t./main.go:28 +0x60\nexit status 2", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/11-channels/src/channels/simple-broken", - "err": { - "Stderr": null - }, - "exit": 1, - "stderr": "ZmF0YWwgZXJyb3I6IGFsbCBnb3JvdXRpbmVzIGFyZSBhc2xlZXAgLSBkZWFkbG9jayEKCmdvcm91dGluZSAxIFtjaGFuIHJlY2VpdmVdOgptYWluLkFteSgweDE0MDAwMDljMDU4PykKCS9Vc2Vycy9tYXJrYmF0ZXMvTGlicmFyeS9DbG91ZFN0b3JhZ2UvRHJvcGJveC9kZXYvZ3VpZGVzL2NvbnRlbnQvYm9vay9jaGFwdGVycy8xMS1jaGFubmVscy9zcmMvY2hhbm5lbHMvc2ltcGxlLWJyb2tlbi9tYWluLmdvOjcgKzB4MjgKbWFpbi5tYWluKCkKCS9Vc2Vycy9tYXJrYmF0ZXMvTGlicmFyeS9DbG91ZFN0b3JhZ2UvRHJvcGJveC9kZXYvZ3VpZGVzL2NvbnRlbnQvYm9vay9jaGFwdGVycy8xMS1jaGFubmVscy9zcmMvY2hhbm5lbHMvc2ltcGxlLWJyb2tlbi9tYWluLmdvOjI4ICsweDYwCmV4aXQgc3RhdHVzIDI=", - "duration": 1066615709, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": ".", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.21:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Deadlock caused by a channel that can't be unblocked.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 21, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "channels.md", - "level": 2, - "nodes": [ - { - "text": "Ranging over a Channel", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "channels.md", - "nodes": [ - { - "text": "Often you will want to keep listening for messages on a channel until the channel is closed. This can be done with an infinite loop, but the more appropriate way is to use a ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "channels.md", - "nodes": [ - { - "text": "for range", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " loop, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-22" - }, - "file": "channels.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-22" - }, - "nodes": [ - { - "text": "Listing 1.22", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-22" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ". When the channel is closed the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "channels.md", - "nodes": [ - { - "text": "range", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " loop will stop iterating and the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "channels.md", - "nodes": [ - { - "text": "listener", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function will return. We will discuss closing channels in more detail shortly.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-22", - "type": "listing" - }, - "file": "channels.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": ".", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "src/channels/range/main.go#listener" - }, - "lang": "go", - "nodes": [ - { - "content": "func listener(ch chan int) {\n\tfor i := range ch {\n\t\tfmt.Println(i)\n\t}\n\n\tfmt.Println(\"listener exit\")\n}", - "file": "src/channels/range/main.go", - "lang": "go", - "name": "listener", - "start": 8, - "end": 17, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": ".", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.22:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "A simple example of a range loop.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 22, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "channels.md", - "level": 2, - "nodes": [ - { - "text": "Listening to Channels with ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "channels.md", - "nodes": [ - { - "text": "select", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "channels.md", - "nodes": [ - { - "text": "When writing concurrent applications, it is often useful to listen to multiple channels at the same time. For example, an employee might need to listen to multiple channels at the same time, such as to receive work from their boss or be told that it is time to stop. The ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "channels.md", - "nodes": [ - { - "text": "select", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " statement lets a goroutine wait on multiple channels and respond to the first channel that is ready.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "channels.md", - "nodes": [ - { - "text": "Consider the old telephone switchboards, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-23" - }, - "file": "channels.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-23" - }, - "nodes": [ - { - "text": "Listing 1.23", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-23" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ". The telephone operator waits for incoming calls into the switchboard. When a call comes in, the operator answers the call and redirects the call to the appropriate destination. The operator then goes back to waiting for the next incoming call and so on.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-23", - "type": "listing" - }, - "file": "channels.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "img", - "attributes": { - "src": "assets/switchboard.jpg" - }, - "file": ".", - "type": "*hype.Image" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": ".", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.23:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "A telephone switchboard.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 23, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "channels.md", - "level": 2, - "nodes": [ - { - "text": "Using ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "channels.md", - "nodes": [ - { - "text": "select", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " Statements", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "channels.md", - "nodes": [ - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "channels.md", - "nodes": [ - { - "text": "select", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " statement lets a goroutine wait on multiple channels and respond to the first channel that is ready. The ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "channels.md", - "nodes": [ - { - "text": "select", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " statement will block until one of the channels is ready. Once it is ready, the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "channels.md", - "nodes": [ - { - "text": "select", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " statement will execute the corresponding ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "channels.md", - "nodes": [ - { - "text": "case", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " and the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "channels.md", - "nodes": [ - { - "text": "select", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " statement will exit. Because the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "channels.md", - "nodes": [ - { - "text": "select", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " can only be run once, it is often wrapped inside of an infinite ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "channels.md", - "nodes": [ - { - "text": "for", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " loop to re-run the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "channels.md", - "nodes": [ - { - "text": "select", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " statement after ever ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "channels.md", - "nodes": [ - { - "text": "case", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " is executed.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "channels.md", - "nodes": [ - { - "text": "Consider ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-24" - }, - "file": "channels.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-24" - }, - "nodes": [ - { - "text": "Listing 1.24", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-24" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ". The ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "channels.md", - "nodes": [ - { - "text": "operator", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function takes three different channels as arguments. The ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "channels.md", - "nodes": [ - { - "text": "select", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " statement will listen to each channel and respond to the first channel that is ready.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-24", - "type": "listing" - }, - "file": "channels.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": ".", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "src/select/select/main.go#operator" - }, - "lang": "go", - "nodes": [ - { - "content": "func operator(line1 chan string, line2 chan string, quit chan struct{}) {\n\n\t// Use an infinite loop to keep listening for new messages after\n\t// handling a previous one.\n\tfor {\n\n\t\t// select blocks until one of the cases can be executed.\n\t\tselect {\n\t\tcase msg := \u003c-line1: // listen for incoming messages on line1 and assign to msg variable\n\t\t\tfmt.Printf(\"Line 1: %s\\n\", msg)\n\t\tcase msg := \u003c-line2: // listen for incoming messages on line2 and assign to msg variable\n\t\t\tfmt.Printf(\"Line 2: %s\\n\", msg)\n\t\tcase \u003c-quit: // listen for the quit channel to be closed and exit the function\n\t\t\tfmt.Println(\"Quit\")\n\t\t\treturn\n\t\t}\n\n\t}\n}", - "file": "src/select/select/main.go", - "lang": "go", - "name": "operator", - "start": 13, - "end": 34, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": ".", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.24:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "An example of a ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": ".", - "nodes": [ - { - "text": "select", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " statement.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 24, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "channels.md", - "level": 2, - "nodes": [ - { - "text": "Channels are not Message Queues", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "channels.md", - "nodes": [ - { - "text": "Only one goroutine will receive a message sent down a channel. If multiple goroutines are listening to a channel, only one will receive the message.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "channels.md", - "nodes": [ - { - "text": "It is also possible, and likely, that one goroutine will receive more messages than another goroutine.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-25", - "type": "listing" - }, - "file": "channels.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": ".", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "src/channels/message-queue/main.go#example" - }, - "lang": "go", - "nodes": [ - { - "content": "func main() {\n\tconst N = 5\n\n\t// make a new channel\n\t// of type int\n\tch := make(chan int)\n\n\tfor i := 0; i \u003c N; i++ {\n\n\t\t// create a goroutine to listen to the channel\n\t\tgo func(i int) {\n\n\t\t\t// listen for new messages\n\t\t\tfor m := range ch {\n\t\t\t\tfmt.Printf(\"routine %d received %d\\n\", i, m)\n\t\t\t}\n\n\t\t}(i)\n\t}\n\n\t// print messages to the channel\n\tfor i := 0; i \u003c N*2; i++ {\n\t\tch \u003c- i\n\t}\n\n\t// close the channel\n\t// this will break the `range`\n\t// statement in the goroutine\n\tclose(ch)\n\n\t// wait for the goroutines to finish\n\ttime.Sleep(50 * time.Millisecond)\n}", - "file": "src/channels/message-queue/main.go", - "lang": "go", - "name": "example", - "start": 8, - "end": 43, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "atom": "hr", - "file": ".", - "type": "*hype.Element" - }, - [ - { - "args": [ - "go", - "run", - "." - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go run .", - "run": ".", - "src": "src/channels/message-queue" - }, - "expected_exit": 0, - "file": ".", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\nroutine 4 received 0\nroutine 4 received 4\nroutine 4 received 6\nroutine 0 received 2\nroutine 3 received 3\nroutine 3 received 8\nroutine 4 received 7\nroutine 2 received 5\nroutine 1 received 1\nroutine 3 received 9", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/11-channels/src/channels/message-queue", - "stdout": "cm91dGluZSA0IHJlY2VpdmVkIDAKcm91dGluZSA0IHJlY2VpdmVkIDQKcm91dGluZSA0IHJlY2VpdmVkIDYKcm91dGluZSAwIHJlY2VpdmVkIDIKcm91dGluZSAzIHJlY2VpdmVkIDMKcm91dGluZSAzIHJlY2VpdmVkIDgKcm91dGluZSA0IHJlY2VpdmVkIDcKcm91dGluZSAyIHJlY2VpdmVkIDUKcm91dGluZSAxIHJlY2VpdmVkIDEKcm91dGluZSAzIHJlY2VpdmVkIDk=", - "duration": 328026708, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\nroutine 4 received 0\nroutine 4 received 4\nroutine 4 received 6\nroutine 0 received 2\nroutine 3 received 3\nroutine 3 received 8\nroutine 4 received 7\nroutine 2 received 5\nroutine 1 received 1\nroutine 3 received 9", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/11-channels/src/channels/message-queue", - "stdout": "cm91dGluZSA0IHJlY2VpdmVkIDAKcm91dGluZSA0IHJlY2VpdmVkIDQKcm91dGluZSA0IHJlY2VpdmVkIDYKcm91dGluZSAwIHJlY2VpdmVkIDIKcm91dGluZSAzIHJlY2VpdmVkIDMKcm91dGluZSAzIHJlY2VpdmVkIDgKcm91dGluZSA0IHJlY2VpdmVkIDcKcm91dGluZSAyIHJlY2VpdmVkIDUKcm91dGluZSAxIHJlY2VpdmVkIDEKcm91dGluZSAzIHJlY2VpdmVkIDk=", - "duration": 328026708, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": ".", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.25:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Messages are pulled off a channel by the first goroutine to read from it.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 25, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "title": "Channels", - "type": "*hype.Page" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "type": "*hype.Include" - } - ], - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "include", - "attributes": { - "src": "unidirectional.md" - }, - "dir": ".", - "file": "module.md", - "nodes": [ - [ - { - "atom": "page", - "file": "unidirectional.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "h1", - "file": "unidirectional.md", - "level": 1, - "nodes": [ - { - "text": "Uni-Directional Channels", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "unidirectional.md", - "nodes": [ - { - "text": "By default channels are bi-directional, meaning you can both send and receive data from the channel.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "unidirectional.md", - "nodes": [ - { - "text": "A common use for uni-directional channels is when you are passing a channel as an argument or receiving a channel as return value. This allows for control of the channel for the function/method and prevents outside callers from polluting the channel.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "unidirectional.md", - "nodes": [ - { - "text": "The standard library does this in the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "time", - "href": "https://pkg.go.dev/time", - "target": "_blank" - }, - "file": "unidirectional.md", - "nodes": [ - { - "atom": "code", - "file": "unidirectional.md", - "nodes": [ - { - "text": "time", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/time" - } - ], - { - "text": " package with methods like ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "time#Ticker", - "href": "https://pkg.go.dev/time#Ticker", - "target": "_blank" - }, - "file": "unidirectional.md", - "nodes": [ - { - "atom": "code", - "file": "unidirectional.md", - "nodes": [ - { - "text": "time.Ticker", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/time#Ticker" - } - ], - { - "text": ", ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-26" - }, - "file": "unidirectional.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-26" - }, - "nodes": [ - { - "text": "Listing 1.26", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-26" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-26", - "type": "listing" - }, - "file": "unidirectional.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "doc", - "time.Ticker" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "doc": "time.Ticker", - "exec": "go doc time.Ticker" - }, - "expected_exit": 0, - "file": ".", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc time.Ticker\n\npackage time // import \u0026#34;time\u0026#34;\n\ntype Ticker struct {\n\tC \u0026lt;-chan Time // The channel on which the ticks are delivered.\n\t// Has unexported fields.\n}\n A Ticker holds a channel that delivers “ticks” of a clock at intervals.\n\nfunc NewTicker(d Duration) *Ticker\nfunc (t *Ticker) Reset(d Duration)\nfunc (t *Ticker) Stop()", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "time.Ticker" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSB0aW1lIC8vIGltcG9ydCAidGltZSIKCnR5cGUgVGlja2VyIHN0cnVjdCB7CglDIDwtY2hhbiBUaW1lIC8vIFRoZSBjaGFubmVsIG9uIHdoaWNoIHRoZSB0aWNrcyBhcmUgZGVsaXZlcmVkLgoJLy8gSGFzIHVuZXhwb3J0ZWQgZmllbGRzLgp9CiAgICBBIFRpY2tlciBob2xkcyBhIGNoYW5uZWwgdGhhdCBkZWxpdmVycyDigJx0aWNrc+KAnSBvZiBhIGNsb2NrIGF0IGludGVydmFscy4KCmZ1bmMgTmV3VGlja2VyKGQgRHVyYXRpb24pICpUaWNrZXIKZnVuYyAodCAqVGlja2VyKSBSZXNldChkIER1cmF0aW9uKQpmdW5jICh0ICpUaWNrZXIpIFN0b3AoKQ==", - "duration": 217767334, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc time.Ticker\n\npackage time // import \u0026#34;time\u0026#34;\n\ntype Ticker struct {\n\tC \u0026lt;-chan Time // The channel on which the ticks are delivered.\n\t// Has unexported fields.\n}\n A Ticker holds a channel that delivers “ticks” of a clock at intervals.\n\nfunc NewTicker(d Duration) *Ticker\nfunc (t *Ticker) Reset(d Duration)\nfunc (t *Ticker) Stop()", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "time.Ticker" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSB0aW1lIC8vIGltcG9ydCAidGltZSIKCnR5cGUgVGlja2VyIHN0cnVjdCB7CglDIDwtY2hhbiBUaW1lIC8vIFRoZSBjaGFubmVsIG9uIHdoaWNoIHRoZSB0aWNrcyBhcmUgZGVsaXZlcmVkLgoJLy8gSGFzIHVuZXhwb3J0ZWQgZmllbGRzLgp9CiAgICBBIFRpY2tlciBob2xkcyBhIGNoYW5uZWwgdGhhdCBkZWxpdmVycyDigJx0aWNrc+KAnSBvZiBhIGNsb2NrIGF0IGludGVydmFscy4KCmZ1bmMgTmV3VGlja2VyKGQgRHVyYXRpb24pICpUaWNrZXIKZnVuYyAodCAqVGlja2VyKSBSZXNldChkIER1cmF0aW9uKQpmdW5jICh0ICpUaWNrZXIpIFN0b3AoKQ==", - "duration": 217767334, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": ".", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.26:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "time#Ticker", - "href": "https://pkg.go.dev/time#Ticker", - "target": "_blank" - }, - "file": ".", - "nodes": [ - [ - { - "atom": "code", - "file": ".", - "nodes": [ - { - "text": "time.Ticker", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/time#Ticker" - } - ], - { - "text": " function.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 26, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "unidirectional.md", - "level": 2, - "nodes": [ - { - "text": "Understanding Uni-Directional Channels", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "unidirectional.md", - "nodes": [ - { - "text": "Consider ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-27" - }, - "file": "unidirectional.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-27" - }, - "nodes": [ - { - "text": "Listing 1.27", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-27" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ". The ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "unidirectional.md", - "nodes": [ - { - "text": "Newspaper", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " contains a bi-directional channel, ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "unidirectional.md", - "nodes": [ - { - "text": "headlines chan string", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ", as a field. It also exposes two methods, ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "unidirectional.md", - "nodes": [ - { - "text": "TopHeadlines", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " and ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "unidirectional.md", - "nodes": [ - { - "text": "ReportStory", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-27", - "type": "listing" - }, - "file": "unidirectional.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": ".", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "snippet": "type", - "src": "src/channels/uni/main.go" - }, - "lang": "go", - "nodes": [ - { - "content": "type Newspaper struct {\n\theadlines chan string\n\tquit chan struct{}\n}\n\n// TopHeadlines returns a read-only channel of strings\n// that represent the top headlines of the newspaper.\n// This channel is consumed by newspaper readers.\nfunc (n Newspaper) TopHeadlines() \u003c-chan string {\n\treturn n.headlines\n}\n\n\n// ReportStory returns a write-only channel of strings\n// that a reporter can use to report a story.\nfunc (n Newspaper) ReportStory() chan\u003c- string {\n\treturn n.headlines\n}", - "file": "src/channels/uni/main.go", - "lang": "go", - "name": "type", - "start": 8, - "end": 32, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": ".", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.27:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": ".", - "nodes": [ - { - "text": "Newspaper", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " type.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 27, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "unidirectional.md", - "nodes": [ - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "unidirectional.md", - "nodes": [ - { - "text": "TopHeadlines", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " method returns a read-only version of the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "unidirectional.md", - "nodes": [ - { - "text": "headlines", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " channel that can be consumed by newspaper readers.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "unidirectional.md", - "nodes": [ - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "unidirectional.md", - "nodes": [ - { - "text": "ReportStory", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " method returns a write-only version of the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "unidirectional.md", - "nodes": [ - { - "text": "headlines", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " channel that can be used by newspaper reporters to report their stories to the newspaper.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "unidirectional.md", - "nodes": [ - { - "text": "In both cases, Go, casts the bi-directional channel, ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "unidirectional.md", - "nodes": [ - { - "text": "headlines", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ", to the appropriate uni-directional channel returned by the method.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "title": "Uni-Directional Channels", - "type": "*hype.Page" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "type": "*hype.Include" - } - ], - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "include", - "attributes": { - "src": "closing.md" - }, - "dir": ".", - "file": "module.md", - "nodes": [ - [ - { - "atom": "page", - "file": "closing.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "h1", - "file": "closing.md", - "level": 1, - "nodes": [ - { - "text": "Closing Channels", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "closing.md", - "nodes": [ - { - "text": "As we have seen so far, when a message is sent to a channel, only one receiver can pull that message off the channel. Channels do not provide a \"fan-out\" type of functionality where many receivers can pull the same message off of a channel.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "closing.md", - "nodes": [ - { - "text": "The exception to this rule is when a channel is closed. When a channel is closed ", - "type": "hype.Text" - }, - { - "atom": "strong", - "file": "closing.md", - "nodes": [ - { - "text": "ALL", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " receivers will be notified that the channel is closed. This can be exploited to signal many listeners, goroutines, that it is time to stop what they're doing.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-28", - "type": "listing" - }, - "file": "closing.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": ".", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "src/closing/quit/main.go#listener" - }, - "lang": "go", - "nodes": [ - { - "content": "func listener(i int, quit \u003c-chan struct{}) {\n\tfmt.Printf(\"listener %d is waiting\\n\", i)\n\n\t// this will block until the channel is closed\n\t\u003c-quit\n\n\tfmt.Printf(\"listener %d is exiting\\n\", i)\n}", - "file": "src/closing/quit/main.go", - "lang": "go", - "name": "listener", - "start": 8, - "end": 18, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": ".", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.28:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": ".", - "nodes": [ - { - "text": "Listener", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 28, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "closing.md", - "nodes": [ - { - "text": "Consider ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-28" - }, - "file": "closing.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-28" - }, - "nodes": [ - { - "text": "Listing 1.28", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-28" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ". The ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "closing.md", - "nodes": [ - { - "text": "listener", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function takes a ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "closing.md", - "nodes": [ - { - "text": "\u0026lt;-chan struct{}", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " as the last argument, ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "closing.md", - "nodes": [ - { - "text": "quit", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ". The function listens for a signal on the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "closing.md", - "nodes": [ - { - "text": "quit", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " channel, which is a blocking operation. When the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "closing.md", - "nodes": [ - { - "text": "quit", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " channel is closed elsewhere, the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "closing.md", - "nodes": [ - { - "text": "listener", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function will exit.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-29", - "type": "listing" - }, - "file": "closing.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - null, - { - "atom": "pre", - "file": ".", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "src/closing/quit/main.go#main" - }, - "lang": "go", - "nodes": [ - { - "content": "func main() {\n\t// create a channel to signal listeners to exit\n\tquit := make(chan struct{})\n\n\t// create 5 listeners\n\tfor i := 0; i \u003c 5; i++ {\n\t\t// launch listener in a goroutine\n\t\tgo listener(i, quit)\n\t}\n\n\t// allow the listeners to start\n\ttime.Sleep(10 * time.Millisecond)\n\n\tfmt.Println(\"closing the quit channel\")\n\n\t// close the channel to signal listeners to exit\n\tclose(quit)\n\n\t// allow the listeners to exit\n\ttime.Sleep(50 * time.Millisecond)\n}", - "file": "src/closing/quit/main.go", - "lang": "go", - "name": "main", - "start": 20, - "end": 43, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "atom": "hr", - "file": ".", - "type": "*hype.Element" - }, - [ - { - "args": [ - "go", - "run", - "." - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go run .", - "run": ".", - "src": "src/closing/quit" - }, - "expected_exit": 0, - "file": ".", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\nlistener 0 is waiting\nlistener 4 is waiting\nlistener 3 is waiting\nlistener 2 is waiting\nlistener 1 is waiting\nclosing the quit channel\nlistener 0 is exiting\nlistener 3 is exiting\nlistener 4 is exiting\nlistener 1 is exiting\nlistener 2 is exiting", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/11-channels/src/closing/quit", - "stdout": "bGlzdGVuZXIgMCBpcyB3YWl0aW5nCmxpc3RlbmVyIDQgaXMgd2FpdGluZwpsaXN0ZW5lciAzIGlzIHdhaXRpbmcKbGlzdGVuZXIgMiBpcyB3YWl0aW5nCmxpc3RlbmVyIDEgaXMgd2FpdGluZwpjbG9zaW5nIHRoZSBxdWl0IGNoYW5uZWwKbGlzdGVuZXIgMCBpcyBleGl0aW5nCmxpc3RlbmVyIDMgaXMgZXhpdGluZwpsaXN0ZW5lciA0IGlzIGV4aXRpbmcKbGlzdGVuZXIgMSBpcyBleGl0aW5nCmxpc3RlbmVyIDIgaXMgZXhpdGluZw==", - "duration": 539691375, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\nlistener 0 is waiting\nlistener 4 is waiting\nlistener 3 is waiting\nlistener 2 is waiting\nlistener 1 is waiting\nclosing the quit channel\nlistener 0 is exiting\nlistener 3 is exiting\nlistener 4 is exiting\nlistener 1 is exiting\nlistener 2 is exiting", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/11-channels/src/closing/quit", - "stdout": "bGlzdGVuZXIgMCBpcyB3YWl0aW5nCmxpc3RlbmVyIDQgaXMgd2FpdGluZwpsaXN0ZW5lciAzIGlzIHdhaXRpbmcKbGlzdGVuZXIgMiBpcyB3YWl0aW5nCmxpc3RlbmVyIDEgaXMgd2FpdGluZwpjbG9zaW5nIHRoZSBxdWl0IGNoYW5uZWwKbGlzdGVuZXIgMCBpcyBleGl0aW5nCmxpc3RlbmVyIDMgaXMgZXhpdGluZwpsaXN0ZW5lciA0IGlzIGV4aXRpbmcKbGlzdGVuZXIgMSBpcyBleGl0aW5nCmxpc3RlbmVyIDIgaXMgZXhpdGluZw==", - "duration": 539691375, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": ".", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.29:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": ".", - "nodes": [ - { - "text": "main", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - null, - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 29, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "closing.md", - "nodes": [ - { - "text": "In ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-29" - }, - "file": "closing.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-29" - }, - "nodes": [ - { - "text": "Listing 1.29", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-29" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": " we create a ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "closing.md", - "nodes": [ - { - "text": "chan struct{}", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " named ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "closing.md", - "nodes": [ - { - "text": "quit", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ". Then we create a handful of goroutines for the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "closing.md", - "nodes": [ - { - "text": "listener", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function passing it the loop index and the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "closing.md", - "nodes": [ - { - "text": "quit", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " channel.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "closing.md", - "nodes": [ - { - "text": "We sleep shortly to allow the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "closing.md", - "nodes": [ - { - "text": "listener", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " goroutines to start and listen to the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "closing.md", - "nodes": [ - { - "text": "quit", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " channel. Then we close the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "closing.md", - "nodes": [ - { - "text": "quit", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " channel, ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "closing.md", - "nodes": [ - { - "text": "close(quit)", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ". Finally, we sleep again to allow the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "closing.md", - "nodes": [ - { - "text": "listener", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " goroutines to exit.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "closing.md", - "level": 2, - "nodes": [ - { - "text": "Detecting Closed Channels On Read", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "closing.md", - "nodes": [ - { - "text": "When listening to a channel it can often be useful to know if the channel is closed or not. Like we've seen with type assertions and map key assertions, we can use the magic ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "closing.md", - "nodes": [ - { - "text": "ok", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " value to check if a channel is closed.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "closing.md", - "nodes": [ - { - "text": "In ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-30" - }, - "file": "closing.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-30" - }, - "nodes": [ - { - "text": "Listing 1.30", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-30" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", we ask for, not just the incoming message from the channel, but also the second boolean argument ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "closing.md", - "nodes": [ - { - "text": "ok", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " which will be ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "closing.md", - "nodes": [ - { - "text": "true", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " if the channel is open and ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "closing.md", - "nodes": [ - { - "text": "false", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " if it is closed.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-30", - "type": "listing" - }, - "file": "closing.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - null, - { - "atom": "pre", - "file": ".", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "src/closing/closed-read/main.go#listener" - }, - "lang": "go", - "nodes": [ - { - "content": "func listener(ch \u003c-chan int) {\n\n\t// infinite loop to keep listening\n\t// for messages on the channel\n\tfor {\n\n\t\t// store the message from the channel to variable i\n\t\t// capture if the channel is closed or not to variable ok\n\t\ti, ok := \u003c-ch\n\n\t\t// if the channel is closed, return from the function\n\t\tif !ok {\n\t\t\tfmt.Println(\"closed channel\")\n\t\t\treturn\n\t\t}\n\n\t\t// print the message\n\t\tfmt.Printf(\"read %d from channel\\n\", i)\n\t}\n\n}", - "file": "src/closing/closed-read/main.go", - "lang": "go", - "name": "listener", - "start": 8, - "end": 31, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "atom": "hr", - "file": ".", - "type": "*hype.Element" - }, - [ - { - "args": [ - "go", - "run", - "." - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go run .", - "run": ".", - "src": "src/closing/closed-read" - }, - "expected_exit": 0, - "file": ".", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\nread 0 from channel\nread 1 from channel\nread 2 from channel\nread 3 from channel\nread 4 from channel\nclosed channel", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/11-channels/src/closing/closed-read", - "stdout": "cmVhZCAwIGZyb20gY2hhbm5lbApyZWFkIDEgZnJvbSBjaGFubmVsCnJlYWQgMiBmcm9tIGNoYW5uZWwKcmVhZCAzIGZyb20gY2hhbm5lbApyZWFkIDQgZnJvbSBjaGFubmVsCmNsb3NlZCBjaGFubmVs", - "duration": 905539750, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\nread 0 from channel\nread 1 from channel\nread 2 from channel\nread 3 from channel\nread 4 from channel\nclosed channel", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/11-channels/src/closing/closed-read", - "stdout": "cmVhZCAwIGZyb20gY2hhbm5lbApyZWFkIDEgZnJvbSBjaGFubmVsCnJlYWQgMiBmcm9tIGNoYW5uZWwKcmVhZCAzIGZyb20gY2hhbm5lbApyZWFkIDQgZnJvbSBjaGFubmVsCmNsb3NlZCBjaGFubmVs", - "duration": 905539750, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": ".", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.30:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Reading from a closed channel.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - null, - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 30, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "closing.md", - "level": 2, - "nodes": [ - { - "text": "Zero Value on Closed Read", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "closing.md", - "nodes": [ - { - "text": "When reading from a channel that has been closed, we will get the zero value of the channel's type returned, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-31" - }, - "file": "closing.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-31" - }, - "nodes": [ - { - "text": "Listing 1.31", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-31" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ". This is similar to when we ask for a map key that doesn't exist, we get back the zero value of the map's value type.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-31", - "type": "listing" - }, - "file": "closing.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - null, - { - "atom": "pre", - "file": ".", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "src/closing/closed-zero-bad/main.go#main" - }, - "lang": "go", - "nodes": [ - { - "content": "func main() {\n\t// make a channel of type User\n\tch := make(chan User)\n\n\t// launch a goroutine to send a User down the channel\n\tgo func() {\n\n\t\t// send a User down the channel\n\t\tch \u003c- User{ID: 1, Name: \"Amy\"}\n\t}()\n\n\t// read the User from the channel\n\tuser := \u003c-ch\n\tfmt.Printf(\"read successful: %+v\\n\", user)\n\n\t// close the channel\n\tclose(ch)\n\n\t// try to read from the channel again\n\tuser = \u003c-ch\n\tfmt.Println(\"attempted read of closed channel\")\n\tfmt.Printf(\"received zero value %s\\n\", user)\n\n}", - "file": "src/closing/closed-zero-bad/main.go", - "lang": "go", - "name": "main", - "start": 17, - "end": 43, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "atom": "hr", - "file": ".", - "type": "*hype.Element" - }, - [ - { - "args": [ - "go", - "run", - "." - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go run .", - "run": ".", - "src": "src/closing/closed-zero-bad" - }, - "expected_exit": 0, - "file": ".", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\nread successful: \u0026lt;User: id:\u0026#34;1\u0026#34; name:\u0026#34;Amy\u0026#34;\u0026gt;\nattempted read of closed channel\nreceived zero value \u0026lt;User: id:\u0026#34;0\u0026#34; name:\u0026#34;\u0026#34;\u0026gt;", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/11-channels/src/closing/closed-zero-bad", - "stdout": "cmVhZCBzdWNjZXNzZnVsOiA8VXNlcjogaWQ6IjEiIG5hbWU6IkFteSI+CmF0dGVtcHRlZCByZWFkIG9mIGNsb3NlZCBjaGFubmVsCnJlY2VpdmVkIHplcm8gdmFsdWUgPFVzZXI6IGlkOiIwIiBuYW1lOiIiPg==", - "duration": 862862542, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\nread successful: \u0026lt;User: id:\u0026#34;1\u0026#34; name:\u0026#34;Amy\u0026#34;\u0026gt;\nattempted read of closed channel\nreceived zero value \u0026lt;User: id:\u0026#34;0\u0026#34; name:\u0026#34;\u0026#34;\u0026gt;", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/11-channels/src/closing/closed-zero-bad", - "stdout": "cmVhZCBzdWNjZXNzZnVsOiA8VXNlcjogaWQ6IjEiIG5hbWU6IkFteSI+CmF0dGVtcHRlZCByZWFkIG9mIGNsb3NlZCBjaGFubmVsCnJlY2VpdmVkIHplcm8gdmFsdWUgPFVzZXI6IGlkOiIwIiBuYW1lOiIiPg==", - "duration": 862862542, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": ".", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.31:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "A zero value is returned when reading a closed channel.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - null, - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 31, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "closing.md", - "nodes": [ - { - "text": "By checking if the channel is closed or not, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-32" - }, - "file": "closing.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-32" - }, - "nodes": [ - { - "text": "Listing 1.32", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-32" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", we can avoid the zero value and take appropriate action.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-32", - "type": "listing" - }, - "file": "closing.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - null, - { - "atom": "pre", - "file": ".", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "src/closing/closed-zero-good/main.go#main" - }, - "lang": "go", - "nodes": [ - { - "content": "func main() {\n\n\t// make a channel of type User\n\tch := make(chan User)\n\n\t// launch a goroutine to send a User down the channel\n\tgo func() {\n\n\t\t// send a User down the channel\n\t\tch \u003c- User{ID: 1, Name: \"Amy\"}\n\t}()\n\n\t// read the User from the channel\n\tuser := \u003c-ch\n\tfmt.Printf(\"read successful: %+v\\n\", user)\n\n\t// close the channel\n\tclose(ch)\n\n\t// try to read from the channel again\n\tuser, ok := \u003c-ch\n\n\t// check if the channel is closed\n\tif !ok {\n\t\tfmt.Println(\"attempted read of closed channel\")\n\t\tfmt.Printf(\"received zero value %s\\n\", user)\n\t\treturn\n\t}\n\n\t// the channel is still open, so print the user.\n\tfmt.Printf(\"read successful: %+v\\n\", user)\n}", - "file": "src/closing/closed-zero-good/main.go", - "lang": "go", - "name": "main", - "start": 17, - "end": 51, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "atom": "hr", - "file": ".", - "type": "*hype.Element" - }, - [ - { - "args": [ - "go", - "run", - "." - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go run .", - "run": ".", - "src": "src/closing/closed-zero-good" - }, - "expected_exit": 0, - "file": ".", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\nread successful: \u0026lt;User: id:\u0026#34;1\u0026#34; name:\u0026#34;Amy\u0026#34;\u0026gt;\nattempted read of closed channel\nreceived zero value \u0026lt;User: id:\u0026#34;0\u0026#34; name:\u0026#34;\u0026#34;\u0026gt;", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/11-channels/src/closing/closed-zero-good", - "stdout": "cmVhZCBzdWNjZXNzZnVsOiA8VXNlcjogaWQ6IjEiIG5hbWU6IkFteSI+CmF0dGVtcHRlZCByZWFkIG9mIGNsb3NlZCBjaGFubmVsCnJlY2VpdmVkIHplcm8gdmFsdWUgPFVzZXI6IGlkOiIwIiBuYW1lOiIiPg==", - "duration": 544407750, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\nread successful: \u0026lt;User: id:\u0026#34;1\u0026#34; name:\u0026#34;Amy\u0026#34;\u0026gt;\nattempted read of closed channel\nreceived zero value \u0026lt;User: id:\u0026#34;0\u0026#34; name:\u0026#34;\u0026#34;\u0026gt;", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/11-channels/src/closing/closed-zero-good", - "stdout": "cmVhZCBzdWNjZXNzZnVsOiA8VXNlcjogaWQ6IjEiIG5hbWU6IkFteSI+CmF0dGVtcHRlZCByZWFkIG9mIGNsb3NlZCBjaGFubmVsCnJlY2VpdmVkIHplcm8gdmFsdWUgPFVzZXI6IGlkOiIwIiBuYW1lOiIiPg==", - "duration": 544407750, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": ".", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.32:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "A zero value is not returned when reading a closed channel.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - null, - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 32, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "closing.md", - "level": 2, - "nodes": [ - { - "text": "Closing an Already Closed Channel", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "closing.md", - "nodes": [ - { - "text": "Care must be taken when closing a channel. If the channel has already been closed, a panic will be raised and the application will crash, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-33" - }, - "file": "closing.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-33" - }, - "nodes": [ - { - "text": "Listing 1.33", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-33" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-33", - "type": "listing" - }, - "file": "closing.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - null, - { - "atom": "pre", - "file": ".", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "src/closing/close-closed/main.go#main" - }, - "lang": "go", - "nodes": [ - { - "content": "func main() {\n\n\t// make a new channel\n\tch := make(chan struct{})\n\n\t// close the channel\n\tclose(ch)\n\n\t// try to close the channel again\n\t// this will panic\n\tclose(ch)\n\n}", - "file": "src/closing/close-closed/main.go", - "lang": "go", - "name": "main", - "start": 3, - "end": 18, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "atom": "hr", - "file": ".", - "type": "*hype.Element" - }, - [ - { - "args": [ - "go", - "run", - "." - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go run .", - "exit": "-1", - "run": ".", - "src": "src/closing/close-closed" - }, - "expected_exit": -1, - "file": ".", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\npanic: close of closed channel\n\ngoroutine 1 [running]:\nmain.main()\n\t./main.go:14 +0x38\nexit status 2", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/11-channels/src/closing/close-closed", - "err": { - "Stderr": null - }, - "exit": 1, - "stderr": "cGFuaWM6IGNsb3NlIG9mIGNsb3NlZCBjaGFubmVsCgpnb3JvdXRpbmUgMSBbcnVubmluZ106Cm1haW4ubWFpbigpCgkvVXNlcnMvbWFya2JhdGVzL0xpYnJhcnkvQ2xvdWRTdG9yYWdlL0Ryb3Bib3gvZGV2L2d1aWRlcy9jb250ZW50L2Jvb2svY2hhcHRlcnMvMTEtY2hhbm5lbHMvc3JjL2Nsb3NpbmcvY2xvc2UtY2xvc2VkL21haW4uZ286MTQgKzB4MzgKZXhpdCBzdGF0dXMgMg==", - "duration": 603889458, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\npanic: close of closed channel\n\ngoroutine 1 [running]:\nmain.main()\n\t./main.go:14 +0x38\nexit status 2", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/11-channels/src/closing/close-closed", - "err": { - "Stderr": null - }, - "exit": 1, - "stderr": "cGFuaWM6IGNsb3NlIG9mIGNsb3NlZCBjaGFubmVsCgpnb3JvdXRpbmUgMSBbcnVubmluZ106Cm1haW4ubWFpbigpCgkvVXNlcnMvbWFya2JhdGVzL0xpYnJhcnkvQ2xvdWRTdG9yYWdlL0Ryb3Bib3gvZGV2L2d1aWRlcy9jb250ZW50L2Jvb2svY2hhcHRlcnMvMTEtY2hhbm5lbHMvc3JjL2Nsb3NpbmcvY2xvc2UtY2xvc2VkL21haW4uZ286MTQgKzB4MzgKZXhpdCBzdGF0dXMgMg==", - "duration": 603889458, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": ".", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.33:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Panicking when closing an already closed channel.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - null, - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 33, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "closing.md", - "nodes": [ - { - "text": "Later is this ", - "type": "hype.Text" - }, - { - "atom": "binding", - "attributes": { - "whole": "" - }, - "file": "closing.md", - "type": "*hype.Element" - }, - { - "text": ", we will will learn about different synchronization primitives that can be used to help prevent this sort of situation.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "closing.md", - "level": 2, - "nodes": [ - { - "text": "Writing to a Closed Channel", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "closing.md", - "nodes": [ - { - "text": "If we attempt to write to a closed channel, as in ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-34" - }, - "file": "closing.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-34" - }, - "nodes": [ - { - "text": "Listing 1.34", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-34" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", a panic will be raised and the application will crash. Unfortunately, there is no way to check if the channel is closed before writing. With proper synchronization, good architecture, and solid tests, we can prevent this situation.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - null, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-34", - "type": "listing" - }, - "file": "closing.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": ".", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "src/closing/closed-write/main.go#main" - }, - "lang": "go", - "nodes": [ - { - "content": "func main() {\n\n\t// make a new channel\n\tch := make(chan int)\n\n\t// close the channel\n\tclose(ch)\n\n\t// try to write to the closed channel\n\t// this will panic\n\tch \u003c- 1\n\n}", - "file": "src/closing/closed-write/main.go", - "lang": "go", - "name": "main", - "start": 3, - "end": 18, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "atom": "hr", - "file": ".", - "type": "*hype.Element" - }, - [ - { - "args": [ - "go", - "run", - "." - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go run .", - "exit": "-1", - "run": ".", - "src": "src/closing/closed-write" - }, - "expected_exit": -1, - "file": ".", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\npanic: send on closed channel\n\ngoroutine 1 [running]:\nmain.main()\n\t./main.go:14 +0x40\nexit status 2", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/11-channels/src/closing/closed-write", - "err": { - "Stderr": null - }, - "exit": 1, - "stderr": "cGFuaWM6IHNlbmQgb24gY2xvc2VkIGNoYW5uZWwKCmdvcm91dGluZSAxIFtydW5uaW5nXToKbWFpbi5tYWluKCkKCS9Vc2Vycy9tYXJrYmF0ZXMvTGlicmFyeS9DbG91ZFN0b3JhZ2UvRHJvcGJveC9kZXYvZ3VpZGVzL2NvbnRlbnQvYm9vay9jaGFwdGVycy8xMS1jaGFubmVscy9zcmMvY2xvc2luZy9jbG9zZWQtd3JpdGUvbWFpbi5nbzoxNCArMHg0MApleGl0IHN0YXR1cyAy", - "duration": 204237625, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\npanic: send on closed channel\n\ngoroutine 1 [running]:\nmain.main()\n\t./main.go:14 +0x40\nexit status 2", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/11-channels/src/closing/closed-write", - "err": { - "Stderr": null - }, - "exit": 1, - "stderr": "cGFuaWM6IHNlbmQgb24gY2xvc2VkIGNoYW5uZWwKCmdvcm91dGluZSAxIFtydW5uaW5nXToKbWFpbi5tYWluKCkKCS9Vc2Vycy9tYXJrYmF0ZXMvTGlicmFyeS9DbG91ZFN0b3JhZ2UvRHJvcGJveC9kZXYvZ3VpZGVzL2NvbnRlbnQvYm9vay9jaGFwdGVycy8xMS1jaGFubmVscy9zcmMvY2xvc2luZy9jbG9zZWQtd3JpdGUvbWFpbi5nbzoxNCArMHg0MApleGl0IHN0YXR1cyAy", - "duration": 204237625, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": ".", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.34:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Panicking when writing to a closed channel.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 34, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "title": "Closing Channels", - "type": "*hype.Page" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "type": "*hype.Include" - } - ], - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "include", - "attributes": { - "src": "buffered.md" - }, - "dir": ".", - "file": "module.md", - "nodes": [ - [ - { - "atom": "page", - "file": "buffered.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "h1", - "file": "buffered.md", - "level": 1, - "nodes": [ - { - "text": "Buffered Channels", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "buffered.md", - "nodes": [ - { - "text": "By default channels are un-buffered. Someone trying to send a message down a channel will block until someone else is ready to receive the message. A buffered channel, however, is a channel that can hold ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "buffered.md", - "nodes": [ - { - "text": "N", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " messages before writing to the channel blocks.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-35", - "type": "listing" - }, - "file": "buffered.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "img", - "attributes": { - "src": "assets/buffered.png" - }, - "file": ".", - "type": "*hype.Image" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": ".", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.35:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Leaving a voicemail is an buffered operation.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 35, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "buffered.md", - "nodes": [ - { - "text": "Consider a phone call that results in a voicemail, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-35" - }, - "file": "buffered.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-35" - }, - "nodes": [ - { - "text": "Listing 1.35", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-35" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ". This is a buffered operation. The caller is not blocked waiting for the recipient to pick up the phone. The caller can leave a voicemail message and the recipient can retrieve the message later. The size of the buffer is dependent on the number of messages that can be held in memory.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "buffered.md", - "level": 2, - "nodes": [ - { - "text": "Basic Buffered Channel Example", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "buffered.md", - "nodes": [ - { - "text": "With slices we have seen that you can use the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "builtin#make", - "href": "https://pkg.go.dev/builtin#make", - "target": "_blank" - }, - "file": "buffered.md", - "nodes": [ - { - "atom": "code", - "file": "buffered.md", - "nodes": [ - { - "text": "make", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/builtin#make" - } - ], - { - "text": " function to create a slice of a particular length, ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "buffered.md", - "nodes": [ - { - "text": "make([]int, 10)", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " creates a slice of 10 integers.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "buffered.md", - "nodes": [ - { - "text": "To create a buffered channel we use the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "buffered.md", - "nodes": [ - { - "text": "make", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function with a second argument, just like with slices. In ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-36" - }, - "file": "buffered.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-36" - }, - "nodes": [ - { - "text": "Listing 1.36", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-36" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", we are creating a buffered channel of strings, ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "buffered.md", - "nodes": [ - { - "text": "make(chan string, 2)", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-36", - "type": "listing" - }, - "file": "buffered.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": ".", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "src/buffered/basic/main.go#main" - }, - "lang": "go", - "nodes": [ - { - "content": "func main() {\n\n\t// adding a second argument to the make function creates a buffered channel\n\tmessages := make(chan string, 2)\n\n\t// the program is no longer blocked on writing to a channel,\n\t// as it has capacity to write 2 messages to the channel\n\t// before blocking.\n\tmessages \u003c- \"hello!\"\n\tmessages \u003c- \"hello again!\"\n\n\t// reads are no longer blocked as there is already something to read from\n\tfmt.Println(\u003c-messages)\n\tfmt.Println(\u003c-messages)\n}", - "file": "src/buffered/basic/main.go", - "lang": "go", - "name": "main", - "start": 5, - "end": 22, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "atom": "hr", - "file": ".", - "type": "*hype.Element" - }, - [ - { - "args": [ - "go", - "run", - "." - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go run .", - "run": ".", - "src": "src/buffered/basic" - }, - "expected_exit": 0, - "file": ".", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\nhello!\nhello again!", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/11-channels/src/buffered/basic", - "stdout": "aGVsbG8hCmhlbGxvIGFnYWluIQ==", - "duration": 411119583, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\nhello!\nhello again!", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/11-channels/src/buffered/basic", - "stdout": "aGVsbG8hCmhlbGxvIGFnYWluIQ==", - "duration": 411119583, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": ".", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.36:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "A buffered channel example.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 36, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "buffered.md", - "nodes": [ - { - "text": "If we were to try and write a third message into the channel, to ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-36" - }, - "file": "buffered.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-36" - }, - "nodes": [ - { - "text": "Listing 1.36", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-36" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", before it has had a chance to be read, the program would block. In this case, because it is impossible for someone to read the message, the application crash with a deadlock, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-37" - }, - "file": "buffered.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-37" - }, - "nodes": [ - { - "text": "Listing 1.37", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-37" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-37", - "type": "listing" - }, - "file": "buffered.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": ".", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "src/buffered/blocked/main.go#main" - }, - "lang": "go", - "nodes": [ - { - "content": "func main() {\n\n\t// adding a second argument to the make function creates a buffered channel\n\tmessages := make(chan string, 2)\n\n\t// the program is no longer blocked on writing to a channel,\n\t// as it has capacity to write 2 messages to the channel\n\t// before blocking.\n\tmessages \u003c- \"hello!\"\n\tmessages \u003c- \"hello again!\"\n\n\t// this line will block until someone is ready to read from the channel\n\t// this application will deadlock and crash here.\n\tmessages \u003c- \"hello once more\"\n\n\t// reads are no longer blocked as there is already something to read from\n\tfmt.Println(\u003c-messages)\n\tfmt.Println(\u003c-messages)\n}", - "file": "src/buffered/blocked/main.go", - "lang": "go", - "name": "main", - "start": 5, - "end": 26, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "atom": "hr", - "file": ".", - "type": "*hype.Element" - }, - [ - { - "args": [ - "go", - "run", - "." - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go run .", - "exit": "-1", - "run": ".", - "src": "src/buffered/blocked" - }, - "expected_exit": -1, - "file": ".", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\nfatal error: all goroutines are asleep - deadlock!\n\ngoroutine 1 [chan send]:\nmain.main()\n\t./main.go:19 +0x58\nexit status 2", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/11-channels/src/buffered/blocked", - "err": { - "Stderr": null - }, - "exit": 1, - "stderr": "ZmF0YWwgZXJyb3I6IGFsbCBnb3JvdXRpbmVzIGFyZSBhc2xlZXAgLSBkZWFkbG9jayEKCmdvcm91dGluZSAxIFtjaGFuIHNlbmRdOgptYWluLm1haW4oKQoJL1VzZXJzL21hcmtiYXRlcy9MaWJyYXJ5L0Nsb3VkU3RvcmFnZS9Ecm9wYm94L2Rldi9ndWlkZXMvY29udGVudC9ib29rL2NoYXB0ZXJzLzExLWNoYW5uZWxzL3NyYy9idWZmZXJlZC9ibG9ja2VkL21haW4uZ286MTkgKzB4NTgKZXhpdCBzdGF0dXMgMg==", - "duration": 740779500, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\nfatal error: all goroutines are asleep - deadlock!\n\ngoroutine 1 [chan send]:\nmain.main()\n\t./main.go:19 +0x58\nexit status 2", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/11-channels/src/buffered/blocked", - "err": { - "Stderr": null - }, - "exit": 1, - "stderr": "ZmF0YWwgZXJyb3I6IGFsbCBnb3JvdXRpbmVzIGFyZSBhc2xlZXAgLSBkZWFkbG9jayEKCmdvcm91dGluZSAxIFtjaGFuIHNlbmRdOgptYWluLm1haW4oKQoJL1VzZXJzL21hcmtiYXRlcy9MaWJyYXJ5L0Nsb3VkU3RvcmFnZS9Ecm9wYm94L2Rldi9ndWlkZXMvY29udGVudC9ib29rL2NoYXB0ZXJzLzExLWNoYW5uZWxzL3NyYy9idWZmZXJlZC9ibG9ja2VkL21haW4uZ286MTkgKzB4NTgKZXhpdCBzdGF0dXMgMg==", - "duration": 740779500, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": ".", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.37:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "A deadlock caused by trying to write to a channel when no one can read from it.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 37, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h3", - "file": "buffered.md", - "level": 3, - "nodes": [ - { - "text": "Buffered Channel And Delivery", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "buffered.md", - "nodes": [ - { - "text": "Use buffered channels cautiously. They do not guarantee delivery of the message. It is your responsibility to ensure a channel is drained before exiting a routine.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "buffered.md", - "nodes": [ - { - "text": "Consider ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-38" - }, - "file": "buffered.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-38" - }, - "nodes": [ - { - "text": "Listing 1.38", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-38" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ". The goroutine is able to write two messages into the queue before blocking. The ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "buffered.md", - "nodes": [ - { - "text": "main", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function blocks and waits for the first message in the channel, and then exits. The second message is never read. In fact, the goroutine has had the opportunity to write one more message into the channel before the program exits.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-38", - "type": "listing" - }, - "file": "buffered.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": ".", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "src/buffered/failure/main.go#main" - }, - "lang": "go", - "nodes": [ - { - "content": "func main() {\n\n\t// make a buffered channel of type strings\n\t// with a buffer size of 2\n\tmessages := make(chan string, 2)\n\n\t// launch a goroutine to send messages\n\t// to the channel\n\tgo func() {\n\n\t\t// try to send 10 messages down the channel\n\t\tfor i := 0; i \u003c 10; i++ {\n\t\t\tmsg := fmt.Sprintf(\"message %d\", i+1)\n\n\t\t\t// send the message down the channel\n\t\t\t// if the channel is full, this will block\n\t\t\t// if not, the message will be buffered\n\t\t\t// in the channel\n\t\t\tmessages \u003c- msg\n\n\t\t\t// log the message was sent down the channel\n\t\t\tfmt.Printf(\"sent: %s\\n\", msg)\n\t\t}\n\n\t}()\n\n\t// listen for the first message in the channel\n\tm := \u003c-messages\n\n\t// log the message received\n\tfmt.Printf(\"received: %s\\n\", m)\n\n\t// exit the program\n}", - "file": "src/buffered/failure/main.go", - "lang": "go", - "name": "main", - "start": 7, - "end": 43, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "atom": "hr", - "file": ".", - "type": "*hype.Element" - }, - [ - { - "args": [ - "go", - "run", - "." - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go run .", - "run": ".", - "src": "src/buffered/failure" - }, - "expected_exit": 0, - "file": ".", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\nsent: message 1\nsent: message 2\nsent: message 3\nreceived: message 1", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/11-channels/src/buffered/failure", - "stdout": "c2VudDogbWVzc2FnZSAxCnNlbnQ6IG1lc3NhZ2UgMgpzZW50OiBtZXNzYWdlIDMKcmVjZWl2ZWQ6IG1lc3NhZ2UgMQ==", - "duration": 996917958, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\nsent: message 1\nsent: message 2\nsent: message 3\nreceived: message 1", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/11-channels/src/buffered/failure", - "stdout": "c2VudDogbWVzc2FnZSAxCnNlbnQ6IG1lc3NhZ2UgMgpzZW50OiBtZXNzYWdlIDMKcmVjZWl2ZWQ6IG1lc3NhZ2UgMQ==", - "duration": 996917958, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": ".", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.38:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "A failure to drain a buffered channel.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 38, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "buffered.md", - "level": 2, - "nodes": [ - { - "text": "Reading From Closed Buffered Channels", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "buffered.md", - "nodes": [ - { - "text": "If a buffered channel is closed, but still has messages in it, those messages can still be read from the channel until it is empty, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-39" - }, - "file": "buffered.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-39" - }, - "nodes": [ - { - "text": "Listing 1.39", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-39" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ". We can't, however, continue to write to the closed channel.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-39", - "type": "listing" - }, - "file": "buffered.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": ".", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "src/buffered/read-closed/main.go#main" - }, - "lang": "go", - "nodes": [ - { - "content": "func main() {\n\t// make a buffered channel of ints\n\t// that can hold 5 values before blocking\n\tch := make(chan int, 5)\n\n\t// write messages to the channel\n\tfor i := 0; i \u003c 5; i++ {\n\t\tch \u003c- i\n\t}\n\n\t// close the channel\n\tclose(ch)\n\n\t// we can continue to read messages\n\t// from the closed channel until it is empty.\n\t// when it is empty the for loop will exit.\n\tfor i := range ch {\n\t\tfmt.Println(i)\n\t}\n\n\t// trying to write to the closed channel\n\t// will cause a panic and the program will crash.\n\tch \u003c- 42\n}", - "file": "src/buffered/read-closed/main.go", - "lang": "go", - "name": "main", - "start": 7, - "end": 33, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "atom": "hr", - "file": ".", - "type": "*hype.Element" - }, - [ - { - "args": [ - "go", - "run", - "." - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go run .", - "exit": "-1", - "run": ".", - "src": "src/buffered/read-closed" - }, - "expected_exit": -1, - "file": ".", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\n0\n1\n2\n3\n4\n\npanic: send on closed channel\n\ngoroutine 1 [running]:\nmain.main()\n\t./main.go:30 +0xc4\nexit status 2", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/11-channels/src/buffered/read-closed", - "err": { - "Stderr": null - }, - "exit": 1, - "stderr": "cGFuaWM6IHNlbmQgb24gY2xvc2VkIGNoYW5uZWwKCmdvcm91dGluZSAxIFtydW5uaW5nXToKbWFpbi5tYWluKCkKCS9Vc2Vycy9tYXJrYmF0ZXMvTGlicmFyeS9DbG91ZFN0b3JhZ2UvRHJvcGJveC9kZXYvZ3VpZGVzL2NvbnRlbnQvYm9vay9jaGFwdGVycy8xMS1jaGFubmVscy9zcmMvYnVmZmVyZWQvcmVhZC1jbG9zZWQvbWFpbi5nbzozMCArMHhjNApleGl0IHN0YXR1cyAy", - "stdout": "MAoxCjIKMwo0", - "duration": 672902583, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\n0\n1\n2\n3\n4\n\npanic: send on closed channel\n\ngoroutine 1 [running]:\nmain.main()\n\t./main.go:30 +0xc4\nexit status 2", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/11-channels/src/buffered/read-closed", - "err": { - "Stderr": null - }, - "exit": 1, - "stderr": "cGFuaWM6IHNlbmQgb24gY2xvc2VkIGNoYW5uZWwKCmdvcm91dGluZSAxIFtydW5uaW5nXToKbWFpbi5tYWluKCkKCS9Vc2Vycy9tYXJrYmF0ZXMvTGlicmFyeS9DbG91ZFN0b3JhZ2UvRHJvcGJveC9kZXYvZ3VpZGVzL2NvbnRlbnQvYm9vay9jaGFwdGVycy8xMS1jaGFubmVscy9zcmMvYnVmZmVyZWQvcmVhZC1jbG9zZWQvbWFpbi5nbzozMCArMHhjNApleGl0IHN0YXR1cyAy", - "stdout": "MAoxCjIKMwo0", - "duration": 672902583, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": ".", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.39:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Reading from a closed buffered channel.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 39, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "title": "Buffered Channels", - "type": "*hype.Page" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "type": "*hype.Include" - } - ], - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "include", - "attributes": { - "src": "signals.md" - }, - "dir": ".", - "file": "module.md", - "nodes": [ - [ - { - "atom": "page", - "file": "signals.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "h1", - "file": "signals.md", - "level": 1, - "nodes": [ - { - "text": "Capturing System Signals with Channels", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "signals.md", - "nodes": [ - { - "text": "All programs should attempt a graceful shutdown. This means that, instead of crashing, or exiting an application, before resources are released, the application, should, instead, wait for the resources to be released. ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-40" - }, - "file": "signals.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-40" - }, - "nodes": [ - { - "text": "Listing 1.40", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-40" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": " covers the rules for graceful shutdown.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-40", - "type": "listing" - }, - "file": "signals.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "h3", - "file": ".", - "level": 3, - "nodes": [ - { - "text": "Rules for Graceful Shutdown", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "ul", - "file": ".", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "li", - "file": ".", - "list-type": "ul", - "nodes": [ - { - "text": "Detecting that the program was requested to shut down", - "type": "hype.Text" - } - ], - "type": "*hype.LI" - } - ], - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "li", - "file": ".", - "list-type": "ul", - "nodes": [ - { - "text": "Shut down all internal processes, including long running go routines", - "type": "hype.Text" - } - ], - "type": "*hype.LI" - } - ], - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "li", - "file": ".", - "list-type": "ul", - "nodes": [ - { - "text": "Have a reasonable timeout in the event that internal processes are taking to long to shut down or are deadlocked", - "type": "hype.Text" - } - ], - "type": "*hype.LI" - } - ], - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "li", - "file": ".", - "list-type": "ul", - "nodes": [ - { - "text": "Respond to an actual user request for immediate hard shutdown", - "type": "hype.Text" - } - ], - "type": "*hype.LI" - } - ], - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "li", - "file": ".", - "list-type": "ul", - "nodes": [ - { - "text": "Record the result of the shutdown (success, timeout, user intervention)", - "type": "hype.Text" - } - ], - "type": "*hype.LI" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "type": "*hype.UL" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": ".", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.40:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Rules for graceful shutdown.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 40, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "signals.md", - "level": 2, - "nodes": [ - { - "text": "The \"os/signals\" Package", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "signals.md", - "nodes": [ - { - "text": "Using channels, and the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "os/signal", - "href": "https://pkg.go.dev/os/signal", - "target": "_blank" - }, - "file": "signals.md", - "nodes": [ - { - "atom": "code", - "file": "signals.md", - "nodes": [ - { - "text": "os/signal", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/os/signal" - } - ], - { - "text": " package, you, can capture system signals and respond accordingly. The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "os/signal#Notify", - "href": "https://pkg.go.dev/os/signal#Notify", - "target": "_blank" - }, - "file": "signals.md", - "nodes": [ - { - "atom": "code", - "file": "signals.md", - "nodes": [ - { - "text": "signal.Notify", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/os/signal#Notify" - } - ], - { - "text": " function, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-41" - }, - "file": "signals.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-41" - }, - "nodes": [ - { - "text": "Listing 1.41", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-41" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", allows you to register a channel to receive notifications of ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "os#Signal", - "href": "https://pkg.go.dev/os#Signal", - "target": "_blank" - }, - "file": "signals.md", - "nodes": [ - { - "atom": "code", - "file": "signals.md", - "nodes": [ - { - "text": "os.Signal", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/os#Signal" - } - ], - { - "text": ", ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-42" - }, - "file": "signals.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-42" - }, - "nodes": [ - { - "text": "Listing 1.42", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-42" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-41", - "type": "listing" - }, - "file": "signals.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "doc", - "os/signal.Notify" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "doc": "os/signal.Notify", - "exec": "go doc os/signal.Notify" - }, - "expected_exit": 0, - "file": ".", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc os/signal.Notify\n\npackage signal // import \u0026#34;os/signal\u0026#34;\n\nfunc Notify(c chan\u0026lt;- os.Signal, sig ...os.Signal)\n Notify causes package signal to relay incoming signals to c. If no signals\n are provided, all incoming signals will be relayed to c. Otherwise, just the\n provided signals will.\n\n Package signal will not block sending to c: the caller must ensure that\n c has sufficient buffer space to keep up with the expected signal rate.\n For a channel used for notification of just one signal value, a buffer of\n size 1 is sufficient.\n\n It is allowed to call Notify multiple times with the same channel: each call\n expands the set of signals sent to that channel. The only way to remove\n signals from the set is to call Stop.\n\n It is allowed to call Notify multiple times with different channels\n and the same signals: each channel receives copies of incoming signals\n independently.", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "os/signal.Notify" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBzaWduYWwgLy8gaW1wb3J0ICJvcy9zaWduYWwiCgpmdW5jIE5vdGlmeShjIGNoYW48LSBvcy5TaWduYWwsIHNpZyAuLi5vcy5TaWduYWwpCiAgICBOb3RpZnkgY2F1c2VzIHBhY2thZ2Ugc2lnbmFsIHRvIHJlbGF5IGluY29taW5nIHNpZ25hbHMgdG8gYy4gSWYgbm8gc2lnbmFscwogICAgYXJlIHByb3ZpZGVkLCBhbGwgaW5jb21pbmcgc2lnbmFscyB3aWxsIGJlIHJlbGF5ZWQgdG8gYy4gT3RoZXJ3aXNlLCBqdXN0IHRoZQogICAgcHJvdmlkZWQgc2lnbmFscyB3aWxsLgoKICAgIFBhY2thZ2Ugc2lnbmFsIHdpbGwgbm90IGJsb2NrIHNlbmRpbmcgdG8gYzogdGhlIGNhbGxlciBtdXN0IGVuc3VyZSB0aGF0CiAgICBjIGhhcyBzdWZmaWNpZW50IGJ1ZmZlciBzcGFjZSB0byBrZWVwIHVwIHdpdGggdGhlIGV4cGVjdGVkIHNpZ25hbCByYXRlLgogICAgRm9yIGEgY2hhbm5lbCB1c2VkIGZvciBub3RpZmljYXRpb24gb2YganVzdCBvbmUgc2lnbmFsIHZhbHVlLCBhIGJ1ZmZlciBvZgogICAgc2l6ZSAxIGlzIHN1ZmZpY2llbnQuCgogICAgSXQgaXMgYWxsb3dlZCB0byBjYWxsIE5vdGlmeSBtdWx0aXBsZSB0aW1lcyB3aXRoIHRoZSBzYW1lIGNoYW5uZWw6IGVhY2ggY2FsbAogICAgZXhwYW5kcyB0aGUgc2V0IG9mIHNpZ25hbHMgc2VudCB0byB0aGF0IGNoYW5uZWwuIFRoZSBvbmx5IHdheSB0byByZW1vdmUKICAgIHNpZ25hbHMgZnJvbSB0aGUgc2V0IGlzIHRvIGNhbGwgU3RvcC4KCiAgICBJdCBpcyBhbGxvd2VkIHRvIGNhbGwgTm90aWZ5IG11bHRpcGxlIHRpbWVzIHdpdGggZGlmZmVyZW50IGNoYW5uZWxzCiAgICBhbmQgdGhlIHNhbWUgc2lnbmFsczogZWFjaCBjaGFubmVsIHJlY2VpdmVzIGNvcGllcyBvZiBpbmNvbWluZyBzaWduYWxzCiAgICBpbmRlcGVuZGVudGx5Lg==", - "duration": 303499875, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc os/signal.Notify\n\npackage signal // import \u0026#34;os/signal\u0026#34;\n\nfunc Notify(c chan\u0026lt;- os.Signal, sig ...os.Signal)\n Notify causes package signal to relay incoming signals to c. If no signals\n are provided, all incoming signals will be relayed to c. Otherwise, just the\n provided signals will.\n\n Package signal will not block sending to c: the caller must ensure that\n c has sufficient buffer space to keep up with the expected signal rate.\n For a channel used for notification of just one signal value, a buffer of\n size 1 is sufficient.\n\n It is allowed to call Notify multiple times with the same channel: each call\n expands the set of signals sent to that channel. The only way to remove\n signals from the set is to call Stop.\n\n It is allowed to call Notify multiple times with different channels\n and the same signals: each channel receives copies of incoming signals\n independently.", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "os/signal.Notify" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBzaWduYWwgLy8gaW1wb3J0ICJvcy9zaWduYWwiCgpmdW5jIE5vdGlmeShjIGNoYW48LSBvcy5TaWduYWwsIHNpZyAuLi5vcy5TaWduYWwpCiAgICBOb3RpZnkgY2F1c2VzIHBhY2thZ2Ugc2lnbmFsIHRvIHJlbGF5IGluY29taW5nIHNpZ25hbHMgdG8gYy4gSWYgbm8gc2lnbmFscwogICAgYXJlIHByb3ZpZGVkLCBhbGwgaW5jb21pbmcgc2lnbmFscyB3aWxsIGJlIHJlbGF5ZWQgdG8gYy4gT3RoZXJ3aXNlLCBqdXN0IHRoZQogICAgcHJvdmlkZWQgc2lnbmFscyB3aWxsLgoKICAgIFBhY2thZ2Ugc2lnbmFsIHdpbGwgbm90IGJsb2NrIHNlbmRpbmcgdG8gYzogdGhlIGNhbGxlciBtdXN0IGVuc3VyZSB0aGF0CiAgICBjIGhhcyBzdWZmaWNpZW50IGJ1ZmZlciBzcGFjZSB0byBrZWVwIHVwIHdpdGggdGhlIGV4cGVjdGVkIHNpZ25hbCByYXRlLgogICAgRm9yIGEgY2hhbm5lbCB1c2VkIGZvciBub3RpZmljYXRpb24gb2YganVzdCBvbmUgc2lnbmFsIHZhbHVlLCBhIGJ1ZmZlciBvZgogICAgc2l6ZSAxIGlzIHN1ZmZpY2llbnQuCgogICAgSXQgaXMgYWxsb3dlZCB0byBjYWxsIE5vdGlmeSBtdWx0aXBsZSB0aW1lcyB3aXRoIHRoZSBzYW1lIGNoYW5uZWw6IGVhY2ggY2FsbAogICAgZXhwYW5kcyB0aGUgc2V0IG9mIHNpZ25hbHMgc2VudCB0byB0aGF0IGNoYW5uZWwuIFRoZSBvbmx5IHdheSB0byByZW1vdmUKICAgIHNpZ25hbHMgZnJvbSB0aGUgc2V0IGlzIHRvIGNhbGwgU3RvcC4KCiAgICBJdCBpcyBhbGxvd2VkIHRvIGNhbGwgTm90aWZ5IG11bHRpcGxlIHRpbWVzIHdpdGggZGlmZmVyZW50IGNoYW5uZWxzCiAgICBhbmQgdGhlIHNhbWUgc2lnbmFsczogZWFjaCBjaGFubmVsIHJlY2VpdmVzIGNvcGllcyBvZiBpbmNvbWluZyBzaWduYWxzCiAgICBpbmRlcGVuZGVudGx5Lg==", - "duration": 303499875, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": ".", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.41:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "os/signal#Notify", - "href": "https://pkg.go.dev/os/signal#Notify", - "target": "_blank" - }, - "file": ".", - "nodes": [ - [ - { - "atom": "code", - "file": ".", - "nodes": [ - { - "text": "signal.Notify", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/os/signal#Notify" - } - ], - { - "text": " function.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 41, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-42", - "type": "listing" - }, - "file": "signals.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "doc", - "os.Signal" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "doc": "os.Signal", - "exec": "go doc os.Signal" - }, - "expected_exit": 0, - "file": ".", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc os.Signal\n\npackage os // import \u0026#34;os\u0026#34;\n\ntype Signal interface {\n\tString() string\n\tSignal() // to distinguish from other Stringers\n}\n A Signal represents an operating system signal. The usual underlying\n implementation is operating system-dependent: on Unix it is syscall.Signal.\n\nvar Interrupt Signal = syscall.SIGINT ...", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "os.Signal" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBvcyAvLyBpbXBvcnQgIm9zIgoKdHlwZSBTaWduYWwgaW50ZXJmYWNlIHsKCVN0cmluZygpIHN0cmluZwoJU2lnbmFsKCkgLy8gdG8gZGlzdGluZ3Vpc2ggZnJvbSBvdGhlciBTdHJpbmdlcnMKfQogICAgQSBTaWduYWwgcmVwcmVzZW50cyBhbiBvcGVyYXRpbmcgc3lzdGVtIHNpZ25hbC4gVGhlIHVzdWFsIHVuZGVybHlpbmcKICAgIGltcGxlbWVudGF0aW9uIGlzIG9wZXJhdGluZyBzeXN0ZW0tZGVwZW5kZW50OiBvbiBVbml4IGl0IGlzIHN5c2NhbGwuU2lnbmFsLgoKdmFyIEludGVycnVwdCBTaWduYWwgPSBzeXNjYWxsLlNJR0lOVCAuLi4=", - "duration": 263467500, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc os.Signal\n\npackage os // import \u0026#34;os\u0026#34;\n\ntype Signal interface {\n\tString() string\n\tSignal() // to distinguish from other Stringers\n}\n A Signal represents an operating system signal. The usual underlying\n implementation is operating system-dependent: on Unix it is syscall.Signal.\n\nvar Interrupt Signal = syscall.SIGINT ...", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "os.Signal" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBvcyAvLyBpbXBvcnQgIm9zIgoKdHlwZSBTaWduYWwgaW50ZXJmYWNlIHsKCVN0cmluZygpIHN0cmluZwoJU2lnbmFsKCkgLy8gdG8gZGlzdGluZ3Vpc2ggZnJvbSBvdGhlciBTdHJpbmdlcnMKfQogICAgQSBTaWduYWwgcmVwcmVzZW50cyBhbiBvcGVyYXRpbmcgc3lzdGVtIHNpZ25hbC4gVGhlIHVzdWFsIHVuZGVybHlpbmcKICAgIGltcGxlbWVudGF0aW9uIGlzIG9wZXJhdGluZyBzeXN0ZW0tZGVwZW5kZW50OiBvbiBVbml4IGl0IGlzIHN5c2NhbGwuU2lnbmFsLgoKdmFyIEludGVycnVwdCBTaWduYWwgPSBzeXNjYWxsLlNJR0lOVCAuLi4=", - "duration": 263467500, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": ".", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.42:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "os#Signal", - "href": "https://pkg.go.dev/os#Signal", - "target": "_blank" - }, - "file": ".", - "nodes": [ - [ - { - "atom": "code", - "file": ".", - "nodes": [ - { - "text": "os.Signal", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/os#Signal" - } - ], - { - "text": " type.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 42, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "signals.md", - "nodes": [ - { - "text": "In ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-43" - }, - "file": "signals.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-43" - }, - "nodes": [ - { - "text": "Listing 1.43", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-43" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", we register a channel, ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "signals.md", - "nodes": [ - { - "text": "ch", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ", to listen for ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "os#Interrupt", - "href": "https://pkg.go.dev/os#Interrupt", - "target": "_blank" - }, - "file": "signals.md", - "nodes": [ - { - "atom": "code", - "file": "signals.md", - "nodes": [ - { - "text": "os.Interrupt", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/os#Interrupt" - } - ], - { - "text": " with ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "signal#Notify", - "href": "https://pkg.go.dev/signal#Notify", - "target": "_blank" - }, - "file": "signals.md", - "nodes": [ - { - "atom": "code", - "file": "signals.md", - "nodes": [ - { - "text": "signal.Notify", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/signal#Notify" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-43", - "type": "listing" - }, - "file": "signals.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": ".", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "src/signals/signal/main.go#main" - }, - "lang": "go", - "nodes": [ - { - "content": "func main() {\n\n\t// set up channel on which to send signal notifications.\n\t// we must use a buffered channel or risk missing the signal\n\t// if we're not ready to receive when the signal is sent.\n\tch := make(chan os.Signal, 1)\n\n\t// wire up the channel to an `os.Signal`\n\t// this tells the signal package to send\n\t// the specified signals to our channel\n\t// this is not a blocking operation\n\tsignal.Notify(ch, os.Interrupt)\n\n\tfmt.Println(\"awaiting signal...\")\n\n\t// block until a signal is received.\n\ts := \u003c-ch\n\n\tfmt.Println(\"Got signal:\", s)\n\n\t// perform final shutdown operations\n\t// then exit the program\n}", - "file": "src/signals/signal/main.go", - "lang": "go", - "name": "main", - "start": 9, - "end": 34, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": ".", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.43:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Listening for ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "os#Interrupt", - "href": "https://pkg.go.dev/os#Interrupt", - "target": "_blank" - }, - "file": ".", - "nodes": [ - [ - { - "atom": "code", - "file": ".", - "nodes": [ - { - "text": "os.Interrupt", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/os#Interrupt" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 43, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "signals.md", - "level": 2, - "nodes": [ - { - "text": "Implementing Graceful Shutdown", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "signals.md", - "nodes": [ - { - "text": "Consider ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-44" - }, - "file": "signals.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-44" - }, - "nodes": [ - { - "text": "Listing 1.44", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-44" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ". It creates a new ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "signals.md", - "nodes": [ - { - "text": "Monitor", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " and starts the monitor in a goroutine giving it a ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "signals.md", - "nodes": [ - { - "text": "quit", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " channel to listen for shutdown. The application runs for a bit and then closes the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "signals.md", - "nodes": [ - { - "text": "quit", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " channel.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-44", - "type": "listing" - }, - "file": "signals.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": ".", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "src/signals/shutdown/start/main.go#main" - }, - "lang": "go", - "nodes": [ - { - "content": "func main() {\n\t// create a new quit channel\n\tquit := make(chan struct{})\n\n\t// create a new monitor\n\tmon := Monitor{}\n\n\t// launch the monitor in a goroutine\n\tgo mon.Start(quit)\n\n\t// sleep for a while to let the monitor run\n\ttime.Sleep(50 * time.Millisecond)\n\n\t// close the quit channel to stop the monitor\n\t// and exit the program\n\tclose(quit)\n}", - "file": "src/signals/shutdown/start/main.go", - "lang": "go", - "name": "main", - "start": 36, - "end": 55, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": ".", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.44:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "An application without graceful shutdown.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 44, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "signals.md", - "nodes": [ - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "signals.md", - "nodes": [ - { - "text": "Monitor", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ", ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-45" - }, - "file": "signals.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-45" - }, - "nodes": [ - { - "text": "Listing 1.45", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-45" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": " listens to both the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "signals.md", - "nodes": [ - { - "text": "quit", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " channel and a ticker channel that will send the time down the channel at the set interval. If a tick is received a message is printed and the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "signals.md", - "nodes": [ - { - "text": "for", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " loop and ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "signals.md", - "nodes": [ - { - "text": "select", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " statement go back to listens to the two channels. If the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "signals.md", - "nodes": [ - { - "text": "quit", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " channel is closed the function will return.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-45", - "type": "listing" - }, - "file": "signals.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": ".", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "src/signals/shutdown/start/main.go#monitor" - }, - "lang": "go", - "nodes": [ - { - "content": "type Monitor struct{}\n\nfunc (m Monitor) Start(quit chan struct{}) {\n\n\t// create a new ticker channel to listen to\n\ttick := time.NewTicker(10 * time.Millisecond)\n\tdefer tick.Stop()\n\n\t// use an infinite loop to continue to listen\n\t// to new messages after the select statement\n\t// has been executed\n\tfor {\n\n\t\tselect {\n\t\tcase \u003c-quit: // shut down if the quit channel is closed\n\t\t\tfmt.Println(\"shutting down monitor\")\n\t\t\treturn\n\t\tcase \u003c-tick.C: // listen to the ticker channel\n\t\t\tfmt.Println(\"monitor check\")\n\t\t}\n\n\t}\n\n}", - "file": "src/signals/shutdown/start/main.go", - "lang": "go", - "name": "monitor", - "start": 8, - "end": 34, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": ".", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.45:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Listening to multiple channels with a select statement.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 45, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "signals.md", - "nodes": [ - { - "text": "If we were to interrupt this program, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-46" - }, - "file": "signals.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-46" - }, - "nodes": [ - { - "text": "Listing 1.46", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-46" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": " we would see that the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "signals.md", - "nodes": [ - { - "text": "Monitor", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " was never shutdown properly.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-46", - "type": "listing" - }, - "file": "signals.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": ".", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "src/signals/shutdown/start/main.go#output" - }, - "lang": "go", - "nodes": [ - { - "content": "monitor check\nmonitor check\nmonitor check\nmonitor check\nmonitor check\nmonitor check\n^Csignal: interrupt", - "file": "src/signals/shutdown/start/main.go", - "lang": "go", - "name": "output", - "start": 58, - "end": 66, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": ".", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.46:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Output from interrupting ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-44" - }, - "file": ".", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-44" - }, - "nodes": [ - { - "text": "Listing 1.44", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-44" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 46, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "signals.md", - "level": 2, - "nodes": [ - { - "text": "Listening for System Signals", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "signals.md", - "nodes": [ - { - "text": "The first step in implementing graceful shutdown is to listen for system signals. We can update the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "signals.md", - "nodes": [ - { - "text": "main", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function to listen for the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "signals.md", - "nodes": [ - { - "text": "Interrupt", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " signal on a new channel, ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "signals.md", - "nodes": [ - { - "text": "sig", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ". Finally, instead of the application sleeping for a while we can listen for the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "signals.md", - "nodes": [ - { - "text": "Interrupt", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " signal on the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "signals.md", - "nodes": [ - { - "text": "sig", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " channel and respond accordingly.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-47", - "type": "listing" - }, - "file": "signals.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": ".", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "src/signals/shutdown/signal/main.go#main" - }, - "lang": "go", - "nodes": [ - { - "content": "func main() {\n\n\t// create a new channel to listen to\n\t// system signals\n\tsig := make(chan os.Signal, 1)\n\n\t// register the channel to be notified\n\t// on os.Interrupt signals\n\tsignal.Notify(sig, os.Interrupt)\n\n\t// create a new quit channel\n\tquit := make(chan struct{})\n\n\t// create a new monitor\n\tmon := Monitor{}\n\n\t// launch the monitor in a goroutine\n\tgo mon.Start(quit)\n\n\t// block until the os.Interrupt signal is\n\t// is received (ctrl-c)\n\t\u003c-sig\n\n\t// close the quit channel to stop the monitor\n\t// and exit the program\n\tclose(quit)\n}", - "file": "src/signals/shutdown/signal/main.go", - "lang": "go", - "name": "main", - "start": 41, - "end": 70, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": ".", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.47:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Listening for ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "os#Interrupt", - "href": "https://pkg.go.dev/os#Interrupt", - "target": "_blank" - }, - "file": ".", - "nodes": [ - [ - { - "atom": "code", - "file": ".", - "nodes": [ - { - "text": "os.Interrupt", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/os#Interrupt" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 47, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "signals.md", - "nodes": [ - { - "text": "From the output in ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-48" - }, - "file": "signals.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-48" - }, - "nodes": [ - { - "text": "Listing 1.48", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-48" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", we can see that the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "signals.md", - "nodes": [ - { - "text": "Monitor", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " was still not properly shutdown.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-48", - "type": "listing" - }, - "file": "signals.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": ".", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "src/signals/shutdown/signal/main.go#output" - }, - "lang": "go", - "nodes": [ - { - "content": "monitor check\nmonitor check\nmonitor check\nmonitor check\n^Cmonitor check", - "file": "src/signals/shutdown/signal/main.go", - "lang": "go", - "name": "output", - "start": 73, - "end": 79, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": ".", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.48:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Output from interrupting ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-47" - }, - "file": ".", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-47" - }, - "nodes": [ - { - "text": "Listing 1.47", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-47" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 48, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "signals.md", - "nodes": [ - { - "text": "The reason that the monitor was not shutdown properly is because we didn't give the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "signals.md", - "nodes": [ - { - "text": "Monitor", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " goroutine enough time to shut down gracefully.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "signals.md", - "level": 2, - "nodes": [ - { - "text": "Listening for Shutdown Confirmation", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "signals.md", - "nodes": [ - { - "text": "In order to ensure that the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "signals.md", - "nodes": [ - { - "text": "Monitor", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " was shutdown properly, it has to provide the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "signals.md", - "nodes": [ - { - "text": "main", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function with a way of receiving confirmation that the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "signals.md", - "nodes": [ - { - "text": "Monitor", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " was shutdown.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "signals.md", - "nodes": [ - { - "text": "Let's update the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "signals.md", - "nodes": [ - { - "text": "Monitor", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " to have an internal ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "signals.md", - "nodes": [ - { - "text": "done chan struct{}", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " channel, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-49" - }, - "file": "signals.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-49" - }, - "nodes": [ - { - "text": "Listing 1.49", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-49" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ". The ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "signals.md", - "nodes": [ - { - "text": "Monitor", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " also exposes a ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "signals.md", - "nodes": [ - { - "text": "Done", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " method that returns a read-only channel that will be closed when the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "signals.md", - "nodes": [ - { - "text": "Monitor", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " has properly shutdown.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-49", - "type": "listing" - }, - "file": "signals.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": ".", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "src/signals/shutdown/fixed/main.go#monitor" - }, - "lang": "go", - "nodes": [ - { - "content": "type Monitor struct {\n\tdone chan struct{}\n}\n\nfunc (m Monitor) Done() \u003c-chan struct{} {\n\treturn m.done\n}", - "file": "src/signals/shutdown/fixed/main.go", - "lang": "go", - "name": "monitor", - "start": 10, - "end": 19, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": ".", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.49:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": ".", - "nodes": [ - { - "text": "Monitor", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " with the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": ".", - "nodes": [ - { - "text": "done", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " channel.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 49, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "signals.md", - "nodes": [ - { - "text": "In the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "signals.md", - "nodes": [ - { - "text": "main", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-50" - }, - "file": "signals.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-50" - }, - "nodes": [ - { - "text": "Listing 1.50", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-50" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": " after we close the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "signals.md", - "nodes": [ - { - "text": "quit", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " channel, ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "signals.md", - "nodes": [ - { - "text": "close(quit)", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ", we can block and wait for the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "signals.md", - "nodes": [ - { - "text": "\u0026lt;-mon.Done()", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " channel to be closed. This will happen when the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "signals.md", - "nodes": [ - { - "text": "Monitor", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " has properly shutdown.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-50", - "type": "listing" - }, - "file": "signals.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": ".", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "src/signals/shutdown/fixed/main.go#main" - }, - "lang": "go", - "nodes": [ - { - "content": "func main() {\n\n\t// create a new channel to listen to\n\t// system signals\n\tsig := make(chan os.Signal, 1)\n\n\t// register the channel to be notified\n\t// on os.Interrupt signals\n\tsignal.Notify(sig, os.Interrupt)\n\n\t// create a new quit channel\n\tquit := make(chan struct{})\n\n\t// create a new monitor\n\tmon := Monitor{\n\t\tdone: make(chan struct{}),\n\t}\n\n\t// launch the monitor in a goroutine\n\tgo mon.Start(quit)\n\n\t// block until the os.Interrupt signal is\n\t// is received (ctrl-c)\n\t\u003c-sig\n\n\t// close the quit channel to stop the monitor\n\t// and exit the program\n\tclose(quit)\n\n\t// wait for the monitor to shut down\n\t\u003c-mon.Done()\n\n}", - "file": "src/signals/shutdown/fixed/main.go", - "lang": "go", - "name": "main", - "start": 52, - "end": 87, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": ".", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.50:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Listening for shutdown confirmation.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 50, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "signals.md", - "nodes": [ - { - "text": "Now, when we look at the output, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-51" - }, - "file": "signals.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-51" - }, - "nodes": [ - { - "text": "Listing 1.51", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-51" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": " we can see that the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "signals.md", - "nodes": [ - { - "text": "Monitor", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " was shutdown properly and the application shutdown gracefully.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-51", - "type": "listing" - }, - "file": "signals.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": ".", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "src/signals/shutdown/fixed/main.go#output" - }, - "lang": "go", - "nodes": [ - { - "content": "monitor check\nmonitor check\nmonitor check\nmonitor check\n^Cshutting down monitor", - "file": "src/signals/shutdown/fixed/main.go", - "lang": "go", - "name": "output", - "start": 90, - "end": 96, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": ".", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.51:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Output from interrupting ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-50" - }, - "file": ".", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-50" - }, - "nodes": [ - { - "text": "Listing 1.50", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-50" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 51, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "signals.md", - "level": 2, - "nodes": [ - { - "text": "Timing Out a Non-Responsive Shutdown", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "signals.md", - "nodes": [ - { - "text": "Occasionally, the resources you are waiting on to shutdown properly fail to respond and cause the application to hang indefinitely. The user is then required to manually force the application to stop.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "signals.md", - "nodes": [ - { - "text": "In order to prevent this from happening, we can use a timeout.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "signals.md", - "nodes": [ - { - "text": "In ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-52" - }, - "file": "signals.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-52" - }, - "nodes": [ - { - "text": "Listing 1.52", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-52" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", we update the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "signals.md", - "nodes": [ - { - "text": "main", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function to no longer wait for the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "signals.md", - "nodes": [ - { - "text": "\u0026lt;-mon.Done()", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " channel to be closed before exiting. Now, the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "signals.md", - "nodes": [ - { - "text": "main", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " uses a ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "signals.md", - "nodes": [ - { - "text": "select", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " statement to listen for the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "signals.md", - "nodes": [ - { - "text": "\u0026lt;-mon.Done()", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " channel and a ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "signals.md", - "nodes": [ - { - "text": "\u0026lt;-time.After(timeout)", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " channel. If the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "signals.md", - "nodes": [ - { - "text": "\u0026lt;-mon.Done()", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " channel is closed before the timeout, the application will gracefully shutdown.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-52", - "type": "listing" - }, - "file": "signals.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": ".", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "src/signals/shutdown/timeout/main.go#main" - }, - "lang": "go", - "nodes": [ - { - "content": "func main() {\n\n\t// create a new channel to listen to\n\t// system signals\n\tsig := make(chan os.Signal, 1)\n\n\t// register the channel to be notified\n\t// on os.Interrupt signals\n\tsignal.Notify(sig, os.Interrupt)\n\n\t// create a new quit channel\n\tquit := make(chan struct{})\n\n\t// create a new monitor\n\tmon := Monitor{\n\t\tdone: make(chan struct{}),\n\t}\n\n\t// launch the monitor in a goroutine\n\tgo mon.Start(quit)\n\n\t// block until the os.Interrupt signal is\n\t// is received (ctrl-c)\n\t\u003c-sig\n\n\t// close the quit channel to stop the monitor\n\t// and exit the program\n\tclose(quit)\n\n\tselect {\n\tcase \u003c-mon.Done(): // wait for the monitor to shut down\n\t\t// success shutdown\n\t\tos.Exit(0)\n\tcase \u003c-time.After(500 * time.Millisecond): // timeout after 500ms\n\t\tfmt.Println(\"timed out while trying to shut down the monitor\")\n\n\t\t// non-successful shutdown\n\t\tos.Exit(1)\n\t}\n}", - "file": "src/signals/shutdown/timeout/main.go", - "lang": "go", - "name": "main", - "start": 55, - "end": 97, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": ".", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.52:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Listening for shutdown confirmation.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 52, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "signals.md", - "nodes": [ - { - "text": "As we can see from the output, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-53" - }, - "file": "signals.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-53" - }, - "nodes": [ - { - "text": "Listing 1.53", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-53" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": " if the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "signals.md", - "nodes": [ - { - "text": "Monitor", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " does not shutdown within the specified timeout period, the application will exit with an error.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-53", - "type": "listing" - }, - "file": "signals.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": ".", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "src/signals/shutdown/timeout/main.go#output" - }, - "lang": "go", - "nodes": [ - { - "content": "monitor check\nmonitor check\nmonitor check\nmonitor check\nmonitor check\n^Cshutting down monitor\ntimed out while trying to shut down the monitor\nexit status 1", - "file": "src/signals/shutdown/timeout/main.go", - "lang": "go", - "name": "output", - "start": 100, - "end": 109, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": ".", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.53:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Output from interrupting ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-52" - }, - "file": ".", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-52" - }, - "nodes": [ - { - "text": "Listing 1.52", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-52" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 53, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "title": "Capturing System Signals with Channels", - "type": "*hype.Page" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "type": "*hype.Include" - } - ], - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "page", - "file": "module.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "h1", - "file": "module.md", - "level": 1, - "nodes": [ - { - "text": "Summary", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "module.md", - "nodes": [ - { - "text": "In this ", - "type": "hype.Text" - }, - { - "atom": "binding", - "attributes": { - "part": "" - }, - "file": "module.md", - "type": "*hype.Element" - }, - { - "text": " we started to explore concurrency in Go with Channels. We learned the differences between parallelism and concurrency, and how to use goroutines and channels to achieve concurrency. We learned about channels and how they can be used to communicate between, and control, goroutines. We learned the differences between buffered and un-buffered channels, and when each one will block and unblock. Finally, we learned how we can use channels to listen for system signals so we can gracefully shutdown our applications.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "title": "Summary", - "type": "*hype.Page" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "type": "*hype.Body" - } - ] - ], - "type": "*hype.Element" - } - ], - "type": "*hype.Element" - } - ], - "parser": { - "type": "*hype.Parser", - "root": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/11-channels", - "section": 1, - "snippets": {} - }, - "root": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/11-channels", - "section_id": 1, - "snippets": {}, - "title": "Channels", - "type": "*hype.Document", - "filename": "module.md" -} \ No newline at end of file diff --git a/src/testdata/context.json b/src/testdata/context.json deleted file mode 100644 index a5cae88..0000000 --- a/src/testdata/context.json +++ /dev/null @@ -1,19898 +0,0 @@ -{ - "nodes": [ - { - "file": "module.md", - "nodes": [ - { - "atom": "html", - "file": "module.md", - "nodes": [ - { - "atom": "head", - "file": "module.md", - "type": "*hype.Element" - }, - [ - { - "atom": "body", - "file": "module.md", - "nodes": [ - [ - { - "atom": "page", - "file": "module.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "h1", - "file": "module.md", - "level": 1, - "nodes": [ - { - "text": "Context", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "module.md", - "nodes": [ - { - "text": "Introduced in Go 1.7, the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context", - "href": "https://pkg.go.dev/context", - "target": "_blank" - }, - "file": "module.md", - "nodes": [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context" - } - ], - { - "text": " package was introduced to provide a cleaner way, than the use of channels, of managing cancellation and timeouts across goroutines.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "module.md", - "nodes": [ - { - "text": "While the scope, and API footprint of the package is pretty small, it was a welcome addition to the language when introduced.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "module.md", - "nodes": [ - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context", - "href": "https://pkg.go.dev/context", - "target": "_blank" - }, - "file": "module.md", - "nodes": [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context" - } - ], - { - "text": " package, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-1" - }, - "file": "module.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-1" - }, - "nodes": [ - { - "text": "Listing 1.1", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-1" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", defines the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "module.md", - "nodes": [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": " type, which carries deadlines, cancellation signals, and other request-scoped values across API boundaries and between processes.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "module.md", - "nodes": [ - { - "text": "Context is, mostly, used for controlling concurrent subsystems in your application. This week we will cover the different kinds of behavior with contexts including canceling, timeouts, and values. We'll also see how we can clean up a lot of code involving channels by using contexts.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-1", - "type": "listing" - }, - "file": "module.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "doc", - "-short", - "context" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "doc": "-short context", - "exec": "go doc -short context" - }, - "expected_exit": 0, - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc -short context\n\nvar Canceled = errors.New(\u0026#34;context canceled\u0026#34;)\nvar DeadlineExceeded error = deadlineExceededError{}\nfunc AfterFunc(ctx Context, f func()) (stop func() bool)\nfunc Cause(c Context) error\nfunc WithCancel(parent Context) (ctx Context, cancel CancelFunc)\nfunc WithCancelCause(parent Context) (ctx Context, cancel CancelCauseFunc)\nfunc WithDeadline(parent Context, d time.Time) (Context, CancelFunc)\nfunc WithDeadlineCause(parent Context, d time.Time, cause error) (Context, CancelFunc)\nfunc WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc)\nfunc WithTimeoutCause(parent Context, timeout time.Duration, cause error) (Context, CancelFunc)\ntype CancelCauseFunc func(cause error)\ntype CancelFunc func()\ntype Context interface{ ... }\n func Background() Context\n func TODO() Context\n func WithValue(parent Context, key, val any) Context\n func WithoutCancel(parent Context) Context", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "-short", - "context" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "dmFyIENhbmNlbGVkID0gZXJyb3JzLk5ldygiY29udGV4dCBjYW5jZWxlZCIpCnZhciBEZWFkbGluZUV4Y2VlZGVkIGVycm9yID0gZGVhZGxpbmVFeGNlZWRlZEVycm9ye30KZnVuYyBBZnRlckZ1bmMoY3R4IENvbnRleHQsIGYgZnVuYygpKSAoc3RvcCBmdW5jKCkgYm9vbCkKZnVuYyBDYXVzZShjIENvbnRleHQpIGVycm9yCmZ1bmMgV2l0aENhbmNlbChwYXJlbnQgQ29udGV4dCkgKGN0eCBDb250ZXh0LCBjYW5jZWwgQ2FuY2VsRnVuYykKZnVuYyBXaXRoQ2FuY2VsQ2F1c2UocGFyZW50IENvbnRleHQpIChjdHggQ29udGV4dCwgY2FuY2VsIENhbmNlbENhdXNlRnVuYykKZnVuYyBXaXRoRGVhZGxpbmUocGFyZW50IENvbnRleHQsIGQgdGltZS5UaW1lKSAoQ29udGV4dCwgQ2FuY2VsRnVuYykKZnVuYyBXaXRoRGVhZGxpbmVDYXVzZShwYXJlbnQgQ29udGV4dCwgZCB0aW1lLlRpbWUsIGNhdXNlIGVycm9yKSAoQ29udGV4dCwgQ2FuY2VsRnVuYykKZnVuYyBXaXRoVGltZW91dChwYXJlbnQgQ29udGV4dCwgdGltZW91dCB0aW1lLkR1cmF0aW9uKSAoQ29udGV4dCwgQ2FuY2VsRnVuYykKZnVuYyBXaXRoVGltZW91dENhdXNlKHBhcmVudCBDb250ZXh0LCB0aW1lb3V0IHRpbWUuRHVyYXRpb24sIGNhdXNlIGVycm9yKSAoQ29udGV4dCwgQ2FuY2VsRnVuYykKdHlwZSBDYW5jZWxDYXVzZUZ1bmMgZnVuYyhjYXVzZSBlcnJvcikKdHlwZSBDYW5jZWxGdW5jIGZ1bmMoKQp0eXBlIENvbnRleHQgaW50ZXJmYWNleyAuLi4gfQogICAgZnVuYyBCYWNrZ3JvdW5kKCkgQ29udGV4dAogICAgZnVuYyBUT0RPKCkgQ29udGV4dAogICAgZnVuYyBXaXRoVmFsdWUocGFyZW50IENvbnRleHQsIGtleSwgdmFsIGFueSkgQ29udGV4dAogICAgZnVuYyBXaXRob3V0Q2FuY2VsKHBhcmVudCBDb250ZXh0KSBDb250ZXh0", - "duration": 84652792, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc -short context\n\nvar Canceled = errors.New(\u0026#34;context canceled\u0026#34;)\nvar DeadlineExceeded error = deadlineExceededError{}\nfunc AfterFunc(ctx Context, f func()) (stop func() bool)\nfunc Cause(c Context) error\nfunc WithCancel(parent Context) (ctx Context, cancel CancelFunc)\nfunc WithCancelCause(parent Context) (ctx Context, cancel CancelCauseFunc)\nfunc WithDeadline(parent Context, d time.Time) (Context, CancelFunc)\nfunc WithDeadlineCause(parent Context, d time.Time, cause error) (Context, CancelFunc)\nfunc WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc)\nfunc WithTimeoutCause(parent Context, timeout time.Duration, cause error) (Context, CancelFunc)\ntype CancelCauseFunc func(cause error)\ntype CancelFunc func()\ntype Context interface{ ... }\n func Background() Context\n func TODO() Context\n func WithValue(parent Context, key, val any) Context\n func WithoutCancel(parent Context) Context", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "-short", - "context" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "dmFyIENhbmNlbGVkID0gZXJyb3JzLk5ldygiY29udGV4dCBjYW5jZWxlZCIpCnZhciBEZWFkbGluZUV4Y2VlZGVkIGVycm9yID0gZGVhZGxpbmVFeGNlZWRlZEVycm9ye30KZnVuYyBBZnRlckZ1bmMoY3R4IENvbnRleHQsIGYgZnVuYygpKSAoc3RvcCBmdW5jKCkgYm9vbCkKZnVuYyBDYXVzZShjIENvbnRleHQpIGVycm9yCmZ1bmMgV2l0aENhbmNlbChwYXJlbnQgQ29udGV4dCkgKGN0eCBDb250ZXh0LCBjYW5jZWwgQ2FuY2VsRnVuYykKZnVuYyBXaXRoQ2FuY2VsQ2F1c2UocGFyZW50IENvbnRleHQpIChjdHggQ29udGV4dCwgY2FuY2VsIENhbmNlbENhdXNlRnVuYykKZnVuYyBXaXRoRGVhZGxpbmUocGFyZW50IENvbnRleHQsIGQgdGltZS5UaW1lKSAoQ29udGV4dCwgQ2FuY2VsRnVuYykKZnVuYyBXaXRoRGVhZGxpbmVDYXVzZShwYXJlbnQgQ29udGV4dCwgZCB0aW1lLlRpbWUsIGNhdXNlIGVycm9yKSAoQ29udGV4dCwgQ2FuY2VsRnVuYykKZnVuYyBXaXRoVGltZW91dChwYXJlbnQgQ29udGV4dCwgdGltZW91dCB0aW1lLkR1cmF0aW9uKSAoQ29udGV4dCwgQ2FuY2VsRnVuYykKZnVuYyBXaXRoVGltZW91dENhdXNlKHBhcmVudCBDb250ZXh0LCB0aW1lb3V0IHRpbWUuRHVyYXRpb24sIGNhdXNlIGVycm9yKSAoQ29udGV4dCwgQ2FuY2VsRnVuYykKdHlwZSBDYW5jZWxDYXVzZUZ1bmMgZnVuYyhjYXVzZSBlcnJvcikKdHlwZSBDYW5jZWxGdW5jIGZ1bmMoKQp0eXBlIENvbnRleHQgaW50ZXJmYWNleyAuLi4gfQogICAgZnVuYyBCYWNrZ3JvdW5kKCkgQ29udGV4dAogICAgZnVuYyBUT0RPKCkgQ29udGV4dAogICAgZnVuYyBXaXRoVmFsdWUocGFyZW50IENvbnRleHQsIGtleSwgdmFsIGFueSkgQ29udGV4dAogICAgZnVuYyBXaXRob3V0Q2FuY2VsKHBhcmVudCBDb250ZXh0KSBDb250ZXh0", - "duration": 84652792, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.1:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context", - "href": "https://pkg.go.dev/context", - "target": "_blank" - }, - "nodes": [ - [ - { - "atom": "code", - "nodes": [ - { - "text": "context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context" - } - ], - { - "text": " package.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 1, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "title": "Context", - "type": "*hype.Page" - } - ], - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "include", - "attributes": { - "src": "basics/basics.md" - }, - "dir": "basics", - "file": "module.md", - "nodes": [ - [ - { - "atom": "page", - "file": "basics.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "h1", - "file": "basics.md", - "level": 1, - "nodes": [ - { - "text": "The Context Interface", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "basics.md", - "nodes": [ - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "basics.md", - "nodes": [ - { - "atom": "code", - "file": "basics.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": " interface, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-2" - }, - "file": "basics.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-2" - }, - "nodes": [ - { - "text": "Listing 1.2", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-2" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", consists of four methods. These methods provide us the ability to listen for cancellation and timeout events, retrieve values from the context hierarchy, and finally, a way to check what ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "basics.md", - "nodes": [ - { - "text": "error", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ", if any, caused the context to be canceled.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-2", - "type": "listing" - }, - "file": "basics.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "basics", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-godoc", - "language": "godoc" - }, - "file": "basics", - "lang": "godoc", - "nodes": [ - { - "text": "type Context interface {\n Deadline() (deadline time.Time, ok bool)\n Done() \u0026lt;-chan struct{}\n Err() error\n Value(key interface{}) interface{}\n}\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "basics", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.2:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "basics", - "nodes": [ - [ - { - "atom": "code", - "file": "basics", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": " interface.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 2, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "basics.md", - "nodes": [ - { - "text": "We can see, in ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-2" - }, - "file": "basics.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-2" - }, - "nodes": [ - { - "text": "Listing 1.2", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-2" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", that the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "basics.md", - "nodes": [ - { - "atom": "code", - "file": "basics.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": " interface implements several of the channel patterns we have already seen, such as have a ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "basics.md", - "nodes": [ - { - "text": "Done", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " channel that can be listened to for cancellation.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "basics.md", - "nodes": [ - { - "text": "We will cover each of these methods in more detail later. For now, let's briefly look at each one of them.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "basics.md", - "level": 2, - "nodes": [ - { - "text": "Context#Deadline", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "basics.md", - "nodes": [ - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context.Deadline", - "href": "https://pkg.go.dev/context#Context.Deadline", - "target": "_blank" - }, - "file": "basics.md", - "nodes": [ - { - "atom": "code", - "file": "basics.md", - "nodes": [ - { - "text": "context.Context.Deadline", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context.Deadline" - } - ], - { - "text": " method, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-3" - }, - "file": "basics.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-3" - }, - "nodes": [ - { - "text": "Listing 1.3", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-3" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", can be used to check if a context has a cancellation deadline set, and if so, what that deadline is.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-3", - "type": "listing" - }, - "file": "basics.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "doc", - "context.Context.Deadline" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "doc": "context.Context.Deadline", - "exec": "go doc context.Context.Deadline" - }, - "expected_exit": 0, - "file": "basics", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc context.Context.Deadline\n\npackage context // import \u0026#34;context\u0026#34;\n\ntype Context interface {\n\t// Deadline returns the time when work done on behalf of this context\n\t// should be canceled. Deadline returns ok==false when no deadline is\n\t// set. Successive calls to Deadline return the same results.\n\tDeadline() (deadline time.Time, ok bool)\n}", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "context.Context.Deadline" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBjb250ZXh0IC8vIGltcG9ydCAiY29udGV4dCIKCnR5cGUgQ29udGV4dCBpbnRlcmZhY2UgewoJLy8gRGVhZGxpbmUgcmV0dXJucyB0aGUgdGltZSB3aGVuIHdvcmsgZG9uZSBvbiBiZWhhbGYgb2YgdGhpcyBjb250ZXh0CgkvLyBzaG91bGQgYmUgY2FuY2VsZWQuIERlYWRsaW5lIHJldHVybnMgb2s9PWZhbHNlIHdoZW4gbm8gZGVhZGxpbmUgaXMKCS8vIHNldC4gU3VjY2Vzc2l2ZSBjYWxscyB0byBEZWFkbGluZSByZXR1cm4gdGhlIHNhbWUgcmVzdWx0cy4KCURlYWRsaW5lKCkgKGRlYWRsaW5lIHRpbWUuVGltZSwgb2sgYm9vbCkKfQ==", - "duration": 67596250, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc context.Context.Deadline\n\npackage context // import \u0026#34;context\u0026#34;\n\ntype Context interface {\n\t// Deadline returns the time when work done on behalf of this context\n\t// should be canceled. Deadline returns ok==false when no deadline is\n\t// set. Successive calls to Deadline return the same results.\n\tDeadline() (deadline time.Time, ok bool)\n}", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "context.Context.Deadline" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBjb250ZXh0IC8vIGltcG9ydCAiY29udGV4dCIKCnR5cGUgQ29udGV4dCBpbnRlcmZhY2UgewoJLy8gRGVhZGxpbmUgcmV0dXJucyB0aGUgdGltZSB3aGVuIHdvcmsgZG9uZSBvbiBiZWhhbGYgb2YgdGhpcyBjb250ZXh0CgkvLyBzaG91bGQgYmUgY2FuY2VsZWQuIERlYWRsaW5lIHJldHVybnMgb2s9PWZhbHNlIHdoZW4gbm8gZGVhZGxpbmUgaXMKCS8vIHNldC4gU3VjY2Vzc2l2ZSBjYWxscyB0byBEZWFkbGluZSByZXR1cm4gdGhlIHNhbWUgcmVzdWx0cy4KCURlYWRsaW5lKCkgKGRlYWRsaW5lIHRpbWUuVGltZSwgb2sgYm9vbCkKfQ==", - "duration": 67596250, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "basics", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.3:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context.Deadline", - "href": "https://pkg.go.dev/context#Context.Deadline", - "target": "_blank" - }, - "file": "basics", - "nodes": [ - [ - { - "atom": "code", - "file": "basics", - "nodes": [ - { - "text": "context.Context.Deadline", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context.Deadline" - } - ], - { - "text": " method.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 3, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "basics.md", - "level": 2, - "nodes": [ - { - "text": "Context#Done", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "basics.md", - "nodes": [ - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context.Done", - "href": "https://pkg.go.dev/context#Context.Done", - "target": "_blank" - }, - "file": "basics.md", - "nodes": [ - { - "atom": "code", - "file": "basics.md", - "nodes": [ - { - "text": "context.Context.Done", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context.Done" - } - ], - { - "text": " method, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-4" - }, - "file": "basics.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-4" - }, - "nodes": [ - { - "text": "Listing 1.4", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-4" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", can be used to listen for cancellation events. This is similar to how we can listen for a channel being closed, but it is more flexible.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-4", - "type": "listing" - }, - "file": "basics.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "doc", - "context.Context.Done" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "doc": "context.Context.Done", - "exec": "go doc context.Context.Done" - }, - "expected_exit": 0, - "file": "basics", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc context.Context.Done\n\npackage context // import \u0026#34;context\u0026#34;\n\ntype Context interface {\n\n\t// Done returns a channel that\u0026#39;s closed when work done on behalf of this\n\t// context should be canceled. Done may return nil if this context can\n\t// never be canceled. Successive calls to Done return the same value.\n\t// The close of the Done channel may happen asynchronously,\n\t// after the cancel function returns.\n\t//\n\t// WithCancel arranges for Done to be closed when cancel is called;\n\t// WithDeadline arranges for Done to be closed when the deadline\n\t// expires; WithTimeout arranges for Done to be closed when the timeout\n\t// elapses.\n\t//\n\t// Done is provided for use in select statements:\n\t//\n\t// // Stream generates values with DoSomething and sends them to out\n\t// // until DoSomething returns an error or ctx.Done is closed.\n\t// func Stream(ctx context.Context, out chan\u0026lt;- Value) error {\n\t// \tfor {\n\t// \t\tv, err := DoSomething(ctx)\n\t// \t\tif err != nil {\n\t// \t\t\treturn err\n\t// \t\t}\n\t// \t\tselect {\n\t// \t\tcase \u0026lt;-ctx.Done():\n\t// \t\t\treturn ctx.Err()\n\t// \t\tcase out \u0026lt;- v:\n\t// \t\t}\n\t// \t}\n\t// }\n\t//\n\t// See https://blog.golang.org/pipelines for more examples of how to use\n\t// a Done channel for cancellation.\n\tDone() \u0026lt;-chan struct{}\n}", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "context.Context.Done" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBjb250ZXh0IC8vIGltcG9ydCAiY29udGV4dCIKCnR5cGUgQ29udGV4dCBpbnRlcmZhY2UgewoKCS8vIERvbmUgcmV0dXJucyBhIGNoYW5uZWwgdGhhdCdzIGNsb3NlZCB3aGVuIHdvcmsgZG9uZSBvbiBiZWhhbGYgb2YgdGhpcwoJLy8gY29udGV4dCBzaG91bGQgYmUgY2FuY2VsZWQuIERvbmUgbWF5IHJldHVybiBuaWwgaWYgdGhpcyBjb250ZXh0IGNhbgoJLy8gbmV2ZXIgYmUgY2FuY2VsZWQuIFN1Y2Nlc3NpdmUgY2FsbHMgdG8gRG9uZSByZXR1cm4gdGhlIHNhbWUgdmFsdWUuCgkvLyBUaGUgY2xvc2Ugb2YgdGhlIERvbmUgY2hhbm5lbCBtYXkgaGFwcGVuIGFzeW5jaHJvbm91c2x5LAoJLy8gYWZ0ZXIgdGhlIGNhbmNlbCBmdW5jdGlvbiByZXR1cm5zLgoJLy8KCS8vIFdpdGhDYW5jZWwgYXJyYW5nZXMgZm9yIERvbmUgdG8gYmUgY2xvc2VkIHdoZW4gY2FuY2VsIGlzIGNhbGxlZDsKCS8vIFdpdGhEZWFkbGluZSBhcnJhbmdlcyBmb3IgRG9uZSB0byBiZSBjbG9zZWQgd2hlbiB0aGUgZGVhZGxpbmUKCS8vIGV4cGlyZXM7IFdpdGhUaW1lb3V0IGFycmFuZ2VzIGZvciBEb25lIHRvIGJlIGNsb3NlZCB3aGVuIHRoZSB0aW1lb3V0CgkvLyBlbGFwc2VzLgoJLy8KCS8vIERvbmUgaXMgcHJvdmlkZWQgZm9yIHVzZSBpbiBzZWxlY3Qgc3RhdGVtZW50czoKCS8vCgkvLyAgLy8gU3RyZWFtIGdlbmVyYXRlcyB2YWx1ZXMgd2l0aCBEb1NvbWV0aGluZyBhbmQgc2VuZHMgdGhlbSB0byBvdXQKCS8vICAvLyB1bnRpbCBEb1NvbWV0aGluZyByZXR1cm5zIGFuIGVycm9yIG9yIGN0eC5Eb25lIGlzIGNsb3NlZC4KCS8vICBmdW5jIFN0cmVhbShjdHggY29udGV4dC5Db250ZXh0LCBvdXQgY2hhbjwtIFZhbHVlKSBlcnJvciB7CgkvLyAgCWZvciB7CgkvLyAgCQl2LCBlcnIgOj0gRG9Tb21ldGhpbmcoY3R4KQoJLy8gIAkJaWYgZXJyICE9IG5pbCB7CgkvLyAgCQkJcmV0dXJuIGVycgoJLy8gIAkJfQoJLy8gIAkJc2VsZWN0IHsKCS8vICAJCWNhc2UgPC1jdHguRG9uZSgpOgoJLy8gIAkJCXJldHVybiBjdHguRXJyKCkKCS8vICAJCWNhc2Ugb3V0IDwtIHY6CgkvLyAgCQl9CgkvLyAgCX0KCS8vICB9CgkvLwoJLy8gU2VlIGh0dHBzOi8vYmxvZy5nb2xhbmcub3JnL3BpcGVsaW5lcyBmb3IgbW9yZSBleGFtcGxlcyBvZiBob3cgdG8gdXNlCgkvLyBhIERvbmUgY2hhbm5lbCBmb3IgY2FuY2VsbGF0aW9uLgoJRG9uZSgpIDwtY2hhbiBzdHJ1Y3R7fQp9", - "duration": 376732041, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc context.Context.Done\n\npackage context // import \u0026#34;context\u0026#34;\n\ntype Context interface {\n\n\t// Done returns a channel that\u0026#39;s closed when work done on behalf of this\n\t// context should be canceled. Done may return nil if this context can\n\t// never be canceled. Successive calls to Done return the same value.\n\t// The close of the Done channel may happen asynchronously,\n\t// after the cancel function returns.\n\t//\n\t// WithCancel arranges for Done to be closed when cancel is called;\n\t// WithDeadline arranges for Done to be closed when the deadline\n\t// expires; WithTimeout arranges for Done to be closed when the timeout\n\t// elapses.\n\t//\n\t// Done is provided for use in select statements:\n\t//\n\t// // Stream generates values with DoSomething and sends them to out\n\t// // until DoSomething returns an error or ctx.Done is closed.\n\t// func Stream(ctx context.Context, out chan\u0026lt;- Value) error {\n\t// \tfor {\n\t// \t\tv, err := DoSomething(ctx)\n\t// \t\tif err != nil {\n\t// \t\t\treturn err\n\t// \t\t}\n\t// \t\tselect {\n\t// \t\tcase \u0026lt;-ctx.Done():\n\t// \t\t\treturn ctx.Err()\n\t// \t\tcase out \u0026lt;- v:\n\t// \t\t}\n\t// \t}\n\t// }\n\t//\n\t// See https://blog.golang.org/pipelines for more examples of how to use\n\t// a Done channel for cancellation.\n\tDone() \u0026lt;-chan struct{}\n}", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "context.Context.Done" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBjb250ZXh0IC8vIGltcG9ydCAiY29udGV4dCIKCnR5cGUgQ29udGV4dCBpbnRlcmZhY2UgewoKCS8vIERvbmUgcmV0dXJucyBhIGNoYW5uZWwgdGhhdCdzIGNsb3NlZCB3aGVuIHdvcmsgZG9uZSBvbiBiZWhhbGYgb2YgdGhpcwoJLy8gY29udGV4dCBzaG91bGQgYmUgY2FuY2VsZWQuIERvbmUgbWF5IHJldHVybiBuaWwgaWYgdGhpcyBjb250ZXh0IGNhbgoJLy8gbmV2ZXIgYmUgY2FuY2VsZWQuIFN1Y2Nlc3NpdmUgY2FsbHMgdG8gRG9uZSByZXR1cm4gdGhlIHNhbWUgdmFsdWUuCgkvLyBUaGUgY2xvc2Ugb2YgdGhlIERvbmUgY2hhbm5lbCBtYXkgaGFwcGVuIGFzeW5jaHJvbm91c2x5LAoJLy8gYWZ0ZXIgdGhlIGNhbmNlbCBmdW5jdGlvbiByZXR1cm5zLgoJLy8KCS8vIFdpdGhDYW5jZWwgYXJyYW5nZXMgZm9yIERvbmUgdG8gYmUgY2xvc2VkIHdoZW4gY2FuY2VsIGlzIGNhbGxlZDsKCS8vIFdpdGhEZWFkbGluZSBhcnJhbmdlcyBmb3IgRG9uZSB0byBiZSBjbG9zZWQgd2hlbiB0aGUgZGVhZGxpbmUKCS8vIGV4cGlyZXM7IFdpdGhUaW1lb3V0IGFycmFuZ2VzIGZvciBEb25lIHRvIGJlIGNsb3NlZCB3aGVuIHRoZSB0aW1lb3V0CgkvLyBlbGFwc2VzLgoJLy8KCS8vIERvbmUgaXMgcHJvdmlkZWQgZm9yIHVzZSBpbiBzZWxlY3Qgc3RhdGVtZW50czoKCS8vCgkvLyAgLy8gU3RyZWFtIGdlbmVyYXRlcyB2YWx1ZXMgd2l0aCBEb1NvbWV0aGluZyBhbmQgc2VuZHMgdGhlbSB0byBvdXQKCS8vICAvLyB1bnRpbCBEb1NvbWV0aGluZyByZXR1cm5zIGFuIGVycm9yIG9yIGN0eC5Eb25lIGlzIGNsb3NlZC4KCS8vICBmdW5jIFN0cmVhbShjdHggY29udGV4dC5Db250ZXh0LCBvdXQgY2hhbjwtIFZhbHVlKSBlcnJvciB7CgkvLyAgCWZvciB7CgkvLyAgCQl2LCBlcnIgOj0gRG9Tb21ldGhpbmcoY3R4KQoJLy8gIAkJaWYgZXJyICE9IG5pbCB7CgkvLyAgCQkJcmV0dXJuIGVycgoJLy8gIAkJfQoJLy8gIAkJc2VsZWN0IHsKCS8vICAJCWNhc2UgPC1jdHguRG9uZSgpOgoJLy8gIAkJCXJldHVybiBjdHguRXJyKCkKCS8vICAJCWNhc2Ugb3V0IDwtIHY6CgkvLyAgCQl9CgkvLyAgCX0KCS8vICB9CgkvLwoJLy8gU2VlIGh0dHBzOi8vYmxvZy5nb2xhbmcub3JnL3BpcGVsaW5lcyBmb3IgbW9yZSBleGFtcGxlcyBvZiBob3cgdG8gdXNlCgkvLyBhIERvbmUgY2hhbm5lbCBmb3IgY2FuY2VsbGF0aW9uLgoJRG9uZSgpIDwtY2hhbiBzdHJ1Y3R7fQp9", - "duration": 376732041, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "basics", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.4:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context.Done", - "href": "https://pkg.go.dev/context#Context.Done", - "target": "_blank" - }, - "file": "basics", - "nodes": [ - [ - { - "atom": "code", - "file": "basics", - "nodes": [ - { - "text": "context.Context.Done", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context.Done" - } - ], - { - "text": " method.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 4, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "basics.md", - "level": 2, - "nodes": [ - { - "text": "Context#Err", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "basics.md", - "nodes": [ - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context.Err", - "href": "https://pkg.go.dev/context#Context.Err", - "target": "_blank" - }, - "file": "basics.md", - "nodes": [ - { - "atom": "code", - "file": "basics.md", - "nodes": [ - { - "text": "context.Context.Err", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context.Err" - } - ], - { - "text": " method, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-5" - }, - "file": "basics.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-5" - }, - "nodes": [ - { - "text": "Listing 1.5", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-5" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", can be used to check if a context has been canceled.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-5", - "type": "listing" - }, - "file": "basics.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "doc", - "context.Context.Err" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "doc": "context.Context.Err", - "exec": "go doc context.Context.Err" - }, - "expected_exit": 0, - "file": "basics", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc context.Context.Err\n\npackage context // import \u0026#34;context\u0026#34;\n\ntype Context interface {\n\n\t// If Done is not yet closed, Err returns nil.\n\t// If Done is closed, Err returns a non-nil error explaining why:\n\t// Canceled if the context was canceled\n\t// or DeadlineExceeded if the context\u0026#39;s deadline passed.\n\t// After Err returns a non-nil error, successive calls to Err return the same error.\n\tErr() error\n}", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "context.Context.Err" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBjb250ZXh0IC8vIGltcG9ydCAiY29udGV4dCIKCnR5cGUgQ29udGV4dCBpbnRlcmZhY2UgewoKCS8vIElmIERvbmUgaXMgbm90IHlldCBjbG9zZWQsIEVyciByZXR1cm5zIG5pbC4KCS8vIElmIERvbmUgaXMgY2xvc2VkLCBFcnIgcmV0dXJucyBhIG5vbi1uaWwgZXJyb3IgZXhwbGFpbmluZyB3aHk6CgkvLyBDYW5jZWxlZCBpZiB0aGUgY29udGV4dCB3YXMgY2FuY2VsZWQKCS8vIG9yIERlYWRsaW5lRXhjZWVkZWQgaWYgdGhlIGNvbnRleHQncyBkZWFkbGluZSBwYXNzZWQuCgkvLyBBZnRlciBFcnIgcmV0dXJucyBhIG5vbi1uaWwgZXJyb3IsIHN1Y2Nlc3NpdmUgY2FsbHMgdG8gRXJyIHJldHVybiB0aGUgc2FtZSBlcnJvci4KCUVycigpIGVycm9yCn0=", - "duration": 181689334, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc context.Context.Err\n\npackage context // import \u0026#34;context\u0026#34;\n\ntype Context interface {\n\n\t// If Done is not yet closed, Err returns nil.\n\t// If Done is closed, Err returns a non-nil error explaining why:\n\t// Canceled if the context was canceled\n\t// or DeadlineExceeded if the context\u0026#39;s deadline passed.\n\t// After Err returns a non-nil error, successive calls to Err return the same error.\n\tErr() error\n}", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "context.Context.Err" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBjb250ZXh0IC8vIGltcG9ydCAiY29udGV4dCIKCnR5cGUgQ29udGV4dCBpbnRlcmZhY2UgewoKCS8vIElmIERvbmUgaXMgbm90IHlldCBjbG9zZWQsIEVyciByZXR1cm5zIG5pbC4KCS8vIElmIERvbmUgaXMgY2xvc2VkLCBFcnIgcmV0dXJucyBhIG5vbi1uaWwgZXJyb3IgZXhwbGFpbmluZyB3aHk6CgkvLyBDYW5jZWxlZCBpZiB0aGUgY29udGV4dCB3YXMgY2FuY2VsZWQKCS8vIG9yIERlYWRsaW5lRXhjZWVkZWQgaWYgdGhlIGNvbnRleHQncyBkZWFkbGluZSBwYXNzZWQuCgkvLyBBZnRlciBFcnIgcmV0dXJucyBhIG5vbi1uaWwgZXJyb3IsIHN1Y2Nlc3NpdmUgY2FsbHMgdG8gRXJyIHJldHVybiB0aGUgc2FtZSBlcnJvci4KCUVycigpIGVycm9yCn0=", - "duration": 181689334, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "basics", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.5:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context.Err", - "href": "https://pkg.go.dev/context#Context.Err", - "target": "_blank" - }, - "file": "basics", - "nodes": [ - [ - { - "atom": "code", - "file": "basics", - "nodes": [ - { - "text": "context.Context.Err", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context.Err" - } - ], - { - "text": " method.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 5, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "basics.md", - "level": 2, - "nodes": [ - { - "text": "Context#Value", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "basics.md", - "nodes": [ - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context.Value", - "href": "https://pkg.go.dev/context#Context.Value", - "target": "_blank" - }, - "file": "basics.md", - "nodes": [ - { - "atom": "code", - "file": "basics.md", - "nodes": [ - { - "text": "context.Context.Value", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context.Value" - } - ], - { - "text": " method, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-6" - }, - "file": "basics.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-6" - }, - "nodes": [ - { - "text": "Listing 1.6", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-6" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", can be used to retrieve values from the context hierarchy.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-6", - "type": "listing" - }, - "file": "basics.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "doc", - "context.Context.Value" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "doc": "context.Context.Value", - "exec": "go doc context.Context.Value" - }, - "expected_exit": 0, - "file": "basics", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc context.Context.Value\n\npackage context // import \u0026#34;context\u0026#34;\n\ntype Context interface {\n\n\t// Value returns the value associated with this context for key, or nil\n\t// if no value is associated with key. Successive calls to Value with\n\t// the same key returns the same result.\n\t//\n\t// Use context values only for request-scoped data that transits\n\t// processes and API boundaries, not for passing optional parameters to\n\t// functions.\n\t//\n\t// A key identifies a specific value in a Context. Functions that wish\n\t// to store values in Context typically allocate a key in a global\n\t// variable then use that key as the argument to context.WithValue and\n\t// Context.Value. A key can be any type that supports equality;\n\t// packages should define keys as an unexported type to avoid\n\t// collisions.\n\t//\n\t// Packages that define a Context key should provide type-safe accessors\n\t// for the values stored using that key:\n\t//\n\t// \t// Package user defines a User type that\u0026#39;s stored in Contexts.\n\t// \tpackage user\n\t//\n\t// \timport \u0026#34;context\u0026#34;\n\t//\n\t// \t// User is the type of value stored in the Contexts.\n\t// \ttype User struct {...}\n\t//\n\t// \t// key is an unexported type for keys defined in this package.\n\t// \t// This prevents collisions with keys defined in other packages.\n\t// \ttype key int\n\t//\n\t// \t// userKey is the key for user.User values in Contexts. It is\n\t// \t// unexported; clients use user.NewContext and user.FromContext\n\t// \t// instead of using this key directly.\n\t// \tvar userKey key\n\t//\n\t// \t// NewContext returns a new Context that carries value u.\n\t// \tfunc NewContext(ctx context.Context, u *User) context.Context {\n\t// \t\treturn context.WithValue(ctx, userKey, u)\n\t// \t}\n\t//\n\t// \t// FromContext returns the User value stored in ctx, if any.\n\t// \tfunc FromContext(ctx context.Context) (*User, bool) {\n\t// \t\tu, ok := ctx.Value(userKey).(*User)\n\t// \t\treturn u, ok\n\t// \t}\n\tValue(key any) any\n}", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "context.Context.Value" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBjb250ZXh0IC8vIGltcG9ydCAiY29udGV4dCIKCnR5cGUgQ29udGV4dCBpbnRlcmZhY2UgewoKCS8vIFZhbHVlIHJldHVybnMgdGhlIHZhbHVlIGFzc29jaWF0ZWQgd2l0aCB0aGlzIGNvbnRleHQgZm9yIGtleSwgb3IgbmlsCgkvLyBpZiBubyB2YWx1ZSBpcyBhc3NvY2lhdGVkIHdpdGgga2V5LiBTdWNjZXNzaXZlIGNhbGxzIHRvIFZhbHVlIHdpdGgKCS8vIHRoZSBzYW1lIGtleSByZXR1cm5zIHRoZSBzYW1lIHJlc3VsdC4KCS8vCgkvLyBVc2UgY29udGV4dCB2YWx1ZXMgb25seSBmb3IgcmVxdWVzdC1zY29wZWQgZGF0YSB0aGF0IHRyYW5zaXRzCgkvLyBwcm9jZXNzZXMgYW5kIEFQSSBib3VuZGFyaWVzLCBub3QgZm9yIHBhc3Npbmcgb3B0aW9uYWwgcGFyYW1ldGVycyB0bwoJLy8gZnVuY3Rpb25zLgoJLy8KCS8vIEEga2V5IGlkZW50aWZpZXMgYSBzcGVjaWZpYyB2YWx1ZSBpbiBhIENvbnRleHQuIEZ1bmN0aW9ucyB0aGF0IHdpc2gKCS8vIHRvIHN0b3JlIHZhbHVlcyBpbiBDb250ZXh0IHR5cGljYWxseSBhbGxvY2F0ZSBhIGtleSBpbiBhIGdsb2JhbAoJLy8gdmFyaWFibGUgdGhlbiB1c2UgdGhhdCBrZXkgYXMgdGhlIGFyZ3VtZW50IHRvIGNvbnRleHQuV2l0aFZhbHVlIGFuZAoJLy8gQ29udGV4dC5WYWx1ZS4gQSBrZXkgY2FuIGJlIGFueSB0eXBlIHRoYXQgc3VwcG9ydHMgZXF1YWxpdHk7CgkvLyBwYWNrYWdlcyBzaG91bGQgZGVmaW5lIGtleXMgYXMgYW4gdW5leHBvcnRlZCB0eXBlIHRvIGF2b2lkCgkvLyBjb2xsaXNpb25zLgoJLy8KCS8vIFBhY2thZ2VzIHRoYXQgZGVmaW5lIGEgQ29udGV4dCBrZXkgc2hvdWxkIHByb3ZpZGUgdHlwZS1zYWZlIGFjY2Vzc29ycwoJLy8gZm9yIHRoZSB2YWx1ZXMgc3RvcmVkIHVzaW5nIHRoYXQga2V5OgoJLy8KCS8vIAkvLyBQYWNrYWdlIHVzZXIgZGVmaW5lcyBhIFVzZXIgdHlwZSB0aGF0J3Mgc3RvcmVkIGluIENvbnRleHRzLgoJLy8gCXBhY2thZ2UgdXNlcgoJLy8KCS8vIAlpbXBvcnQgImNvbnRleHQiCgkvLwoJLy8gCS8vIFVzZXIgaXMgdGhlIHR5cGUgb2YgdmFsdWUgc3RvcmVkIGluIHRoZSBDb250ZXh0cy4KCS8vIAl0eXBlIFVzZXIgc3RydWN0IHsuLi59CgkvLwoJLy8gCS8vIGtleSBpcyBhbiB1bmV4cG9ydGVkIHR5cGUgZm9yIGtleXMgZGVmaW5lZCBpbiB0aGlzIHBhY2thZ2UuCgkvLyAJLy8gVGhpcyBwcmV2ZW50cyBjb2xsaXNpb25zIHdpdGgga2V5cyBkZWZpbmVkIGluIG90aGVyIHBhY2thZ2VzLgoJLy8gCXR5cGUga2V5IGludAoJLy8KCS8vIAkvLyB1c2VyS2V5IGlzIHRoZSBrZXkgZm9yIHVzZXIuVXNlciB2YWx1ZXMgaW4gQ29udGV4dHMuIEl0IGlzCgkvLyAJLy8gdW5leHBvcnRlZDsgY2xpZW50cyB1c2UgdXNlci5OZXdDb250ZXh0IGFuZCB1c2VyLkZyb21Db250ZXh0CgkvLyAJLy8gaW5zdGVhZCBvZiB1c2luZyB0aGlzIGtleSBkaXJlY3RseS4KCS8vIAl2YXIgdXNlcktleSBrZXkKCS8vCgkvLyAJLy8gTmV3Q29udGV4dCByZXR1cm5zIGEgbmV3IENvbnRleHQgdGhhdCBjYXJyaWVzIHZhbHVlIHUuCgkvLyAJZnVuYyBOZXdDb250ZXh0KGN0eCBjb250ZXh0LkNvbnRleHQsIHUgKlVzZXIpIGNvbnRleHQuQ29udGV4dCB7CgkvLyAJCXJldHVybiBjb250ZXh0LldpdGhWYWx1ZShjdHgsIHVzZXJLZXksIHUpCgkvLyAJfQoJLy8KCS8vIAkvLyBGcm9tQ29udGV4dCByZXR1cm5zIHRoZSBVc2VyIHZhbHVlIHN0b3JlZCBpbiBjdHgsIGlmIGFueS4KCS8vIAlmdW5jIEZyb21Db250ZXh0KGN0eCBjb250ZXh0LkNvbnRleHQpICgqVXNlciwgYm9vbCkgewoJLy8gCQl1LCBvayA6PSBjdHguVmFsdWUodXNlcktleSkuKCpVc2VyKQoJLy8gCQlyZXR1cm4gdSwgb2sKCS8vIAl9CglWYWx1ZShrZXkgYW55KSBhbnkKfQ==", - "duration": 82724917, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc context.Context.Value\n\npackage context // import \u0026#34;context\u0026#34;\n\ntype Context interface {\n\n\t// Value returns the value associated with this context for key, or nil\n\t// if no value is associated with key. Successive calls to Value with\n\t// the same key returns the same result.\n\t//\n\t// Use context values only for request-scoped data that transits\n\t// processes and API boundaries, not for passing optional parameters to\n\t// functions.\n\t//\n\t// A key identifies a specific value in a Context. Functions that wish\n\t// to store values in Context typically allocate a key in a global\n\t// variable then use that key as the argument to context.WithValue and\n\t// Context.Value. A key can be any type that supports equality;\n\t// packages should define keys as an unexported type to avoid\n\t// collisions.\n\t//\n\t// Packages that define a Context key should provide type-safe accessors\n\t// for the values stored using that key:\n\t//\n\t// \t// Package user defines a User type that\u0026#39;s stored in Contexts.\n\t// \tpackage user\n\t//\n\t// \timport \u0026#34;context\u0026#34;\n\t//\n\t// \t// User is the type of value stored in the Contexts.\n\t// \ttype User struct {...}\n\t//\n\t// \t// key is an unexported type for keys defined in this package.\n\t// \t// This prevents collisions with keys defined in other packages.\n\t// \ttype key int\n\t//\n\t// \t// userKey is the key for user.User values in Contexts. It is\n\t// \t// unexported; clients use user.NewContext and user.FromContext\n\t// \t// instead of using this key directly.\n\t// \tvar userKey key\n\t//\n\t// \t// NewContext returns a new Context that carries value u.\n\t// \tfunc NewContext(ctx context.Context, u *User) context.Context {\n\t// \t\treturn context.WithValue(ctx, userKey, u)\n\t// \t}\n\t//\n\t// \t// FromContext returns the User value stored in ctx, if any.\n\t// \tfunc FromContext(ctx context.Context) (*User, bool) {\n\t// \t\tu, ok := ctx.Value(userKey).(*User)\n\t// \t\treturn u, ok\n\t// \t}\n\tValue(key any) any\n}", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "context.Context.Value" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBjb250ZXh0IC8vIGltcG9ydCAiY29udGV4dCIKCnR5cGUgQ29udGV4dCBpbnRlcmZhY2UgewoKCS8vIFZhbHVlIHJldHVybnMgdGhlIHZhbHVlIGFzc29jaWF0ZWQgd2l0aCB0aGlzIGNvbnRleHQgZm9yIGtleSwgb3IgbmlsCgkvLyBpZiBubyB2YWx1ZSBpcyBhc3NvY2lhdGVkIHdpdGgga2V5LiBTdWNjZXNzaXZlIGNhbGxzIHRvIFZhbHVlIHdpdGgKCS8vIHRoZSBzYW1lIGtleSByZXR1cm5zIHRoZSBzYW1lIHJlc3VsdC4KCS8vCgkvLyBVc2UgY29udGV4dCB2YWx1ZXMgb25seSBmb3IgcmVxdWVzdC1zY29wZWQgZGF0YSB0aGF0IHRyYW5zaXRzCgkvLyBwcm9jZXNzZXMgYW5kIEFQSSBib3VuZGFyaWVzLCBub3QgZm9yIHBhc3Npbmcgb3B0aW9uYWwgcGFyYW1ldGVycyB0bwoJLy8gZnVuY3Rpb25zLgoJLy8KCS8vIEEga2V5IGlkZW50aWZpZXMgYSBzcGVjaWZpYyB2YWx1ZSBpbiBhIENvbnRleHQuIEZ1bmN0aW9ucyB0aGF0IHdpc2gKCS8vIHRvIHN0b3JlIHZhbHVlcyBpbiBDb250ZXh0IHR5cGljYWxseSBhbGxvY2F0ZSBhIGtleSBpbiBhIGdsb2JhbAoJLy8gdmFyaWFibGUgdGhlbiB1c2UgdGhhdCBrZXkgYXMgdGhlIGFyZ3VtZW50IHRvIGNvbnRleHQuV2l0aFZhbHVlIGFuZAoJLy8gQ29udGV4dC5WYWx1ZS4gQSBrZXkgY2FuIGJlIGFueSB0eXBlIHRoYXQgc3VwcG9ydHMgZXF1YWxpdHk7CgkvLyBwYWNrYWdlcyBzaG91bGQgZGVmaW5lIGtleXMgYXMgYW4gdW5leHBvcnRlZCB0eXBlIHRvIGF2b2lkCgkvLyBjb2xsaXNpb25zLgoJLy8KCS8vIFBhY2thZ2VzIHRoYXQgZGVmaW5lIGEgQ29udGV4dCBrZXkgc2hvdWxkIHByb3ZpZGUgdHlwZS1zYWZlIGFjY2Vzc29ycwoJLy8gZm9yIHRoZSB2YWx1ZXMgc3RvcmVkIHVzaW5nIHRoYXQga2V5OgoJLy8KCS8vIAkvLyBQYWNrYWdlIHVzZXIgZGVmaW5lcyBhIFVzZXIgdHlwZSB0aGF0J3Mgc3RvcmVkIGluIENvbnRleHRzLgoJLy8gCXBhY2thZ2UgdXNlcgoJLy8KCS8vIAlpbXBvcnQgImNvbnRleHQiCgkvLwoJLy8gCS8vIFVzZXIgaXMgdGhlIHR5cGUgb2YgdmFsdWUgc3RvcmVkIGluIHRoZSBDb250ZXh0cy4KCS8vIAl0eXBlIFVzZXIgc3RydWN0IHsuLi59CgkvLwoJLy8gCS8vIGtleSBpcyBhbiB1bmV4cG9ydGVkIHR5cGUgZm9yIGtleXMgZGVmaW5lZCBpbiB0aGlzIHBhY2thZ2UuCgkvLyAJLy8gVGhpcyBwcmV2ZW50cyBjb2xsaXNpb25zIHdpdGgga2V5cyBkZWZpbmVkIGluIG90aGVyIHBhY2thZ2VzLgoJLy8gCXR5cGUga2V5IGludAoJLy8KCS8vIAkvLyB1c2VyS2V5IGlzIHRoZSBrZXkgZm9yIHVzZXIuVXNlciB2YWx1ZXMgaW4gQ29udGV4dHMuIEl0IGlzCgkvLyAJLy8gdW5leHBvcnRlZDsgY2xpZW50cyB1c2UgdXNlci5OZXdDb250ZXh0IGFuZCB1c2VyLkZyb21Db250ZXh0CgkvLyAJLy8gaW5zdGVhZCBvZiB1c2luZyB0aGlzIGtleSBkaXJlY3RseS4KCS8vIAl2YXIgdXNlcktleSBrZXkKCS8vCgkvLyAJLy8gTmV3Q29udGV4dCByZXR1cm5zIGEgbmV3IENvbnRleHQgdGhhdCBjYXJyaWVzIHZhbHVlIHUuCgkvLyAJZnVuYyBOZXdDb250ZXh0KGN0eCBjb250ZXh0LkNvbnRleHQsIHUgKlVzZXIpIGNvbnRleHQuQ29udGV4dCB7CgkvLyAJCXJldHVybiBjb250ZXh0LldpdGhWYWx1ZShjdHgsIHVzZXJLZXksIHUpCgkvLyAJfQoJLy8KCS8vIAkvLyBGcm9tQ29udGV4dCByZXR1cm5zIHRoZSBVc2VyIHZhbHVlIHN0b3JlZCBpbiBjdHgsIGlmIGFueS4KCS8vIAlmdW5jIEZyb21Db250ZXh0KGN0eCBjb250ZXh0LkNvbnRleHQpICgqVXNlciwgYm9vbCkgewoJLy8gCQl1LCBvayA6PSBjdHguVmFsdWUodXNlcktleSkuKCpVc2VyKQoJLy8gCQlyZXR1cm4gdSwgb2sKCS8vIAl9CglWYWx1ZShrZXkgYW55KSBhbnkKfQ==", - "duration": 82724917, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "basics", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.6:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context.Value", - "href": "https://pkg.go.dev/context#Context.Value", - "target": "_blank" - }, - "file": "basics", - "nodes": [ - [ - { - "atom": "code", - "file": "basics", - "nodes": [ - { - "text": "context.Context.Value", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context.Value" - } - ], - { - "text": " method.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 6, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "basics.md", - "level": 2, - "nodes": [ - { - "text": "Helper Functions", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "basics.md", - "nodes": [ - { - "text": "As we will see the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context", - "href": "https://pkg.go.dev/context", - "target": "_blank" - }, - "file": "basics.md", - "nodes": [ - { - "atom": "code", - "file": "basics.md", - "nodes": [ - { - "text": "context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context" - } - ], - { - "text": " package provides a number of useful helper functions for wrapping a ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "basics.md", - "nodes": [ - { - "atom": "code", - "file": "basics.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": " making the need for custom implementations of the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "basics.md", - "nodes": [ - { - "atom": "code", - "file": "basics.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": " interface less common.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-7", - "type": "listing" - }, - "file": "basics.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "doc", - "-short", - "context" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "doc": "-short context", - "exec": "go doc -short context" - }, - "expected_exit": 0, - "file": "basics", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc -short context\n\nvar Canceled = errors.New(\u0026#34;context canceled\u0026#34;)\nvar DeadlineExceeded error = deadlineExceededError{}\nfunc AfterFunc(ctx Context, f func()) (stop func() bool)\nfunc Cause(c Context) error\nfunc WithCancel(parent Context) (ctx Context, cancel CancelFunc)\nfunc WithCancelCause(parent Context) (ctx Context, cancel CancelCauseFunc)\nfunc WithDeadline(parent Context, d time.Time) (Context, CancelFunc)\nfunc WithDeadlineCause(parent Context, d time.Time, cause error) (Context, CancelFunc)\nfunc WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc)\nfunc WithTimeoutCause(parent Context, timeout time.Duration, cause error) (Context, CancelFunc)\ntype CancelCauseFunc func(cause error)\ntype CancelFunc func()\ntype Context interface{ ... }\n func Background() Context\n func TODO() Context\n func WithValue(parent Context, key, val any) Context\n func WithoutCancel(parent Context) Context", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "-short", - "context" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "dmFyIENhbmNlbGVkID0gZXJyb3JzLk5ldygiY29udGV4dCBjYW5jZWxlZCIpCnZhciBEZWFkbGluZUV4Y2VlZGVkIGVycm9yID0gZGVhZGxpbmVFeGNlZWRlZEVycm9ye30KZnVuYyBBZnRlckZ1bmMoY3R4IENvbnRleHQsIGYgZnVuYygpKSAoc3RvcCBmdW5jKCkgYm9vbCkKZnVuYyBDYXVzZShjIENvbnRleHQpIGVycm9yCmZ1bmMgV2l0aENhbmNlbChwYXJlbnQgQ29udGV4dCkgKGN0eCBDb250ZXh0LCBjYW5jZWwgQ2FuY2VsRnVuYykKZnVuYyBXaXRoQ2FuY2VsQ2F1c2UocGFyZW50IENvbnRleHQpIChjdHggQ29udGV4dCwgY2FuY2VsIENhbmNlbENhdXNlRnVuYykKZnVuYyBXaXRoRGVhZGxpbmUocGFyZW50IENvbnRleHQsIGQgdGltZS5UaW1lKSAoQ29udGV4dCwgQ2FuY2VsRnVuYykKZnVuYyBXaXRoRGVhZGxpbmVDYXVzZShwYXJlbnQgQ29udGV4dCwgZCB0aW1lLlRpbWUsIGNhdXNlIGVycm9yKSAoQ29udGV4dCwgQ2FuY2VsRnVuYykKZnVuYyBXaXRoVGltZW91dChwYXJlbnQgQ29udGV4dCwgdGltZW91dCB0aW1lLkR1cmF0aW9uKSAoQ29udGV4dCwgQ2FuY2VsRnVuYykKZnVuYyBXaXRoVGltZW91dENhdXNlKHBhcmVudCBDb250ZXh0LCB0aW1lb3V0IHRpbWUuRHVyYXRpb24sIGNhdXNlIGVycm9yKSAoQ29udGV4dCwgQ2FuY2VsRnVuYykKdHlwZSBDYW5jZWxDYXVzZUZ1bmMgZnVuYyhjYXVzZSBlcnJvcikKdHlwZSBDYW5jZWxGdW5jIGZ1bmMoKQp0eXBlIENvbnRleHQgaW50ZXJmYWNleyAuLi4gfQogICAgZnVuYyBCYWNrZ3JvdW5kKCkgQ29udGV4dAogICAgZnVuYyBUT0RPKCkgQ29udGV4dAogICAgZnVuYyBXaXRoVmFsdWUocGFyZW50IENvbnRleHQsIGtleSwgdmFsIGFueSkgQ29udGV4dAogICAgZnVuYyBXaXRob3V0Q2FuY2VsKHBhcmVudCBDb250ZXh0KSBDb250ZXh0", - "duration": 302744333, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc -short context\n\nvar Canceled = errors.New(\u0026#34;context canceled\u0026#34;)\nvar DeadlineExceeded error = deadlineExceededError{}\nfunc AfterFunc(ctx Context, f func()) (stop func() bool)\nfunc Cause(c Context) error\nfunc WithCancel(parent Context) (ctx Context, cancel CancelFunc)\nfunc WithCancelCause(parent Context) (ctx Context, cancel CancelCauseFunc)\nfunc WithDeadline(parent Context, d time.Time) (Context, CancelFunc)\nfunc WithDeadlineCause(parent Context, d time.Time, cause error) (Context, CancelFunc)\nfunc WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc)\nfunc WithTimeoutCause(parent Context, timeout time.Duration, cause error) (Context, CancelFunc)\ntype CancelCauseFunc func(cause error)\ntype CancelFunc func()\ntype Context interface{ ... }\n func Background() Context\n func TODO() Context\n func WithValue(parent Context, key, val any) Context\n func WithoutCancel(parent Context) Context", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "-short", - "context" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "dmFyIENhbmNlbGVkID0gZXJyb3JzLk5ldygiY29udGV4dCBjYW5jZWxlZCIpCnZhciBEZWFkbGluZUV4Y2VlZGVkIGVycm9yID0gZGVhZGxpbmVFeGNlZWRlZEVycm9ye30KZnVuYyBBZnRlckZ1bmMoY3R4IENvbnRleHQsIGYgZnVuYygpKSAoc3RvcCBmdW5jKCkgYm9vbCkKZnVuYyBDYXVzZShjIENvbnRleHQpIGVycm9yCmZ1bmMgV2l0aENhbmNlbChwYXJlbnQgQ29udGV4dCkgKGN0eCBDb250ZXh0LCBjYW5jZWwgQ2FuY2VsRnVuYykKZnVuYyBXaXRoQ2FuY2VsQ2F1c2UocGFyZW50IENvbnRleHQpIChjdHggQ29udGV4dCwgY2FuY2VsIENhbmNlbENhdXNlRnVuYykKZnVuYyBXaXRoRGVhZGxpbmUocGFyZW50IENvbnRleHQsIGQgdGltZS5UaW1lKSAoQ29udGV4dCwgQ2FuY2VsRnVuYykKZnVuYyBXaXRoRGVhZGxpbmVDYXVzZShwYXJlbnQgQ29udGV4dCwgZCB0aW1lLlRpbWUsIGNhdXNlIGVycm9yKSAoQ29udGV4dCwgQ2FuY2VsRnVuYykKZnVuYyBXaXRoVGltZW91dChwYXJlbnQgQ29udGV4dCwgdGltZW91dCB0aW1lLkR1cmF0aW9uKSAoQ29udGV4dCwgQ2FuY2VsRnVuYykKZnVuYyBXaXRoVGltZW91dENhdXNlKHBhcmVudCBDb250ZXh0LCB0aW1lb3V0IHRpbWUuRHVyYXRpb24sIGNhdXNlIGVycm9yKSAoQ29udGV4dCwgQ2FuY2VsRnVuYykKdHlwZSBDYW5jZWxDYXVzZUZ1bmMgZnVuYyhjYXVzZSBlcnJvcikKdHlwZSBDYW5jZWxGdW5jIGZ1bmMoKQp0eXBlIENvbnRleHQgaW50ZXJmYWNleyAuLi4gfQogICAgZnVuYyBCYWNrZ3JvdW5kKCkgQ29udGV4dAogICAgZnVuYyBUT0RPKCkgQ29udGV4dAogICAgZnVuYyBXaXRoVmFsdWUocGFyZW50IENvbnRleHQsIGtleSwgdmFsIGFueSkgQ29udGV4dAogICAgZnVuYyBXaXRob3V0Q2FuY2VsKHBhcmVudCBDb250ZXh0KSBDb250ZXh0", - "duration": 302744333, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "basics", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.7:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context", - "href": "https://pkg.go.dev/context", - "target": "_blank" - }, - "file": "basics", - "nodes": [ - [ - { - "atom": "code", - "file": "basics", - "nodes": [ - { - "text": "context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context" - } - ], - { - "text": " package.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 7, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "basics.md", - "level": 2, - "nodes": [ - { - "text": "The Background Context", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "basics.md", - "nodes": [ - { - "text": "While often we might be given a ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "basics.md", - "nodes": [ - { - "atom": "code", - "file": "basics.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": ", we might also be the one start a ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "basics.md", - "nodes": [ - { - "atom": "code", - "file": "basics.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": ". The most common way to provide a quick and easy way to start a ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "basics.md", - "nodes": [ - { - "atom": "code", - "file": "basics.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": " is to use the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Background", - "href": "https://pkg.go.dev/context#Background", - "target": "_blank" - }, - "file": "basics.md", - "nodes": [ - { - "atom": "code", - "file": "basics.md", - "nodes": [ - { - "text": "context.Background", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Background" - } - ], - { - "text": " function, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-8" - }, - "file": "basics.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-8" - }, - "nodes": [ - { - "text": "Listing 1.8", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-8" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-8", - "type": "listing" - }, - "file": "basics.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "doc", - "context.Background" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "doc": "context.Background", - "exec": "go doc context.Background" - }, - "expected_exit": 0, - "file": "basics", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc context.Background\n\npackage context // import \u0026#34;context\u0026#34;\n\nfunc Background() Context\n Background returns a non-nil, empty Context. It is never canceled, has no\n values, and has no deadline. It is typically used by the main function,\n initialization, and tests, and as the top-level Context for incoming\n requests.", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "context.Background" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBjb250ZXh0IC8vIGltcG9ydCAiY29udGV4dCIKCmZ1bmMgQmFja2dyb3VuZCgpIENvbnRleHQKICAgIEJhY2tncm91bmQgcmV0dXJucyBhIG5vbi1uaWwsIGVtcHR5IENvbnRleHQuIEl0IGlzIG5ldmVyIGNhbmNlbGVkLCBoYXMgbm8KICAgIHZhbHVlcywgYW5kIGhhcyBubyBkZWFkbGluZS4gSXQgaXMgdHlwaWNhbGx5IHVzZWQgYnkgdGhlIG1haW4gZnVuY3Rpb24sCiAgICBpbml0aWFsaXphdGlvbiwgYW5kIHRlc3RzLCBhbmQgYXMgdGhlIHRvcC1sZXZlbCBDb250ZXh0IGZvciBpbmNvbWluZwogICAgcmVxdWVzdHMu", - "duration": 135511333, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc context.Background\n\npackage context // import \u0026#34;context\u0026#34;\n\nfunc Background() Context\n Background returns a non-nil, empty Context. It is never canceled, has no\n values, and has no deadline. It is typically used by the main function,\n initialization, and tests, and as the top-level Context for incoming\n requests.", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "context.Background" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBjb250ZXh0IC8vIGltcG9ydCAiY29udGV4dCIKCmZ1bmMgQmFja2dyb3VuZCgpIENvbnRleHQKICAgIEJhY2tncm91bmQgcmV0dXJucyBhIG5vbi1uaWwsIGVtcHR5IENvbnRleHQuIEl0IGlzIG5ldmVyIGNhbmNlbGVkLCBoYXMgbm8KICAgIHZhbHVlcywgYW5kIGhhcyBubyBkZWFkbGluZS4gSXQgaXMgdHlwaWNhbGx5IHVzZWQgYnkgdGhlIG1haW4gZnVuY3Rpb24sCiAgICBpbml0aWFsaXphdGlvbiwgYW5kIHRlc3RzLCBhbmQgYXMgdGhlIHRvcC1sZXZlbCBDb250ZXh0IGZvciBpbmNvbWluZwogICAgcmVxdWVzdHMu", - "duration": 135511333, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "basics", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.8:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Background", - "href": "https://pkg.go.dev/context#Background", - "target": "_blank" - }, - "file": "basics", - "nodes": [ - [ - { - "atom": "code", - "file": "basics", - "nodes": [ - { - "text": "context.Background", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Background" - } - ], - { - "text": " function.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 8, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "basics.md", - "nodes": [ - { - "text": "In, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-9" - }, - "file": "basics.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-9" - }, - "nodes": [ - { - "text": "Listing 1.9", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-9" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", we print the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "basics.md", - "nodes": [ - { - "atom": "code", - "file": "basics.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": " returned by ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Background", - "href": "https://pkg.go.dev/context#Background", - "target": "_blank" - }, - "file": "basics.md", - "nodes": [ - { - "atom": "code", - "file": "basics.md", - "nodes": [ - { - "text": "context.Background", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Background" - } - ], - { - "text": ". As we can see from the output, the context is empty.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-9", - "type": "listing" - }, - "file": "basics.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "basics", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "basics/src/background/empty/main.go#example" - }, - "lang": "go", - "nodes": [ - { - "content": "func main() {\n\tctx := context.Background()\n\n\t// print the current value\n\t// of the context\n\tfmt.Printf(\"%v\\n\", ctx)\n\n\t// print Go-syntax representation of the value\n\tfmt.Printf(\"\\t%#v\\n\", ctx)\n}", - "file": "basics/src/background/empty/main.go", - "lang": "go", - "name": "example", - "start": 8, - "end": 20, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "atom": "hr", - "file": "basics", - "type": "*hype.Element" - }, - [ - { - "args": [ - "go", - "run", - "main.go" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go run main.go", - "run": "main.go", - "src": "basics/src/background/empty" - }, - "expected_exit": 0, - "file": "basics", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run main.go\n\ncontext.Background\n\tcontext.backgroundCtx{emptyCtx:context.emptyCtx{}}", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "main.go" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/12-context/basics/src/background/empty", - "stdout": "Y29udGV4dC5CYWNrZ3JvdW5kCgljb250ZXh0LmJhY2tncm91bmRDdHh7ZW1wdHlDdHg6Y29udGV4dC5lbXB0eUN0eHt9fQ==", - "duration": 426992917, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run main.go\n\ncontext.Background\n\tcontext.backgroundCtx{emptyCtx:context.emptyCtx{}}", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "main.go" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/12-context/basics/src/background/empty", - "stdout": "Y29udGV4dC5CYWNrZ3JvdW5kCgljb250ZXh0LmJhY2tncm91bmRDdHh7ZW1wdHlDdHg6Y29udGV4dC5lbXB0eUN0eHt9fQ==", - "duration": 426992917, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "basics", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.9:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Background", - "href": "https://pkg.go.dev/context#Background", - "target": "_blank" - }, - "file": "basics", - "nodes": [ - [ - { - "atom": "code", - "file": "basics", - "nodes": [ - { - "text": "context.Background", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Background" - } - ], - { - "text": " function.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 9, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "basics.md", - "level": 2, - "nodes": [ - { - "text": "Default Implementations", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "basics.md", - "nodes": [ - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Background", - "href": "https://pkg.go.dev/context#Background", - "target": "_blank" - }, - "file": "basics.md", - "nodes": [ - { - "atom": "code", - "file": "basics.md", - "nodes": [ - { - "text": "context.Background", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Background" - } - ], - { - "text": " interface, while empty, does provide default implementations of the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "basics.md", - "nodes": [ - { - "atom": "code", - "file": "basics.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": " interface. Because of this the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Background", - "href": "https://pkg.go.dev/context#Background", - "target": "_blank" - }, - "file": "basics.md", - "nodes": [ - { - "atom": "code", - "file": "basics.md", - "nodes": [ - { - "text": "context.Background", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Background" - } - ], - { - "text": " context is almost always used as the base of a new ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "basics.md", - "nodes": [ - { - "atom": "code", - "file": "basics.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": " hierarchy.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-10", - "type": "listing" - }, - "file": "basics.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "basics", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "basics/src/background/implementation/main.go#example" - }, - "lang": "go", - "nodes": [ - { - "content": "func main() {\n\tctx := context.Background()\n\n\t// print the current value\n\t// of the context\n\tfmt.Printf(\"%v\\n\", ctx)\n\n\t// print Go-syntax representation of the value\n\tfmt.Printf(\"\\t%#v\\n\", ctx)\n\n\t// print the value of the Done channel\n\t// does not block because we are not\n\t// trying to read/write to the channel\n\tfmt.Printf(\"\\tDone:\\t%#v\\n\", ctx.Done())\n\n\t// print the value of the Err\n\tfmt.Printf(\"\\tErr:\\t%#v\\n\", ctx.Err())\n\n\t// print the value of \"KEY\"\n\tfmt.Printf(\"\\tValue:\\t%#v\\n\", ctx.Value(\"KEY\"))\n\n\t// print the deadline time\n\t// and true/false if there is no deadline\n\tdeadline, ok := ctx.Deadline()\n\tfmt.Printf(\"\\tDeadline:\\t%s (%t)\\n\", deadline, ok)\n}", - "file": "basics/src/background/implementation/main.go", - "lang": "go", - "name": "example", - "start": 8, - "end": 36, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "atom": "hr", - "file": "basics", - "type": "*hype.Element" - }, - [ - { - "args": [ - "go", - "run", - "main.go" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go run main.go", - "run": "main.go", - "src": "basics/src/background/implementation" - }, - "expected_exit": 0, - "file": "basics", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run main.go\n\ncontext.Background\n\tcontext.backgroundCtx{emptyCtx:context.emptyCtx{}}\n\tDone:\t(\u0026lt;-chan struct {})(nil)\n\tErr:\t\u0026lt;nil\u0026gt;\n\tValue:\t\u0026lt;nil\u0026gt;\n\tDeadline:\t0001-01-01 00:00:00 +0000 UTC (false)", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "main.go" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/12-context/basics/src/background/implementation", - "stdout": "Y29udGV4dC5CYWNrZ3JvdW5kCgljb250ZXh0LmJhY2tncm91bmRDdHh7ZW1wdHlDdHg6Y29udGV4dC5lbXB0eUN0eHt9fQoJRG9uZToJKDwtY2hhbiBzdHJ1Y3Qge30pKG5pbCkKCUVycjoJPG5pbD4KCVZhbHVlOgk8bmlsPgoJRGVhZGxpbmU6CTAwMDEtMDEtMDEgMDA6MDA6MDAgKzAwMDAgVVRDIChmYWxzZSk=", - "duration": 1068404667, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run main.go\n\ncontext.Background\n\tcontext.backgroundCtx{emptyCtx:context.emptyCtx{}}\n\tDone:\t(\u0026lt;-chan struct {})(nil)\n\tErr:\t\u0026lt;nil\u0026gt;\n\tValue:\t\u0026lt;nil\u0026gt;\n\tDeadline:\t0001-01-01 00:00:00 +0000 UTC (false)", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "main.go" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/12-context/basics/src/background/implementation", - "stdout": "Y29udGV4dC5CYWNrZ3JvdW5kCgljb250ZXh0LmJhY2tncm91bmRDdHh7ZW1wdHlDdHg6Y29udGV4dC5lbXB0eUN0eHt9fQoJRG9uZToJKDwtY2hhbiBzdHJ1Y3Qge30pKG5pbCkKCUVycjoJPG5pbD4KCVZhbHVlOgk8bmlsPgoJRGVhZGxpbmU6CTAwMDEtMDEtMDEgMDA6MDA6MDAgKzAwMDAgVVRDIChmYWxzZSk=", - "duration": 1068404667, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "basics", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.10:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Background", - "href": "https://pkg.go.dev/context#Background", - "target": "_blank" - }, - "file": "basics", - "nodes": [ - [ - { - "atom": "code", - "file": "basics", - "nodes": [ - { - "text": "context.Background", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Background" - } - ], - { - "text": " function provides default implementation of the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "basics", - "nodes": [ - [ - { - "atom": "code", - "file": "basics", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": " interface.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 10, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "title": "The Context Interface", - "type": "*hype.Page" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "type": "*hype.Include" - } - ], - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "include", - "attributes": { - "src": "rules/rules.md" - }, - "dir": "rules", - "file": "module.md", - "nodes": [ - [ - { - "atom": "page", - "file": "rules.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "h1", - "file": "rules.md", - "level": 1, - "nodes": [ - { - "text": "Context Rules", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "rules.md", - "nodes": [ - { - "text": "According the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context", - "href": "https://pkg.go.dev/context", - "target": "_blank" - }, - "file": "rules.md", - "nodes": [ - { - "atom": "code", - "file": "rules.md", - "nodes": [ - { - "text": "context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context" - } - ], - { - "text": " documentation there are rules that must be followed when using the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context", - "href": "https://pkg.go.dev/context", - "target": "_blank" - }, - "file": "rules.md", - "nodes": [ - { - "atom": "code", - "file": "rules.md", - "nodes": [ - { - "text": "context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context" - } - ], - { - "text": " package, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-11" - }, - "file": "rules.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-11" - }, - "nodes": [ - { - "text": "Listing 1.11", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-11" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-11", - "type": "listing" - }, - "file": "rules.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "ul", - "file": "rules", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "li", - "file": "rules", - "list-type": "ul", - "nodes": [ - { - "text": "Programs that use Contexts should follow these rules to keep interfaces consistent across packages and enable static analysis tools to check context propagation.", - "type": "hype.Text" - } - ], - "type": "*hype.LI" - } - ], - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "li", - "file": "rules", - "list-type": "ul", - "nodes": [ - { - "text": "Do not store Contexts inside a struct type; instead, pass a Context explicitly to each function that needs it. The Context should be the first parameter, typically named ctx.", - "type": "hype.Text" - } - ], - "type": "*hype.LI" - } - ], - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "li", - "file": "rules", - "list-type": "ul", - "nodes": [ - { - "text": "Do not pass a ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "rules", - "nodes": [ - { - "text": "nil", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " Context, even if a function permits it. Pass ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#TODO", - "href": "https://pkg.go.dev/context#TODO", - "target": "_blank" - }, - "file": "rules", - "nodes": [ - [ - { - "atom": "code", - "file": "rules", - "nodes": [ - { - "text": "context.TODO", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#TODO" - } - ], - { - "text": " if you are unsure about which Context to use.", - "type": "hype.Text" - } - ], - "type": "*hype.LI" - } - ], - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "li", - "file": "rules", - "list-type": "ul", - "nodes": [ - { - "text": "Use context Values only for request-scoped data that transits processes and APIs, not for passing optional parameters to functions.", - "type": "hype.Text" - } - ], - "type": "*hype.LI" - } - ], - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "li", - "file": "rules", - "list-type": "ul", - "nodes": [ - { - "text": "The same Context may be passed to functions running in different goroutines; Contexts are safe for simultaneous use by multiple goroutines.", - "type": "hype.Text" - } - ], - "type": "*hype.LI" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "type": "*hype.UL" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "rules", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.11:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Rules for using contexts.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 11, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "title": "Context Rules", - "type": "*hype.Page" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "type": "*hype.Include" - } - ], - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "include", - "attributes": { - "src": "nodes/nodes.md" - }, - "dir": "nodes", - "file": "module.md", - "nodes": [ - [ - { - "atom": "page", - "file": "nodes.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "h1", - "file": "nodes.md", - "level": 1, - "nodes": [ - { - "text": "Context Nodal Hierarchy", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "nodes.md", - "nodes": [ - { - "text": "As the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context", - "href": "https://pkg.go.dev/context", - "target": "_blank" - }, - "file": "nodes.md", - "nodes": [ - { - "atom": "code", - "file": "nodes.md", - "nodes": [ - { - "text": "context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context" - } - ], - { - "text": " documentation states, a ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "nodes.md", - "nodes": [ - { - "atom": "code", - "file": "nodes.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": " is not meant to be stored and held onto, but should be passed at \"runtime\".", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "nodes.md", - "nodes": [ - { - "text": "Consider an HTTP request. An HTTP request is a ", - "type": "hype.Text" - }, - { - "atom": "strong", - "file": "nodes.md", - "nodes": [ - { - "text": "runtime", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " value that gets passed along through the application until eventually the response is returned. We would not want to store, or hold on to, the request for future use as it would be of no benefit once the response is returned.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "nodes.md", - "nodes": [ - { - "text": "Using ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "nodes.md", - "nodes": [ - { - "atom": "code", - "file": "nodes.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": " in our code behaves like the HTTP request. We pass a ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "nodes.md", - "nodes": [ - { - "atom": "code", - "file": "nodes.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": " through the application where they can be listened to for cancellation, or for other purposes, at \"runtime\".", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "nodes.md", - "nodes": [ - { - "text": "As a ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "nodes.md", - "nodes": [ - { - "atom": "code", - "file": "nodes.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": " is passed through the application, a receiving method may wrap the context with their cancellation functionality or with ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#WithValue", - "href": "https://pkg.go.dev/context#WithValue", - "target": "_blank" - }, - "file": "nodes.md", - "nodes": [ - { - "atom": "code", - "file": "nodes.md", - "nodes": [ - { - "text": "context.WithValue", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#WithValue" - } - ], - { - "text": " to add a value, such as a \"request id\", before passing the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "nodes.md", - "nodes": [ - { - "atom": "code", - "file": "nodes.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": " along to any functions, or methods, that it may call.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "nodes.md", - "nodes": [ - { - "text": "The result is a nodal hierarchy of ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "nodes.md", - "nodes": [ - { - "atom": "code", - "file": "nodes.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": " values that starts at the beginning of the request, or the start of the application, and spiders out throughout the application.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "nodes.md", - "level": 2, - "nodes": [ - { - "text": "Understanding the Nodal Hierarchy", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "nodes.md", - "nodes": [ - { - "text": "Consider ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-12" - }, - "file": "nodes.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-12" - }, - "nodes": [ - { - "text": "Listing 1.12", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-12" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ". We start with a ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Background", - "href": "https://pkg.go.dev/context#Background", - "target": "_blank" - }, - "file": "nodes.md", - "nodes": [ - { - "atom": "code", - "file": "nodes.md", - "nodes": [ - { - "text": "context.Background", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Background" - } - ], - { - "text": " context and pass it the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "nodes.md", - "nodes": [ - { - "text": "A", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " and ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "nodes.md", - "nodes": [ - { - "text": "B", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " functions. Each function wraps the given ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "nodes.md", - "nodes": [ - { - "atom": "code", - "file": "nodes.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": ", prints that new ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "nodes.md", - "nodes": [ - { - "atom": "code", - "file": "nodes.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": " with a new one before either passing it along to the next function or returning.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-12", - "type": "listing" - }, - "file": "nodes.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "nodes", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "nodes/src/node-tree/main.go#main" - }, - "lang": "go", - "nodes": [ - { - "content": "func main() {\n\t// create a background context\n\tbg := context.Background()\n\n\t// pass the background context to the A function\n\tA(bg)\n\n\t// pass the background context to the B function\n\tB(bg)\n}", - "file": "nodes/src/node-tree/main.go", - "lang": "go", - "name": "main", - "start": 16, - "end": 28, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "nodes", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.12:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Wrapping contexts creates nodal hierarchies.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 12, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "nodes.md", - "level": 2, - "nodes": [ - { - "text": "Wrapping with Context Values", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "nodes.md", - "nodes": [ - { - "text": "To wrap the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "nodes.md", - "nodes": [ - { - "atom": "code", - "file": "nodes.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": " with a new one, we will use ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#WithValue", - "href": "https://pkg.go.dev/context#WithValue", - "target": "_blank" - }, - "file": "nodes.md", - "nodes": [ - { - "atom": "code", - "file": "nodes.md", - "nodes": [ - { - "text": "context.WithValue", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#WithValue" - } - ], - { - "text": ". The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#WithValue", - "href": "https://pkg.go.dev/context#WithValue", - "target": "_blank" - }, - "file": "nodes.md", - "nodes": [ - { - "atom": "code", - "file": "nodes.md", - "nodes": [ - { - "text": "context.WithValue", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#WithValue" - } - ], - { - "text": " function takes a ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "nodes.md", - "nodes": [ - { - "atom": "code", - "file": "nodes.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": " and a key and value, and returns a new ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "nodes.md", - "nodes": [ - { - "atom": "code", - "file": "nodes.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": " with the given key and value that wraps the original ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "nodes.md", - "nodes": [ - { - "atom": "code", - "file": "nodes.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": ". We will learn more about ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#WithValue", - "href": "https://pkg.go.dev/context#WithValue", - "target": "_blank" - }, - "file": "nodes.md", - "nodes": [ - { - "atom": "code", - "file": "nodes.md", - "nodes": [ - { - "text": "context.WithValue", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#WithValue" - } - ], - { - "text": " later.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "nodes.md", - "level": 2, - "nodes": [ - { - "text": "Following the Context Nodes", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "nodes.md", - "nodes": [ - { - "text": "In ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-13" - }, - "file": "nodes.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-13" - }, - "nodes": [ - { - "text": "Listing 1.13", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-13" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", we define the functions used in ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-12" - }, - "file": "nodes.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-12" - }, - "nodes": [ - { - "text": "Listing 1.12", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-12" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ". Each of these functions takes a ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "nodes.md", - "nodes": [ - { - "atom": "code", - "file": "nodes.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": " as an argument. They then wrap the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "nodes.md", - "nodes": [ - { - "atom": "code", - "file": "nodes.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": " with a new one, print the new ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "nodes.md", - "nodes": [ - { - "atom": "code", - "file": "nodes.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": " with a new one, and pass it along to the next function.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-13", - "type": "listing" - }, - "file": "nodes.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "nodes", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "nodes/src/node-tree/main.go#example" - }, - "lang": "go", - "nodes": [ - { - "content": "func A(ctx context.Context) {\n\t// wrap ctx with a new context\n\t// with the ID set to \"A\"\n\tA := context.WithValue(ctx, ID, \"A\")\n\tprint(\"A\", A)\n\n\t// pass the A context to the A1 function\n\tA1(A)\n}\n\nfunc A1(ctx context.Context) {\n\tA1 := context.WithValue(ctx, ID, \"A1\")\n\tprint(\"A1\", A1)\n}\n\nfunc B(ctx context.Context) {\n\t// wrap ctx with a new context\n\t// with the ID set to \"B\"\n\tB := context.WithValue(ctx, ID, \"B\")\n\tprint(\"B\", B)\n\n\t// pass the B context to the B1 function\n\tB1(B)\n}\n\nfunc B1(ctx context.Context) {\n\t// wrap ctx with a new context\n\t// with the ID set to \"B1\"\n\tB1 := context.WithValue(ctx, ID, \"B1\")\n\tprint(\"B1\", B1)\n\n\t// pass the B1 context to the B1a function\n\tB1a(B1)\n}\n\nfunc B1a(ctx context.Context) {\n\t// wrap ctx with a new context\n\t// with the ID set to \"B1a\"\n\tB1a := context.WithValue(ctx, ID, \"B1a\")\n\tprint(\"B1a\", B1a)\n}", - "file": "nodes/src/node-tree/main.go", - "lang": "go", - "name": "example", - "start": 30, - "end": 73, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "nodes", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.13:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The example application.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 13, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "nodes.md", - "nodes": [ - { - "text": "When we look at the output of the program, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-14" - }, - "file": "nodes.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-14" - }, - "nodes": [ - { - "text": "Listing 1.14", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-14" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", we can see that when we print out any given ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "nodes.md", - "nodes": [ - { - "atom": "code", - "file": "nodes.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": " we see that is at the bottom of the node tree and the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Background", - "href": "https://pkg.go.dev/context#Background", - "target": "_blank" - }, - "file": "nodes.md", - "nodes": [ - { - "atom": "code", - "file": "nodes.md", - "nodes": [ - { - "text": "context.Background", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Background" - } - ], - { - "text": " context is at the top of the node tree hierarchy.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-14", - "type": "listing" - }, - "file": "nodes.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "run", - "main.go" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go run main.go", - "run": "main.go", - "src": "nodes/src/node-tree" - }, - "expected_exit": 0, - "file": "nodes", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run main.go\n\nA.WithValue(key: ctx_id, value: A)\n\t--\u0026gt; context.backgroundCtx\n\nA1.WithValue(key: ctx_id, value: A1)\n\t--\u0026gt; WithValue(key: ctx_id, value: A)\n\t\t--\u0026gt; context.backgroundCtx\n\nB.WithValue(key: ctx_id, value: B)\n\t--\u0026gt; context.backgroundCtx\n\nB1.WithValue(key: ctx_id, value: B1)\n\t--\u0026gt; WithValue(key: ctx_id, value: B)\n\t\t--\u0026gt; context.backgroundCtx\n\nB1a.WithValue(key: ctx_id, value: B1a)\n\t--\u0026gt; WithValue(key: ctx_id, value: B1)\n\t\t--\u0026gt; WithValue(key: ctx_id, value: B)\n\t\t\t--\u0026gt; context.backgroundCtx", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "main.go" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/12-context/nodes/src/node-tree", - "stdout": "QS5XaXRoVmFsdWUoa2V5OiBjdHhfaWQsIHZhbHVlOiBBKQoJLS0+IGNvbnRleHQuYmFja2dyb3VuZEN0eAoKQTEuV2l0aFZhbHVlKGtleTogY3R4X2lkLCB2YWx1ZTogQTEpCgktLT4gV2l0aFZhbHVlKGtleTogY3R4X2lkLCB2YWx1ZTogQSkKCQktLT4gY29udGV4dC5iYWNrZ3JvdW5kQ3R4CgpCLldpdGhWYWx1ZShrZXk6IGN0eF9pZCwgdmFsdWU6IEIpCgktLT4gY29udGV4dC5iYWNrZ3JvdW5kQ3R4CgpCMS5XaXRoVmFsdWUoa2V5OiBjdHhfaWQsIHZhbHVlOiBCMSkKCS0tPiBXaXRoVmFsdWUoa2V5OiBjdHhfaWQsIHZhbHVlOiBCKQoJCS0tPiBjb250ZXh0LmJhY2tncm91bmRDdHgKCkIxYS5XaXRoVmFsdWUoa2V5OiBjdHhfaWQsIHZhbHVlOiBCMWEpCgktLT4gV2l0aFZhbHVlKGtleTogY3R4X2lkLCB2YWx1ZTogQjEpCgkJLS0+IFdpdGhWYWx1ZShrZXk6IGN0eF9pZCwgdmFsdWU6IEIpCgkJCS0tPiBjb250ZXh0LmJhY2tncm91bmRDdHg=", - "duration": 512666625, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run main.go\n\nA.WithValue(key: ctx_id, value: A)\n\t--\u0026gt; context.backgroundCtx\n\nA1.WithValue(key: ctx_id, value: A1)\n\t--\u0026gt; WithValue(key: ctx_id, value: A)\n\t\t--\u0026gt; context.backgroundCtx\n\nB.WithValue(key: ctx_id, value: B)\n\t--\u0026gt; context.backgroundCtx\n\nB1.WithValue(key: ctx_id, value: B1)\n\t--\u0026gt; WithValue(key: ctx_id, value: B)\n\t\t--\u0026gt; context.backgroundCtx\n\nB1a.WithValue(key: ctx_id, value: B1a)\n\t--\u0026gt; WithValue(key: ctx_id, value: B1)\n\t\t--\u0026gt; WithValue(key: ctx_id, value: B)\n\t\t\t--\u0026gt; context.backgroundCtx", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "main.go" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/12-context/nodes/src/node-tree", - "stdout": "QS5XaXRoVmFsdWUoa2V5OiBjdHhfaWQsIHZhbHVlOiBBKQoJLS0+IGNvbnRleHQuYmFja2dyb3VuZEN0eAoKQTEuV2l0aFZhbHVlKGtleTogY3R4X2lkLCB2YWx1ZTogQTEpCgktLT4gV2l0aFZhbHVlKGtleTogY3R4X2lkLCB2YWx1ZTogQSkKCQktLT4gY29udGV4dC5iYWNrZ3JvdW5kQ3R4CgpCLldpdGhWYWx1ZShrZXk6IGN0eF9pZCwgdmFsdWU6IEIpCgktLT4gY29udGV4dC5iYWNrZ3JvdW5kQ3R4CgpCMS5XaXRoVmFsdWUoa2V5OiBjdHhfaWQsIHZhbHVlOiBCMSkKCS0tPiBXaXRoVmFsdWUoa2V5OiBjdHhfaWQsIHZhbHVlOiBCKQoJCS0tPiBjb250ZXh0LmJhY2tncm91bmRDdHgKCkIxYS5XaXRoVmFsdWUoa2V5OiBjdHhfaWQsIHZhbHVlOiBCMWEpCgktLT4gV2l0aFZhbHVlKGtleTogY3R4X2lkLCB2YWx1ZTogQjEpCgkJLS0+IFdpdGhWYWx1ZShrZXk6IGN0eF9pZCwgdmFsdWU6IEIpCgkJCS0tPiBjb250ZXh0LmJhY2tncm91bmRDdHg=", - "duration": 512666625, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "nodes", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.14:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Printing the node tree.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 14, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "nodes.md", - "nodes": [ - { - "text": "In ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-15" - }, - "file": "nodes.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-15" - }, - "nodes": [ - { - "text": "Listing 1.15", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-15" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", we see that the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "nodes.md", - "nodes": [ - { - "text": "B1a", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "nodes.md", - "nodes": [ - { - "atom": "code", - "file": "nodes.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": " is a child of the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "nodes.md", - "nodes": [ - { - "text": "B1", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "nodes.md", - "nodes": [ - { - "atom": "code", - "file": "nodes.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": " and the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "nodes.md", - "nodes": [ - { - "text": "B1", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "nodes.md", - "nodes": [ - { - "atom": "code", - "file": "nodes.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": " is a child of the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "nodes.md", - "nodes": [ - { - "text": "B", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "nodes.md", - "nodes": [ - { - "atom": "code", - "file": "nodes.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": " and the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "nodes.md", - "nodes": [ - { - "text": "B", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "nodes.md", - "nodes": [ - { - "atom": "code", - "file": "nodes.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": " is a child of the original background ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "nodes.md", - "nodes": [ - { - "atom": "code", - "file": "nodes.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-15", - "type": "listing" - }, - "file": "nodes.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "img", - "attributes": { - "src": "nodes/assets/nodes.svg" - }, - "file": "nodes", - "type": "*hype.Image" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "nodes", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.15:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Visualizing the node tree.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 15, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "title": "Context Nodal Hierarchy", - "type": "*hype.Page" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "type": "*hype.Include" - } - ], - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "include", - "attributes": { - "src": "values/values.md" - }, - "dir": "values", - "file": "module.md", - "nodes": [ - [ - { - "atom": "page", - "file": "values.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "h1", - "file": "values.md", - "level": 1, - "nodes": [ - { - "text": "Context Values", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "values.md", - "nodes": [ - { - "text": "As we have seen one feature of the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context", - "href": "https://pkg.go.dev/context", - "target": "_blank" - }, - "file": "values.md", - "nodes": [ - { - "atom": "code", - "file": "values.md", - "nodes": [ - { - "text": "context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context" - } - ], - { - "text": " package is that it allows you to pass request specific values to the next function in the chain.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "values.md", - "nodes": [ - { - "text": "This provide a lot of useful benefits, such as passing request or session specific values, such as the request id, user id of the requestor, etc. to the next function in the chain.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "values.md", - "nodes": [ - { - "text": "Using values, however, has its disadvantages, as we will see shortly.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "values.md", - "level": 2, - "nodes": [ - { - "text": "Understanding Context Values", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "values.md", - "nodes": [ - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#WithValue", - "href": "https://pkg.go.dev/context#WithValue", - "target": "_blank" - }, - "file": "values.md", - "nodes": [ - { - "atom": "code", - "file": "values.md", - "nodes": [ - { - "text": "context.WithValue", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#WithValue" - } - ], - { - "text": " function can be used to wrap a given ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "values.md", - "nodes": [ - { - "atom": "code", - "file": "values.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": " with a new ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "values.md", - "nodes": [ - { - "atom": "code", - "file": "values.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": " that contains the given key/value pair.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "doc", - "context.WithValue" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "doc": "context.WithValue", - "exec": "go doc context.WithValue" - }, - "expected_exit": 0, - "file": "values.md", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc context.WithValue\n\npackage context // import \u0026#34;context\u0026#34;\n\nfunc WithValue(parent Context, key, val any) Context\n WithValue returns a copy of parent in which the value associated with key is\n val.\n\n Use context Values only for request-scoped data that transits processes and\n APIs, not for passing optional parameters to functions.\n\n The provided key must be comparable and should not be of type string or any\n other built-in type to avoid collisions between packages using context.\n Users of WithValue should define their own types for keys. To avoid\n allocating when assigning to an interface{}, context keys often have\n concrete type struct{}. Alternatively, exported context key variables\u0026#39;\n static type should be a pointer or interface.", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "context.WithValue" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBjb250ZXh0IC8vIGltcG9ydCAiY29udGV4dCIKCmZ1bmMgV2l0aFZhbHVlKHBhcmVudCBDb250ZXh0LCBrZXksIHZhbCBhbnkpIENvbnRleHQKICAgIFdpdGhWYWx1ZSByZXR1cm5zIGEgY29weSBvZiBwYXJlbnQgaW4gd2hpY2ggdGhlIHZhbHVlIGFzc29jaWF0ZWQgd2l0aCBrZXkgaXMKICAgIHZhbC4KCiAgICBVc2UgY29udGV4dCBWYWx1ZXMgb25seSBmb3IgcmVxdWVzdC1zY29wZWQgZGF0YSB0aGF0IHRyYW5zaXRzIHByb2Nlc3NlcyBhbmQKICAgIEFQSXMsIG5vdCBmb3IgcGFzc2luZyBvcHRpb25hbCBwYXJhbWV0ZXJzIHRvIGZ1bmN0aW9ucy4KCiAgICBUaGUgcHJvdmlkZWQga2V5IG11c3QgYmUgY29tcGFyYWJsZSBhbmQgc2hvdWxkIG5vdCBiZSBvZiB0eXBlIHN0cmluZyBvciBhbnkKICAgIG90aGVyIGJ1aWx0LWluIHR5cGUgdG8gYXZvaWQgY29sbGlzaW9ucyBiZXR3ZWVuIHBhY2thZ2VzIHVzaW5nIGNvbnRleHQuCiAgICBVc2VycyBvZiBXaXRoVmFsdWUgc2hvdWxkIGRlZmluZSB0aGVpciBvd24gdHlwZXMgZm9yIGtleXMuIFRvIGF2b2lkCiAgICBhbGxvY2F0aW5nIHdoZW4gYXNzaWduaW5nIHRvIGFuIGludGVyZmFjZXt9LCBjb250ZXh0IGtleXMgb2Z0ZW4gaGF2ZQogICAgY29uY3JldGUgdHlwZSBzdHJ1Y3R7fS4gQWx0ZXJuYXRpdmVseSwgZXhwb3J0ZWQgY29udGV4dCBrZXkgdmFyaWFibGVzJwogICAgc3RhdGljIHR5cGUgc2hvdWxkIGJlIGEgcG9pbnRlciBvciBpbnRlcmZhY2Uu", - "duration": 289213958, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc context.WithValue\n\npackage context // import \u0026#34;context\u0026#34;\n\nfunc WithValue(parent Context, key, val any) Context\n WithValue returns a copy of parent in which the value associated with key is\n val.\n\n Use context Values only for request-scoped data that transits processes and\n APIs, not for passing optional parameters to functions.\n\n The provided key must be comparable and should not be of type string or any\n other built-in type to avoid collisions between packages using context.\n Users of WithValue should define their own types for keys. To avoid\n allocating when assigning to an interface{}, context keys often have\n concrete type struct{}. Alternatively, exported context key variables\u0026#39;\n static type should be a pointer or interface.", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "context.WithValue" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBjb250ZXh0IC8vIGltcG9ydCAiY29udGV4dCIKCmZ1bmMgV2l0aFZhbHVlKHBhcmVudCBDb250ZXh0LCBrZXksIHZhbCBhbnkpIENvbnRleHQKICAgIFdpdGhWYWx1ZSByZXR1cm5zIGEgY29weSBvZiBwYXJlbnQgaW4gd2hpY2ggdGhlIHZhbHVlIGFzc29jaWF0ZWQgd2l0aCBrZXkgaXMKICAgIHZhbC4KCiAgICBVc2UgY29udGV4dCBWYWx1ZXMgb25seSBmb3IgcmVxdWVzdC1zY29wZWQgZGF0YSB0aGF0IHRyYW5zaXRzIHByb2Nlc3NlcyBhbmQKICAgIEFQSXMsIG5vdCBmb3IgcGFzc2luZyBvcHRpb25hbCBwYXJhbWV0ZXJzIHRvIGZ1bmN0aW9ucy4KCiAgICBUaGUgcHJvdmlkZWQga2V5IG11c3QgYmUgY29tcGFyYWJsZSBhbmQgc2hvdWxkIG5vdCBiZSBvZiB0eXBlIHN0cmluZyBvciBhbnkKICAgIG90aGVyIGJ1aWx0LWluIHR5cGUgdG8gYXZvaWQgY29sbGlzaW9ucyBiZXR3ZWVuIHBhY2thZ2VzIHVzaW5nIGNvbnRleHQuCiAgICBVc2VycyBvZiBXaXRoVmFsdWUgc2hvdWxkIGRlZmluZSB0aGVpciBvd24gdHlwZXMgZm9yIGtleXMuIFRvIGF2b2lkCiAgICBhbGxvY2F0aW5nIHdoZW4gYXNzaWduaW5nIHRvIGFuIGludGVyZmFjZXt9LCBjb250ZXh0IGtleXMgb2Z0ZW4gaGF2ZQogICAgY29uY3JldGUgdHlwZSBzdHJ1Y3R7fS4gQWx0ZXJuYXRpdmVseSwgZXhwb3J0ZWQgY29udGV4dCBrZXkgdmFyaWFibGVzJwogICAgc3RhdGljIHR5cGUgc2hvdWxkIGJlIGEgcG9pbnRlciBvciBpbnRlcmZhY2Uu", - "duration": 289213958, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "values.md", - "nodes": [ - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#WithValue", - "href": "https://pkg.go.dev/context#WithValue", - "target": "_blank" - }, - "file": "values.md", - "nodes": [ - { - "atom": "code", - "file": "values.md", - "nodes": [ - { - "text": "context.WithValue", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#WithValue" - } - ], - { - "text": " function takes a ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "values.md", - "nodes": [ - { - "atom": "code", - "file": "values.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": " as its first argument, and a key and a value as its second and third arguments.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "values.md", - "nodes": [ - { - "text": "Both the key and value are ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "values.md", - "nodes": [ - { - "text": "any", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " values. While this may seem like you can use any type for the key, this is not the case. Like maps, keys must be comparable, so complex types like maps or functions are not allowed.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "pre", - "file": "values.md", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "values/src/keys/main.go#example" - }, - "file": "values.md", - "lang": "go", - "nodes": [ - { - "content": "ctx := context.Background()\n\n// strings shouldn't be used as keys\n// because they can easily collide\n// with other functions, libraries, etc.\n// that set that same key.\n// instead strings should wrapped in their\n// own type.\nctx = context.WithValue(ctx, \"key\", \"value\")\n\n// keys must be comparable.\n// maps, and other complex types,\n// are not comparable and can't be used\n// used as keys.\nctx = context.WithValue(ctx, map[string]int{}, \"another value\")", - "file": "values/src/keys/main.go", - "lang": "go", - "name": "example", - "start": 9, - "end": 25, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ], - "type": "*hype.Element" - }, - { - "atom": "hr", - "file": "values", - "type": "*hype.Element" - }, - { - "args": [ - "go", - "run", - "main.go" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go run main.go", - "exit": "-1", - "run": "main.go", - "src": "values/src/keys" - }, - "expected_exit": -1, - "file": "values.md", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run main.go\n\npanic: key is not comparable\n\ngoroutine 1 [running]:\ncontext.WithValue({0x1007e1660, 0x140000ac030}, {0x1007d7480?, 0x140000ac060}, {0x1007d5100?, 0x1007e1440})\n\t/usr/local/go/src/context/context.go:716 +0x140\nmain.main()\n\t./main.go:24 +0x7c\nexit status 2", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "main.go" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/12-context/values/src/keys", - "err": { - "Stderr": null - }, - "exit": 1, - "stderr": "cGFuaWM6IGtleSBpcyBub3QgY29tcGFyYWJsZQoKZ29yb3V0aW5lIDEgW3J1bm5pbmddOgpjb250ZXh0LldpdGhWYWx1ZSh7MHgxMDA3ZTE2NjAsIDB4MTQwMDAwYWMwMzB9LCB7MHgxMDA3ZDc0ODA/LCAweDE0MDAwMGFjMDYwfSwgezB4MTAwN2Q1MTAwPywgMHgxMDA3ZTE0NDB9KQoJL3Vzci9sb2NhbC9nby9zcmMvY29udGV4dC9jb250ZXh0LmdvOjcxNiArMHgxNDAKbWFpbi5tYWluKCkKCS9Vc2Vycy9tYXJrYmF0ZXMvTGlicmFyeS9DbG91ZFN0b3JhZ2UvRHJvcGJveC9kZXYvZ3VpZGVzL2NvbnRlbnQvYm9vay9jaGFwdGVycy8xMi1jb250ZXh0L3ZhbHVlcy9zcmMva2V5cy9tYWluLmdvOjI0ICsweDdjCmV4aXQgc3RhdHVzIDI=", - "duration": 294700167, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run main.go\n\npanic: key is not comparable\n\ngoroutine 1 [running]:\ncontext.WithValue({0x1007e1660, 0x140000ac030}, {0x1007d7480?, 0x140000ac060}, {0x1007d5100?, 0x1007e1440})\n\t/usr/local/go/src/context/context.go:716 +0x140\nmain.main()\n\t./main.go:24 +0x7c\nexit status 2", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "main.go" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/12-context/values/src/keys", - "err": { - "Stderr": null - }, - "exit": 1, - "stderr": "cGFuaWM6IGtleSBpcyBub3QgY29tcGFyYWJsZQoKZ29yb3V0aW5lIDEgW3J1bm5pbmddOgpjb250ZXh0LldpdGhWYWx1ZSh7MHgxMDA3ZTE2NjAsIDB4MTQwMDAwYWMwMzB9LCB7MHgxMDA3ZDc0ODA/LCAweDE0MDAwMGFjMDYwfSwgezB4MTAwN2Q1MTAwPywgMHgxMDA3ZTE0NDB9KQoJL3Vzci9sb2NhbC9nby9zcmMvY29udGV4dC9jb250ZXh0LmdvOjcxNiArMHgxNDAKbWFpbi5tYWluKCkKCS9Vc2Vycy9tYXJrYmF0ZXMvTGlicmFyeS9DbG91ZFN0b3JhZ2UvRHJvcGJveC9kZXYvZ3VpZGVzL2NvbnRlbnQvYm9vay9jaGFwdGVycy8xMi1jb250ZXh0L3ZhbHVlcy9zcmMva2V5cy9tYWluLmdvOjI0ICsweDdjCmV4aXQgc3RhdHVzIDI=", - "duration": 294700167, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "values.md", - "level": 2, - "nodes": [ - { - "text": "Key Resolution", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "values.md", - "nodes": [ - { - "text": "When we ask for a key through the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context.Value", - "href": "https://pkg.go.dev/context#Context.Value", - "target": "_blank" - }, - "file": "values.md", - "nodes": [ - { - "atom": "code", - "file": "values.md", - "nodes": [ - { - "text": "context.Context.Value", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context.Value" - } - ], - { - "text": " function, the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "values.md", - "nodes": [ - { - "atom": "code", - "file": "values.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": " will first check if the key is present in the current ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "values.md", - "nodes": [ - { - "atom": "code", - "file": "values.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": ". If the key is present, the value is returned. If the key is not present, the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "values.md", - "nodes": [ - { - "atom": "code", - "file": "values.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": " will then check if the key is present in the parent ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "values.md", - "nodes": [ - { - "atom": "code", - "file": "values.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": ". If the key is present, the value is returned. If the key is not present, the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "values.md", - "nodes": [ - { - "atom": "code", - "file": "values.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": " will then check if the key is present in the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "values.md", - "nodes": [ - { - "atom": "code", - "file": "values.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": "'s parent's parent, and so on.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "values.md", - "nodes": [ - { - "text": "Consider the following example. We wrap a ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "values.md", - "nodes": [ - { - "atom": "code", - "file": "values.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": " multiple times with different key/values.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "pre", - "file": "values.md", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "values/src/resolution/main.go#example" - }, - "file": "values.md", - "lang": "go", - "nodes": [ - { - "content": "func main() {\n\n\t// create a new background context\n\tctx := context.Background()\n\n\t// wrap the context with a new context\n\t// that has the key \"A\" and the value \"a\",\n\tctx = context.WithValue(ctx, CtxKey(\"A\"), \"a\")\n\n\t// wrap the context with a new context\n\t// that has the key \"B\" and the value \"b\",\n\tctx = context.WithValue(ctx, CtxKey(\"B\"), \"b\")\n\n\t// wrap the context with a new context\n\t// that has the key \"C\" and the value \"c\",\n\tctx = context.WithValue(ctx, CtxKey(\"C\"), \"c\")\n\n\t// print the final context\n\tprint(\"ctx\", ctx)\n\n\t// retreive and print the value\n\t// for the key \"A\"\n\ta := ctx.Value(CtxKey(\"A\"))\n\tfmt.Println(\"A:\", a)\n\n\t// retreive and print the value\n\t// for the key \"B\"\n\tb := ctx.Value(CtxKey(\"B\"))\n\tfmt.Println(\"B:\", b)\n\n\t// retreive and print the value\n\t// for the key \"C\"\n\tc := ctx.Value(CtxKey(\"C\"))\n\tfmt.Println(\"C:\", c)\n\n}", - "file": "values/src/resolution/main.go", - "lang": "go", - "name": "example", - "start": 15, - "end": 53, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ], - "type": "*hype.Element" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "values.md", - "nodes": [ - { - "text": "From the output we see that the final ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "values.md", - "nodes": [ - { - "atom": "code", - "file": "values.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": " has a parentage that includes all of the values added with ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#WithValue", - "href": "https://pkg.go.dev/context#WithValue", - "target": "_blank" - }, - "file": "values.md", - "nodes": [ - { - "atom": "code", - "file": "values.md", - "nodes": [ - { - "text": "context.WithValue", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#WithValue" - } - ], - { - "text": ". We can also see that we are able to find all of the keys, including the very first one that we set.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "run", - "main.go" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go run main.go", - "run": "main.go", - "src": "values/src/resolution" - }, - "expected_exit": 0, - "file": "values.md", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run main.go\n\nctx.WithValue(key: C, value: c)\n\t--\u0026gt; WithValue(key: B, value: b)\n\t\t--\u0026gt; WithValue(key: A, value: a)\n\t\t\t--\u0026gt; context.backgroundCtx\n\nA: a\nB: b\nC: c", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "main.go" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/12-context/values/src/resolution", - "stdout": "Y3R4LldpdGhWYWx1ZShrZXk6IEMsIHZhbHVlOiBjKQoJLS0+IFdpdGhWYWx1ZShrZXk6IEIsIHZhbHVlOiBiKQoJCS0tPiBXaXRoVmFsdWUoa2V5OiBBLCB2YWx1ZTogYSkKCQkJLS0+IGNvbnRleHQuYmFja2dyb3VuZEN0eAoKQTogYQpCOiBiCkM6IGM=", - "duration": 1189892584, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run main.go\n\nctx.WithValue(key: C, value: c)\n\t--\u0026gt; WithValue(key: B, value: b)\n\t\t--\u0026gt; WithValue(key: A, value: a)\n\t\t\t--\u0026gt; context.backgroundCtx\n\nA: a\nB: b\nC: c", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "main.go" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/12-context/values/src/resolution", - "stdout": "Y3R4LldpdGhWYWx1ZShrZXk6IEMsIHZhbHVlOiBjKQoJLS0+IFdpdGhWYWx1ZShrZXk6IEIsIHZhbHVlOiBiKQoJCS0tPiBXaXRoVmFsdWUoa2V5OiBBLCB2YWx1ZTogYSkKCQkJLS0+IGNvbnRleHQuYmFja2dyb3VuZEN0eAoKQTogYQpCOiBiCkM6IGM=", - "duration": 1189892584, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "title": "Context Values", - "type": "*hype.Page" - } - ], - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "include", - "attributes": { - "src": "values/_strings.md" - }, - "dir": ".", - "file": "values.md", - "nodes": [ - [ - { - "atom": "page", - "file": "values/_strings.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "h1", - "file": "values/_strings.md", - "level": 1, - "nodes": [ - { - "text": "Problems with String Keys", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "values/_strings.md", - "nodes": [ - { - "text": "As is mentioned in the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context", - "href": "https://pkg.go.dev/context", - "target": "_blank" - }, - "file": "values/_strings.md", - "nodes": [ - { - "atom": "code", - "file": "values/_strings.md", - "nodes": [ - { - "text": "context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context" - } - ], - { - "text": " documentation using string keys is not recommended. As we just saw when ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context.Value", - "href": "https://pkg.go.dev/context#Context.Value", - "target": "_blank" - }, - "file": "values/_strings.md", - "nodes": [ - { - "atom": "code", - "file": "values/_strings.md", - "nodes": [ - { - "text": "context.Context.Value", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context.Value" - } - ], - { - "text": " tries to resolve a key it finds the first, if any, ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "values/_strings.md", - "nodes": [ - { - "atom": "code", - "file": "values/_strings.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": " that contains the key and returns that value.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-16", - "type": "listing" - }, - "file": "values/_strings.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "doc", - "context.WithValue" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "doc": "context.WithValue", - "exec": "go doc context.WithValue" - }, - "expected_exit": 0, - "file": "values", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc context.WithValue\n\npackage context // import \u0026#34;context\u0026#34;\n\nfunc WithValue(parent Context, key, val any) Context\n WithValue returns a copy of parent in which the value associated with key is\n val.\n\n Use context Values only for request-scoped data that transits processes and\n APIs, not for passing optional parameters to functions.\n\n The provided key must be comparable and should not be of type string or any\n other built-in type to avoid collisions between packages using context.\n Users of WithValue should define their own types for keys. To avoid\n allocating when assigning to an interface{}, context keys often have\n concrete type struct{}. Alternatively, exported context key variables\u0026#39;\n static type should be a pointer or interface.", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "context.WithValue" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBjb250ZXh0IC8vIGltcG9ydCAiY29udGV4dCIKCmZ1bmMgV2l0aFZhbHVlKHBhcmVudCBDb250ZXh0LCBrZXksIHZhbCBhbnkpIENvbnRleHQKICAgIFdpdGhWYWx1ZSByZXR1cm5zIGEgY29weSBvZiBwYXJlbnQgaW4gd2hpY2ggdGhlIHZhbHVlIGFzc29jaWF0ZWQgd2l0aCBrZXkgaXMKICAgIHZhbC4KCiAgICBVc2UgY29udGV4dCBWYWx1ZXMgb25seSBmb3IgcmVxdWVzdC1zY29wZWQgZGF0YSB0aGF0IHRyYW5zaXRzIHByb2Nlc3NlcyBhbmQKICAgIEFQSXMsIG5vdCBmb3IgcGFzc2luZyBvcHRpb25hbCBwYXJhbWV0ZXJzIHRvIGZ1bmN0aW9ucy4KCiAgICBUaGUgcHJvdmlkZWQga2V5IG11c3QgYmUgY29tcGFyYWJsZSBhbmQgc2hvdWxkIG5vdCBiZSBvZiB0eXBlIHN0cmluZyBvciBhbnkKICAgIG90aGVyIGJ1aWx0LWluIHR5cGUgdG8gYXZvaWQgY29sbGlzaW9ucyBiZXR3ZWVuIHBhY2thZ2VzIHVzaW5nIGNvbnRleHQuCiAgICBVc2VycyBvZiBXaXRoVmFsdWUgc2hvdWxkIGRlZmluZSB0aGVpciBvd24gdHlwZXMgZm9yIGtleXMuIFRvIGF2b2lkCiAgICBhbGxvY2F0aW5nIHdoZW4gYXNzaWduaW5nIHRvIGFuIGludGVyZmFjZXt9LCBjb250ZXh0IGtleXMgb2Z0ZW4gaGF2ZQogICAgY29uY3JldGUgdHlwZSBzdHJ1Y3R7fS4gQWx0ZXJuYXRpdmVseSwgZXhwb3J0ZWQgY29udGV4dCBrZXkgdmFyaWFibGVzJwogICAgc3RhdGljIHR5cGUgc2hvdWxkIGJlIGEgcG9pbnRlciBvciBpbnRlcmZhY2Uu", - "duration": 485638541, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc context.WithValue\n\npackage context // import \u0026#34;context\u0026#34;\n\nfunc WithValue(parent Context, key, val any) Context\n WithValue returns a copy of parent in which the value associated with key is\n val.\n\n Use context Values only for request-scoped data that transits processes and\n APIs, not for passing optional parameters to functions.\n\n The provided key must be comparable and should not be of type string or any\n other built-in type to avoid collisions between packages using context.\n Users of WithValue should define their own types for keys. To avoid\n allocating when assigning to an interface{}, context keys often have\n concrete type struct{}. Alternatively, exported context key variables\u0026#39;\n static type should be a pointer or interface.", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "context.WithValue" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBjb250ZXh0IC8vIGltcG9ydCAiY29udGV4dCIKCmZ1bmMgV2l0aFZhbHVlKHBhcmVudCBDb250ZXh0LCBrZXksIHZhbCBhbnkpIENvbnRleHQKICAgIFdpdGhWYWx1ZSByZXR1cm5zIGEgY29weSBvZiBwYXJlbnQgaW4gd2hpY2ggdGhlIHZhbHVlIGFzc29jaWF0ZWQgd2l0aCBrZXkgaXMKICAgIHZhbC4KCiAgICBVc2UgY29udGV4dCBWYWx1ZXMgb25seSBmb3IgcmVxdWVzdC1zY29wZWQgZGF0YSB0aGF0IHRyYW5zaXRzIHByb2Nlc3NlcyBhbmQKICAgIEFQSXMsIG5vdCBmb3IgcGFzc2luZyBvcHRpb25hbCBwYXJhbWV0ZXJzIHRvIGZ1bmN0aW9ucy4KCiAgICBUaGUgcHJvdmlkZWQga2V5IG11c3QgYmUgY29tcGFyYWJsZSBhbmQgc2hvdWxkIG5vdCBiZSBvZiB0eXBlIHN0cmluZyBvciBhbnkKICAgIG90aGVyIGJ1aWx0LWluIHR5cGUgdG8gYXZvaWQgY29sbGlzaW9ucyBiZXR3ZWVuIHBhY2thZ2VzIHVzaW5nIGNvbnRleHQuCiAgICBVc2VycyBvZiBXaXRoVmFsdWUgc2hvdWxkIGRlZmluZSB0aGVpciBvd24gdHlwZXMgZm9yIGtleXMuIFRvIGF2b2lkCiAgICBhbGxvY2F0aW5nIHdoZW4gYXNzaWduaW5nIHRvIGFuIGludGVyZmFjZXt9LCBjb250ZXh0IGtleXMgb2Z0ZW4gaGF2ZQogICAgY29uY3JldGUgdHlwZSBzdHJ1Y3R7fS4gQWx0ZXJuYXRpdmVseSwgZXhwb3J0ZWQgY29udGV4dCBrZXkgdmFyaWFibGVzJwogICAgc3RhdGljIHR5cGUgc2hvdWxkIGJlIGEgcG9pbnRlciBvciBpbnRlcmZhY2Uu", - "duration": 485638541, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "values", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.16:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Using strings as context keys is not recommended per the documentation.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 16, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "values/_strings.md", - "nodes": [ - { - "text": "When we use the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context.Value", - "href": "https://pkg.go.dev/context#Context.Value", - "target": "_blank" - }, - "file": "values/_strings.md", - "nodes": [ - { - "atom": "code", - "file": "values/_strings.md", - "nodes": [ - { - "text": "context.Context.Value", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context.Value" - } - ], - { - "text": " function, we get the last value that was set for the given key. Each time we use ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#WithValue", - "href": "https://pkg.go.dev/context#WithValue", - "target": "_blank" - }, - "file": "values/_strings.md", - "nodes": [ - { - "atom": "code", - "file": "values/_strings.md", - "nodes": [ - { - "text": "context.WithValue", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#WithValue" - } - ], - { - "text": " to wrap a ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "values/_strings.md", - "nodes": [ - { - "atom": "code", - "file": "values/_strings.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": " with a new ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "values/_strings.md", - "nodes": [ - { - "atom": "code", - "file": "values/_strings.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": ", the new ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "values/_strings.md", - "nodes": [ - { - "atom": "code", - "file": "values/_strings.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": " will have, essentially, replaced the previous value for the given key.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "img", - "attributes": { - "alt": "string-keys", - "src": "values/assets/string-keys.svg" - }, - "file": "values/_strings.md", - "type": "*hype.Image" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "values/_strings.md", - "level": 2, - "nodes": [ - { - "text": "Key Collisions", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "values/_strings.md", - "nodes": [ - { - "text": "Consider the following example. We wrap a ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "values/_strings.md", - "nodes": [ - { - "atom": "code", - "file": "values/_strings.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": " multiple times, each time with a different value, but the same key, ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "values/_strings.md", - "nodes": [ - { - "text": "request_id", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ", which is of type ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "values/_strings.md", - "nodes": [ - { - "text": "string", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "pre", - "file": "values/_strings.md", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "values/src/string-keys/main.go#example" - }, - "file": "_strings.md", - "lang": "go", - "nodes": [ - { - "content": "func main() {\n\t// create a new background context\n\tctx := context.Background()\n\n\t// call the A function\n\t// passing in the background context\n\tA(ctx)\n}\n\nfunc A(ctx context.Context) {\n\t// wrap the context with a request_id\n\t// to represent this specific A request\n\tctx = context.WithValue(ctx, \"request_id\", \"123\")\n\n\t// call the B function\n\t// passing in the wrapped context\n\tB(ctx)\n}\n\nfunc B(ctx context.Context) {\n\t// wrap the context with a request_id\n\t// to represent this specific B request\n\tctx = context.WithValue(ctx, \"request_id\", \"456\")\n\tLogger(ctx)\n}\n\n// Logger logs the webs request_id\n// as well as the request_id from the B\nfunc Logger(ctx context.Context) {\n\ta := ctx.Value(\"request_id\")\n\tfmt.Println(\"A\\t\", \"request_id:\", a)\n\n\tb := ctx.Value(\"request_id\")\n\tfmt.Println(\"B\\t\", \"request_id:\", b)\n}", - "file": "values/src/string-keys/main.go", - "lang": "go", - "name": "example", - "start": 8, - "end": 45, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ], - "type": "*hype.Element" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "values/_strings.md", - "nodes": [ - { - "text": "When we try to log both the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "values/_strings.md", - "nodes": [ - { - "text": "request_id", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " for both ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "values/_strings.md", - "nodes": [ - { - "text": "A", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " and ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "values/_strings.md", - "nodes": [ - { - "text": "A", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " we see that they are both set to the same value.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "run", - "main.go" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go run main.go", - "run": "main.go", - "src": "values/src/string-keys" - }, - "expected_exit": 0, - "file": "values/_strings.md", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run main.go\n\nA\t request_id: 456\nB\t request_id: 456", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "main.go" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/12-context/values/src/string-keys", - "stdout": "QQkgcmVxdWVzdF9pZDogNDU2CkIJIHJlcXVlc3RfaWQ6IDQ1Ng==", - "duration": 584182042, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run main.go\n\nA\t request_id: 456\nB\t request_id: 456", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "main.go" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/12-context/values/src/string-keys", - "stdout": "QQkgcmVxdWVzdF9pZDogNDU2CkIJIHJlcXVlc3RfaWQ6IDQ1Ng==", - "duration": 584182042, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "values/_strings.md", - "nodes": [ - { - "text": "One way to solve this problem would be try and \"namespace\" your ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "values/_strings.md", - "nodes": [ - { - "text": "string", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " keys, ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "values/_strings.md", - "nodes": [ - { - "text": "myapp.request_id", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ". While you may never get into a collision scenario, the possibility of someone else using the same key is there.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "values/_strings.md", - "level": 2, - "nodes": [ - { - "text": "Custom String Key Types", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "values/_strings.md", - "nodes": [ - { - "text": "Because Go is a typed language, we can leverage the type system to solve the problem of key collisions. We can create a new type based on ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "values/_strings.md", - "nodes": [ - { - "text": "string", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " that we can use as the key.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "pre", - "file": "values/_strings.md", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "values/src/custom-keys/main.go#types" - }, - "file": "_strings.md", - "lang": "go", - "nodes": [ - { - "content": "// CtxKeyA is used to wrap keys\n// associated with a A request\n// \tCtxKeyA(\"request_id\")\n// \tCtxKeyA(\"user_id\")\ntype CtxKeyA string\n\n// CtxKeyB is used to wrap keys\n// associated with a B request\n// \tCtxKeyB(\"request_id\")\n// \tCtxKeyB(\"user_id\")\ntype CtxKeyB string", - "file": "values/src/custom-keys/main.go", - "lang": "go", - "name": "types", - "start": 8, - "end": 21, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ], - "type": "*hype.Element" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "pre", - "file": "values/_strings.md", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "values/src/custom-keys/main.go#example" - }, - "file": "_strings.md", - "lang": "go", - "nodes": [ - { - "content": "func A(ctx context.Context) {\n\t// wrap the context with a request_id\n\t// to represent this specific A request\n\tkey := CtxKeyA(\"request_id\")\n\tctx = context.WithValue(ctx, key, \"123\")\n\n\t// call B with the wrapped context\n\tB(ctx)\n}\n\nfunc B(ctx context.Context) {\n\t// wrap the context with a request_id\n\t// to represent this specific B request\n\tkey := CtxKeyB(\"request_id\")\n\tctx = context.WithValue(ctx, key, \"456\")\n\n\tLogger(ctx)\n}", - "file": "values/src/custom-keys/main.go", - "lang": "go", - "name": "example", - "start": 31, - "end": 51, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ], - "type": "*hype.Element" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "pre", - "file": "values/_strings.md", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "values/src/custom-keys/main.go#logger" - }, - "file": "_strings.md", - "lang": "go", - "nodes": [ - { - "content": "// Logger logs the webs request_id\n// as well as the request_id from the B\nfunc Logger(ctx context.Context) {\n\t// retreive the request_id from the A request\n\taKey := CtxKeyA(\"request_id\")\n\taVal := ctx.Value(aKey)\n\n\t// print the request_id from the A request\n\tprint(\"A\", aKey, aVal)\n\n\t// retreive the request_id from the B request\n\tbKey := CtxKeyB(\"request_id\")\n\tbVal := ctx.Value(bKey)\n\n\t// print the request_id from the B request\n\tprint(\"B\", bKey, bVal)\n}", - "file": "values/src/custom-keys/main.go", - "lang": "go", - "name": "logger", - "start": 53, - "end": 72, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ], - "type": "*hype.Element" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "values/_strings.md", - "nodes": [ - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "values/_strings.md", - "nodes": [ - { - "text": "Logger", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " is now properly able to retrieve the two different ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "values/_strings.md", - "nodes": [ - { - "text": "request_id", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " values because they are no longer of the same type.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "run", - "main.go" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go run main.go", - "run": "main.go", - "src": "values/src/custom-keys" - }, - "expected_exit": 0, - "file": "values/_strings.md", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run main.go\n\nA: main.CtxKeyA(request_id): 123\nB: main.CtxKeyB(request_id): 456", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "main.go" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/12-context/values/src/custom-keys", - "stdout": "QTogbWFpbi5DdHhLZXlBKHJlcXVlc3RfaWQpOiAxMjMKQjogbWFpbi5DdHhLZXlCKHJlcXVlc3RfaWQpOiA0NTY=", - "duration": 361765958, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run main.go\n\nA: main.CtxKeyA(request_id): 123\nB: main.CtxKeyB(request_id): 456", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "main.go" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/12-context/values/src/custom-keys", - "stdout": "QTogbWFpbi5DdHhLZXlBKHJlcXVlc3RfaWQpOiAxMjMKQjogbWFpbi5DdHhLZXlCKHJlcXVlc3RfaWQpOiA0NTY=", - "duration": 361765958, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "values/_strings.md", - "nodes": [ - { - "text": "This code can be further cleaned up by using constants for the keys that our package, or application, uses. This allows for cleaner code and makes it easier to document the potential keys that may be in a ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "values/_strings.md", - "nodes": [ - { - "atom": "code", - "file": "values/_strings.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "pre", - "file": "values/_strings.md", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "values/src/custom-const/main.go#consts" - }, - "file": "_strings.md", - "lang": "go", - "nodes": [ - { - "content": "const (\n\t// A_RequestID can be used to\n\t// retreive the request_id for\n\t// the A request\n\tA_RequestID CtxKeyA = \"request_id\"\n\t// \tA_SESSION_ID CtxKeyA = \"session_id\"\n\t// \tA_SERVER_ID CtxKeyA = \"server_id\"\n\t// \tother keys...\n\n\t// B_RequestID can be used to\n\t// retreive the request_id for\n\t// the B request\n\tB_RequestID CtxKeyB = \"request_id\"\n)", - "file": "values/src/custom-const/main.go", - "lang": "go", - "name": "consts", - "start": 23, - "end": 39, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ], - "type": "*hype.Element" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "pre", - "file": "values/_strings.md", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "values/src/custom-const/main.go#logger" - }, - "file": "_strings.md", - "lang": "go", - "nodes": [ - { - "content": "// Logger logs the webs request_id\n// as well as the request_id from the B\nfunc Logger(ctx context.Context) {\n\t// retreive the request_id from the A request\n\taKey := A_RequestID\n\taVal := ctx.Value(aKey)\n\n\t// print the request_id from the A request\n\tprint(\"A\", aKey, aVal)\n\n\t// retreive the request_id from the B request\n\tbKey := B_RequestID\n\tbVal := ctx.Value(bKey)\n\n\t// print the request_id from the B request\n\tprint(\"B\", bKey, bVal)\n}", - "file": "values/src/custom-const/main.go", - "lang": "go", - "name": "logger", - "start": 69, - "end": 88, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ], - "type": "*hype.Element" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "title": "Problems with String Keys", - "type": "*hype.Page" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "type": "*hype.Include" - } - ], - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "include", - "attributes": { - "src": "values/_securing.md" - }, - "dir": ".", - "file": "values.md", - "nodes": [ - [ - { - "atom": "page", - "file": "values/_securing.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "h1", - "file": "values/_securing.md", - "level": 1, - "nodes": [ - { - "text": "Securing Context Keys and Values", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "values/_securing.md", - "nodes": [ - { - "text": "If we export, make public, the types, and names, of the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "values/_securing.md", - "nodes": [ - { - "atom": "code", - "file": "values/_securing.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": " keys our package or application uses, we run the risk of a malicious agent stealing, or modifying our values. For example, in a web request we might set a ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "values/_securing.md", - "nodes": [ - { - "text": "request_id", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " at the beginning of the request, but a piece of middleware later in the chain might modify that value to something else.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "pre", - "file": "values/_securing.md", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "snippet": "types", - "src": "values/src/malicious/foo/foo.go" - }, - "file": "_securing.md", - "lang": "go", - "nodes": [ - { - "content": "type CtxKey string\n\nconst (\n\tRequestID CtxKey = \"request_id\"\n)", - "file": "values/src/malicious/foo/foo.go", - "lang": "go", - "name": "types", - "start": 5, - "end": 12, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ], - "type": "*hype.Element" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "pre", - "file": "values/_securing.md", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "snippet": "example", - "src": "values/src/malicious/bar/bar.go" - }, - "file": "_securing.md", - "lang": "go", - "nodes": [ - { - "content": "func WithBar(ctx context.Context) context.Context {\n\t// wrap the context with a request_id\n\t// to represent this specific bar request\n\tctx = context.WithValue(ctx, RequestID, \"456\")\n\n\t// maliciously replace the request_id\n\t// set by foo\n\tctx = context.WithValue(ctx, foo.RequestID, \"???\")\n\n\t// return the wrapped context\n\treturn ctx\n}", - "file": "values/src/malicious/bar/bar.go", - "lang": "go", - "name": "example", - "start": 17, - "end": 31, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ], - "type": "*hype.Element" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "values/_securing.md", - "nodes": [ - [ - { - "atom": "pre", - "file": "values/_securing.md", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "snippet": "example", - "src": "values/src/malicious/main.go" - }, - "file": "_securing.md", - "lang": "go", - "nodes": [ - { - "content": "func main() {\n\t// create a background context\n\tctx := context.Background()\n\n\t// wrap the context with foo\n\tctx = foo.WithFoo(ctx)\n\n\t// wrap the context with bar\n\tctx = bar.WithBar(ctx)\n\n\t// retrieve the foo.RequestID\n\t// value from the context\n\tid := ctx.Value(foo.RequestID)\n\n\t// print the value\n\tfmt.Println(\"foo.RequestID: \", id)\n}", - "file": "values/src/malicious/main.go", - "lang": "go", - "name": "example", - "start": 10, - "end": 29, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ], - "type": "*hype.Element" - } - ], - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "pre", - "file": "values/_securing.md", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "snippet": "example", - "src": "values/src/malicious/foo/foo.go" - }, - "file": "_securing.md", - "lang": "go", - "nodes": [ - { - "content": "func WithFoo(ctx context.Context) context.Context {\n\t// wrap the context with a request_id\n\t// to represent this specific foo request\n\tctx = context.WithValue(ctx, RequestID, \"123\")\n\n\t// return the wrapped context\n\treturn ctx\n}", - "file": "values/src/malicious/foo/foo.go", - "lang": "go", - "name": "example", - "start": 14, - "end": 24, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ], - "type": "*hype.Element" - } - ] - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "run", - "main.go" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go run main.go", - "run": "main.go", - "src": "values/src/malicious" - }, - "expected_exit": 0, - "file": "values/_securing.md", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run main.go\n\nfoo.RequestID: ???", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "main.go" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/12-context/values/src/malicious", - "stdout": "Zm9vLlJlcXVlc3RJRDogID8/Pw==", - "duration": 772671917, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run main.go\n\nfoo.RequestID: ???", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "main.go" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/12-context/values/src/malicious", - "stdout": "Zm9vLlJlcXVlc3RJRDogID8/Pw==", - "duration": 772671917, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "values/_securing.md", - "level": 2, - "nodes": [ - { - "text": "Securing by Not Exporting", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "values/_securing.md", - "nodes": [ - { - "text": "The best way to secure your that your key/value pairs aren't maliciously overwritten, or accessed, is by not exporting the types, and any constants, used for keys.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "pre", - "file": "values/_securing.md", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "snippet": "types", - "src": "values/src/secured/foo/foo.go" - }, - "file": "_securing.md", - "lang": "go", - "nodes": [ - { - "content": "type ctxKey string\n\nconst (\n\trequestID ctxKey = \"request_id\"\n)", - "file": "values/src/secured/foo/foo.go", - "lang": "go", - "name": "types", - "start": 8, - "end": 15, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ], - "type": "*hype.Element" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "values/_securing.md", - "nodes": [ - { - "text": "Now, you are in control of what values from the context you wish to make public. For example, we can add a helper function to allow others to get access to the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "values/_securing.md", - "nodes": [ - { - "text": "request_id", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " value.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "values/_securing.md", - "nodes": [ - { - "text": "Because the return value from ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context.Value", - "href": "https://pkg.go.dev/context#Context.Value", - "target": "_blank" - }, - "file": "values/_securing.md", - "nodes": [ - { - "atom": "code", - "file": "values/_securing.md", - "nodes": [ - { - "text": "context.Context.Value", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context.Value" - } - ], - { - "text": " is an empty interface, ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "values/_securing.md", - "nodes": [ - { - "text": "interface{}", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ", we can use these helper functions to, not just retrieve access to the value, but also type assert the value to the type we want, or return an error if it doesn't.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "pre", - "file": "values/_securing.md", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "snippet": "example", - "src": "values/src/secured/foo/foo.go" - }, - "file": "_securing.md", - "lang": "go", - "nodes": [ - { - "content": "func RequestIDFrom(ctx context.Context) (string, error) {\n\t// get the request_id from the context\n\ts, ok := ctx.Value(requestID).(string)\n\tif !ok {\n\t\treturn \"\", fmt.Errorf(\"request_id not found in context\")\n\t}\n\treturn s, nil\n}", - "file": "values/src/secured/foo/foo.go", - "lang": "go", - "name": "example", - "start": 26, - "end": 36, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ], - "type": "*hype.Element" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "values/_securing.md", - "nodes": [ - { - "text": "Our application can be updated to use the new helper function to print the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "values/_securing.md", - "nodes": [ - { - "text": "request_id", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " or exit if there was a problem getting the value.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "pre", - "file": "values/_securing.md", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "snippet": "example", - "src": "values/src/secured/main.go" - }, - "file": "_securing.md", - "lang": "go", - "nodes": [ - { - "content": "func main() {\n\t// create a background context\n\tctx := context.Background()\n\n\t// wrap the context with foo\n\tctx = foo.WithFoo(ctx)\n\n\t// wrap the context with bar\n\tctx = bar.WithBar(ctx)\n\n\t// retrieve the foo.RequestID\n\t// value from the context\n\tid, err := foo.RequestIDFrom(ctx)\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\n\t// print the value\n\tfmt.Println(\"foo.RequestID: \", id)\n}", - "file": "values/src/secured/main.go", - "lang": "go", - "name": "example", - "start": 11, - "end": 33, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ], - "type": "*hype.Element" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "values/_securing.md", - "nodes": [ - { - "text": "The malicious ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "values/_securing.md", - "nodes": [ - { - "text": "bar", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " package can no longer set, or retrieve, the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "values/_securing.md", - "nodes": [ - { - "text": "request_id", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " value set by the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "values/_securing.md", - "nodes": [ - { - "text": "foo", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " package. The ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "values/_securing.md", - "nodes": [ - { - "text": "bar", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " package does not have the ability to create a new type of value ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "values/_securing.md", - "nodes": [ - { - "text": "foo.ctxKey", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " because the type is un-exported can be accessed outside of the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "values/_securing.md", - "nodes": [ - { - "text": "foo", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " package.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "pre", - "file": "values/_securing.md", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "snippet": "example", - "src": "values/src/secured/bar/bar.go" - }, - "file": "_securing.md", - "lang": "go", - "nodes": [ - { - "content": "func WithBar(ctx context.Context) context.Context {\n\t// wrap the context with a request_id\n\t// to represent this specific bar request\n\tctx = context.WithValue(ctx, requestID, \"456\")\n\n\t// no longer able to set the foo request id\n\t// it does not have access to the foo.ctxKey type\n\t// as it is not exported, so bar can not create\n\t// a new key of that type.\n\t// ctx = context.WithValue(ctx, foo.ctxKey(\"request_id\"), \"???\")\n\n\t// return the wrapped context\n\treturn ctx\n}", - "file": "values/src/secured/bar/bar.go", - "lang": "go", - "name": "example", - "start": 16, - "end": 32, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ], - "type": "*hype.Element" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "values/_securing.md", - "nodes": [ - { - "text": "As a result of securing our ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "values/_securing.md", - "nodes": [ - { - "atom": "code", - "file": "values/_securing.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": " values, the application now correctly retrieves the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "values/_securing.md", - "nodes": [ - { - "text": "request_id", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " value set by the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "values/_securing.md", - "nodes": [ - { - "text": "foo", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " package.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "run", - "main.go" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go run main.go", - "run": "main.go", - "src": "values/src/secured" - }, - "expected_exit": 0, - "file": "values/_securing.md", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run main.go\n\nfoo.RequestID: 123", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "main.go" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/12-context/values/src/secured", - "stdout": "Zm9vLlJlcXVlc3RJRDogIDEyMw==", - "duration": 638528792, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run main.go\n\nfoo.RequestID: 123", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "main.go" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/12-context/values/src/secured", - "stdout": "Zm9vLlJlcXVlc3RJRDogIDEyMw==", - "duration": 638528792, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "title": "Securing Context Keys and Values", - "type": "*hype.Page" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "type": "*hype.Include" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "type": "*hype.Include" - } - ], - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "include", - "attributes": { - "src": "cancellation/cancellation.md" - }, - "dir": "cancellation", - "file": "module.md", - "nodes": [ - [ - { - "atom": "page", - "file": "cancellation.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "h1", - "file": "cancellation.md", - "level": 1, - "nodes": [ - { - "text": "Cancellation Propagation with Contexts", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "cancellation.md", - "nodes": [ - { - "text": "While having the ability to pass contextual information via the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "cancellation.md", - "nodes": [ - { - "atom": "code", - "file": "cancellation.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": " is useful, the real benefit, and design of the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context", - "href": "https://pkg.go.dev/context", - "target": "_blank" - }, - "file": "cancellation.md", - "nodes": [ - { - "atom": "code", - "file": "cancellation.md", - "nodes": [ - { - "text": "context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context" - } - ], - { - "text": " package, is that it can be used to propagate cancellation events to those listening to the context. When a parent ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "cancellation.md", - "nodes": [ - { - "atom": "code", - "file": "cancellation.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": " is canceled, all its children are also canceled.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "cancellation.md", - "level": 2, - "nodes": [ - { - "text": "Creating a Cancellable Context", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "cancellation.md", - "nodes": [ - { - "text": "In order to cancel a ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "cancellation.md", - "nodes": [ - { - "atom": "code", - "file": "cancellation.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": ", we must have a way of cancelling it. The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#WithCancel", - "href": "https://pkg.go.dev/context#WithCancel", - "target": "_blank" - }, - "file": "cancellation.md", - "nodes": [ - { - "atom": "code", - "file": "cancellation.md", - "nodes": [ - { - "text": "context.WithCancel", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#WithCancel" - } - ], - { - "text": " function, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-17" - }, - "file": "cancellation.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-17" - }, - "nodes": [ - { - "text": "Listing 1.17", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-17" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", wraps a given ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "cancellation.md", - "nodes": [ - { - "atom": "code", - "file": "cancellation.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": " with a ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "cancellation.md", - "nodes": [ - { - "atom": "code", - "file": "cancellation.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": " that can be cancelled.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-17", - "type": "listing" - }, - "file": "cancellation.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "doc", - "context.WithCancel" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "doc": "context.WithCancel", - "exec": "go doc context.WithCancel" - }, - "expected_exit": 0, - "file": "cancellation", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc context.WithCancel\n\npackage context // import \u0026#34;context\u0026#34;\n\nfunc WithCancel(parent Context) (ctx Context, cancel CancelFunc)\n WithCancel returns a copy of parent with a new Done channel. The returned\n context\u0026#39;s Done channel is closed when the returned cancel function is called\n or when the parent context\u0026#39;s Done channel is closed, whichever happens\n first.\n\n Canceling this context releases resources associated with it, so code should\n call cancel as soon as the operations running in this Context complete.", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "context.WithCancel" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBjb250ZXh0IC8vIGltcG9ydCAiY29udGV4dCIKCmZ1bmMgV2l0aENhbmNlbChwYXJlbnQgQ29udGV4dCkgKGN0eCBDb250ZXh0LCBjYW5jZWwgQ2FuY2VsRnVuYykKICAgIFdpdGhDYW5jZWwgcmV0dXJucyBhIGNvcHkgb2YgcGFyZW50IHdpdGggYSBuZXcgRG9uZSBjaGFubmVsLiBUaGUgcmV0dXJuZWQKICAgIGNvbnRleHQncyBEb25lIGNoYW5uZWwgaXMgY2xvc2VkIHdoZW4gdGhlIHJldHVybmVkIGNhbmNlbCBmdW5jdGlvbiBpcyBjYWxsZWQKICAgIG9yIHdoZW4gdGhlIHBhcmVudCBjb250ZXh0J3MgRG9uZSBjaGFubmVsIGlzIGNsb3NlZCwgd2hpY2hldmVyIGhhcHBlbnMKICAgIGZpcnN0LgoKICAgIENhbmNlbGluZyB0aGlzIGNvbnRleHQgcmVsZWFzZXMgcmVzb3VyY2VzIGFzc29jaWF0ZWQgd2l0aCBpdCwgc28gY29kZSBzaG91bGQKICAgIGNhbGwgY2FuY2VsIGFzIHNvb24gYXMgdGhlIG9wZXJhdGlvbnMgcnVubmluZyBpbiB0aGlzIENvbnRleHQgY29tcGxldGUu", - "duration": 499625958, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc context.WithCancel\n\npackage context // import \u0026#34;context\u0026#34;\n\nfunc WithCancel(parent Context) (ctx Context, cancel CancelFunc)\n WithCancel returns a copy of parent with a new Done channel. The returned\n context\u0026#39;s Done channel is closed when the returned cancel function is called\n or when the parent context\u0026#39;s Done channel is closed, whichever happens\n first.\n\n Canceling this context releases resources associated with it, so code should\n call cancel as soon as the operations running in this Context complete.", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "context.WithCancel" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBjb250ZXh0IC8vIGltcG9ydCAiY29udGV4dCIKCmZ1bmMgV2l0aENhbmNlbChwYXJlbnQgQ29udGV4dCkgKGN0eCBDb250ZXh0LCBjYW5jZWwgQ2FuY2VsRnVuYykKICAgIFdpdGhDYW5jZWwgcmV0dXJucyBhIGNvcHkgb2YgcGFyZW50IHdpdGggYSBuZXcgRG9uZSBjaGFubmVsLiBUaGUgcmV0dXJuZWQKICAgIGNvbnRleHQncyBEb25lIGNoYW5uZWwgaXMgY2xvc2VkIHdoZW4gdGhlIHJldHVybmVkIGNhbmNlbCBmdW5jdGlvbiBpcyBjYWxsZWQKICAgIG9yIHdoZW4gdGhlIHBhcmVudCBjb250ZXh0J3MgRG9uZSBjaGFubmVsIGlzIGNsb3NlZCwgd2hpY2hldmVyIGhhcHBlbnMKICAgIGZpcnN0LgoKICAgIENhbmNlbGluZyB0aGlzIGNvbnRleHQgcmVsZWFzZXMgcmVzb3VyY2VzIGFzc29jaWF0ZWQgd2l0aCBpdCwgc28gY29kZSBzaG91bGQKICAgIGNhbGwgY2FuY2VsIGFzIHNvb24gYXMgdGhlIG9wZXJhdGlvbnMgcnVubmluZyBpbiB0aGlzIENvbnRleHQgY29tcGxldGUu", - "duration": 499625958, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "cancellation", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.17:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#WithCancel", - "href": "https://pkg.go.dev/context#WithCancel", - "target": "_blank" - }, - "file": "cancellation", - "nodes": [ - [ - { - "atom": "code", - "file": "cancellation", - "nodes": [ - { - "text": "context.WithCancel", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#WithCancel" - } - ], - { - "text": " function.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 17, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "cancellation.md", - "nodes": [ - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#WithCancel", - "href": "https://pkg.go.dev/context#WithCancel", - "target": "_blank" - }, - "file": "cancellation.md", - "nodes": [ - { - "atom": "code", - "file": "cancellation.md", - "nodes": [ - { - "text": "context.WithCancel", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#WithCancel" - } - ], - { - "text": " function returns a second argument, that of a ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#CancelFunc", - "href": "https://pkg.go.dev/context#CancelFunc", - "target": "_blank" - }, - "file": "cancellation.md", - "nodes": [ - { - "atom": "code", - "file": "cancellation.md", - "nodes": [ - { - "text": "context.CancelFunc", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#CancelFunc" - } - ], - { - "text": " function, which can be used to cancel the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "cancellation.md", - "nodes": [ - { - "atom": "code", - "file": "cancellation.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h3", - "file": "cancellation.md", - "level": 3, - "nodes": [ - { - "text": "The Cancel Function", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "cancellation.md", - "nodes": [ - { - "text": "There a few things that need to be noted about the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#CancelFunc", - "href": "https://pkg.go.dev/context#CancelFunc", - "target": "_blank" - }, - "file": "cancellation.md", - "nodes": [ - { - "atom": "code", - "file": "cancellation.md", - "nodes": [ - { - "text": "context.CancelFunc", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#CancelFunc" - } - ], - { - "text": " function, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-18" - }, - "file": "cancellation.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-18" - }, - "nodes": [ - { - "text": "Listing 1.18", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-18" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ". So let's examine each in more detail.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-18", - "type": "listing" - }, - "file": "cancellation.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "doc", - "context.CancelFunc" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "doc": "context.CancelFunc", - "exec": "go doc context.CancelFunc" - }, - "expected_exit": 0, - "file": "cancellation", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc context.CancelFunc\n\npackage context // import \u0026#34;context\u0026#34;\n\ntype CancelFunc func()\n A CancelFunc tells an operation to abandon its work. A CancelFunc does not\n wait for the work to stop. A CancelFunc may be called by multiple goroutines\n simultaneously. After the first call, subsequent calls to a CancelFunc do\n nothing.", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "context.CancelFunc" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBjb250ZXh0IC8vIGltcG9ydCAiY29udGV4dCIKCnR5cGUgQ2FuY2VsRnVuYyBmdW5jKCkKICAgIEEgQ2FuY2VsRnVuYyB0ZWxscyBhbiBvcGVyYXRpb24gdG8gYWJhbmRvbiBpdHMgd29yay4gQSBDYW5jZWxGdW5jIGRvZXMgbm90CiAgICB3YWl0IGZvciB0aGUgd29yayB0byBzdG9wLiBBIENhbmNlbEZ1bmMgbWF5IGJlIGNhbGxlZCBieSBtdWx0aXBsZSBnb3JvdXRpbmVzCiAgICBzaW11bHRhbmVvdXNseS4gQWZ0ZXIgdGhlIGZpcnN0IGNhbGwsIHN1YnNlcXVlbnQgY2FsbHMgdG8gYSBDYW5jZWxGdW5jIGRvCiAgICBub3RoaW5nLg==", - "duration": 318657084, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc context.CancelFunc\n\npackage context // import \u0026#34;context\u0026#34;\n\ntype CancelFunc func()\n A CancelFunc tells an operation to abandon its work. A CancelFunc does not\n wait for the work to stop. A CancelFunc may be called by multiple goroutines\n simultaneously. After the first call, subsequent calls to a CancelFunc do\n nothing.", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "context.CancelFunc" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBjb250ZXh0IC8vIGltcG9ydCAiY29udGV4dCIKCnR5cGUgQ2FuY2VsRnVuYyBmdW5jKCkKICAgIEEgQ2FuY2VsRnVuYyB0ZWxscyBhbiBvcGVyYXRpb24gdG8gYWJhbmRvbiBpdHMgd29yay4gQSBDYW5jZWxGdW5jIGRvZXMgbm90CiAgICB3YWl0IGZvciB0aGUgd29yayB0byBzdG9wLiBBIENhbmNlbEZ1bmMgbWF5IGJlIGNhbGxlZCBieSBtdWx0aXBsZSBnb3JvdXRpbmVzCiAgICBzaW11bHRhbmVvdXNseS4gQWZ0ZXIgdGhlIGZpcnN0IGNhbGwsIHN1YnNlcXVlbnQgY2FsbHMgdG8gYSBDYW5jZWxGdW5jIGRvCiAgICBub3RoaW5nLg==", - "duration": 318657084, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "cancellation", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.18:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#CancelFunc", - "href": "https://pkg.go.dev/context#CancelFunc", - "target": "_blank" - }, - "file": "cancellation", - "nodes": [ - [ - { - "atom": "code", - "file": "cancellation", - "nodes": [ - { - "text": "context.CancelFunc", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#CancelFunc" - } - ], - { - "text": " function.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 18, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h4", - "file": "cancellation.md", - "level": 4, - "nodes": [ - { - "text": "Idempotent Behavior", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - { - "atom": "blockquote", - "file": "cancellation.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "cancellation.md", - "nodes": [ - { - "text": "\"After the first call, subsequent calls to a CancelFunc do nothing\".", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "cancellation.md", - "nodes": [ - { - "text": "According to the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#CancelFunc", - "href": "https://pkg.go.dev/context#CancelFunc", - "target": "_blank" - }, - "file": "cancellation.md", - "nodes": [ - { - "atom": "code", - "file": "cancellation.md", - "nodes": [ - { - "text": "context.CancelFunc", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#CancelFunc" - } - ], - { - "text": " documentation, the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#CancelFunc", - "href": "https://pkg.go.dev/context#CancelFunc", - "target": "_blank" - }, - "file": "cancellation.md", - "nodes": [ - { - "atom": "code", - "file": "cancellation.md", - "nodes": [ - { - "text": "context.CancelFunc", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#CancelFunc" - } - ], - { - "text": " function is ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "href": "https://en.wikipedia.org/wiki/Idempotence", - "target": "_blank" - }, - "file": "cancellation.md", - "nodes": [ - { - "text": "idempotent", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "https://en.wikipedia.org/wiki/Idempotence" - } - ], - { - "text": ", ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-19" - }, - "file": "cancellation.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-19" - }, - "nodes": [ - { - "text": "Listing 1.19", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-19" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ". That is, calling it multiple times has no effect beyond the first call.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-19", - "type": "listing" - }, - "file": "cancellation.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "cancellation", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go" - }, - "file": "cancellation", - "lang": "go", - "nodes": [ - { - "text": "ctx, cancel := context.WithCancel(context.Background())\ncancel() // cancels the context\ncancel() // has no effect\ncancel() // has no effect\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "cancellation", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.19:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The idempotent behavior of the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#CancelFunc", - "href": "https://pkg.go.dev/context#CancelFunc", - "target": "_blank" - }, - "file": "cancellation", - "nodes": [ - [ - { - "atom": "code", - "file": "cancellation", - "nodes": [ - { - "text": "context.CancelFunc", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#CancelFunc" - } - ], - { - "text": " function.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 19, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h4", - "file": "cancellation.md", - "level": 4, - "nodes": [ - { - "text": "Leaking Resources", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - { - "atom": "blockquote", - "file": "cancellation.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "cancellation.md", - "nodes": [ - { - "text": "\"Canceling this context releases resources associated with it, so code should call cancel as soon as the operations running in this Context complete.\"", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "cancellation.md", - "nodes": [ - { - "text": "Often you will want to defer execution of the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#CancelFunc", - "href": "https://pkg.go.dev/context#CancelFunc", - "target": "_blank" - }, - "file": "cancellation.md", - "nodes": [ - { - "atom": "code", - "file": "cancellation.md", - "nodes": [ - { - "text": "context.CancelFunc", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#CancelFunc" - } - ], - { - "text": " function until the function, or application, exits. This ensure proper shutdown of the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "cancellation.md", - "nodes": [ - { - "atom": "code", - "file": "cancellation.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": " and prevents the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "cancellation.md", - "nodes": [ - { - "atom": "code", - "file": "cancellation.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": " from leaking resources.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-20", - "type": "listing" - }, - "file": "cancellation.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "cancellation", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go" - }, - "file": "cancellation", - "lang": "go", - "nodes": [ - { - "text": "ctx, cancel := context.WithCancel(context.Background())\n// ensure the cancel function is called at least once\n// to avoid leaking resources\ndefer cancel()\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "cancellation", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.20:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Prevent leaking goroutines by calling the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#CancelFunc", - "href": "https://pkg.go.dev/context#CancelFunc", - "target": "_blank" - }, - "file": "cancellation", - "nodes": [ - [ - { - "atom": "code", - "file": "cancellation", - "nodes": [ - { - "text": "context.CancelFunc", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#CancelFunc" - } - ] - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 20, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - { - "atom": "blockquote", - "file": "cancellation.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "cancellation.md", - "nodes": [ - { - "atom": "strong", - "file": "cancellation.md", - "nodes": [ - { - "text": "ALWAYS", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " call the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#CancelFunc", - "href": "https://pkg.go.dev/context#CancelFunc", - "target": "_blank" - }, - "file": "cancellation.md", - "nodes": [ - { - "atom": "code", - "file": "cancellation.md", - "nodes": [ - { - "text": "context.CancelFunc", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#CancelFunc" - } - ], - { - "text": " function when you no longer need the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "cancellation.md", - "nodes": [ - { - "atom": "code", - "file": "cancellation.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": ". Failure to do so may cause your program to leak resources.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "cancellation.md", - "level": 2, - "nodes": [ - { - "text": "Cancelling a Context", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "cancellation.md", - "nodes": [ - { - "text": "Consider ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-21" - }, - "file": "cancellation.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-21" - }, - "nodes": [ - { - "text": "Listing 1.21", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-21" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ". The ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "cancellation.md", - "nodes": [ - { - "text": "listener", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function takes a ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "cancellation.md", - "nodes": [ - { - "atom": "code", - "file": "cancellation.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": " as its first argument and an ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "cancellation.md", - "nodes": [ - { - "text": "int", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " representing the goroutine id as its second argument.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "cancellation.md", - "nodes": [ - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "cancellation.md", - "nodes": [ - { - "text": "listener", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function will block until the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "cancellation.md", - "nodes": [ - { - "atom": "code", - "file": "cancellation.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": " is cancelled, which close the channel behind ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context.Done", - "href": "https://pkg.go.dev/context#Context.Done", - "target": "_blank" - }, - "file": "cancellation.md", - "nodes": [ - { - "atom": "code", - "file": "cancellation.md", - "nodes": [ - { - "text": "context.Context.Done", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context.Done" - } - ], - { - "text": " method. This will unblock the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "cancellation.md", - "nodes": [ - { - "text": "listener", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function and allow it to exit.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-21", - "type": "listing" - }, - "file": "cancellation.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "cancellation", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "cancellation/src/basic/main.go#listener" - }, - "lang": "go", - "nodes": [ - { - "content": "func listener(ctx context.Context, i int) {\n\tfmt.Printf(\"listener %d is waiting\\n\", i)\n\n\t// this will block until the context\n\t// given context is canceled\n\t\u003c-ctx.Done()\n\n\tfmt.Printf(\"listener %d is exiting\\n\", i)\n}", - "file": "cancellation/src/basic/main.go", - "lang": "go", - "name": "listener", - "start": 9, - "end": 20, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "cancellation", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.21:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Blocking on ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context.Done", - "href": "https://pkg.go.dev/context#Context.Done", - "target": "_blank" - }, - "file": "cancellation", - "nodes": [ - [ - { - "atom": "code", - "file": "cancellation", - "nodes": [ - { - "text": "context.Context.Done", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context.Done" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 21, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "cancellation.md", - "nodes": [ - { - "text": "wThe application creates a ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Background", - "href": "https://pkg.go.dev/context#Background", - "target": "_blank" - }, - "file": "cancellation.md", - "nodes": [ - { - "atom": "code", - "file": "cancellation.md", - "nodes": [ - { - "text": "context.Background", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Background" - } - ], - { - "text": " context and then wraps it with a cancellable ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "cancellation.md", - "nodes": [ - { - "atom": "code", - "file": "cancellation.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": ". The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#CancelFunc", - "href": "https://pkg.go.dev/context#CancelFunc", - "target": "_blank" - }, - "file": "cancellation.md", - "nodes": [ - { - "atom": "code", - "file": "cancellation.md", - "nodes": [ - { - "text": "context.CancelFunc", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#CancelFunc" - } - ], - { - "text": " returned by is immediately deferred to ensure the application doesn't leak any resources.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "cancellation.md", - "nodes": [ - { - "text": "In ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-22" - }, - "file": "cancellation.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-22" - }, - "nodes": [ - { - "text": "Listing 1.22", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-22" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": " we create several goroutines that will listen for the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "cancellation.md", - "nodes": [ - { - "atom": "code", - "file": "cancellation.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": " to be cancelled.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-22", - "type": "listing" - }, - "file": "cancellation.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "cancellation", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "cancellation/src/basic/main.go#main" - }, - "lang": "go", - "nodes": [ - { - "content": "func main() {\n\n\t// create a background context\n\tctx := context.Background()\n\n\t// wrap the context with the ability\n\t// to cancel it\n\tctx, cancel := context.WithCancel(ctx)\n\n\t// defer cancellation of the context\n\t// to ensure that any resources are\n\t// cleaned up regardless of how the\n\t// function exits\n\tdefer cancel()\n\n\t// create 5 listeners\n\tfor i := 0; i \u003c 5; i++ {\n\n\t\t// launch listener in a goroutine\n\t\tgo listener(ctx, i)\n\n\t}\n\n\t// allow the listeners to start\n\ttime.Sleep(time.Millisecond * 500)\n\n\tfmt.Println(\"canceling the context\")\n\n\t// cancel the context and tell the\n\t// listeners to exit\n\tcancel()\n\n\t// allow the listeners to exit\n\ttime.Sleep(time.Millisecond * 500)\n}", - "file": "cancellation/src/basic/main.go", - "lang": "go", - "name": "main", - "start": 22, - "end": 59, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "cancellation", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.22:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Using context cancellation.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 22, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "cancellation.md", - "nodes": [ - { - "text": "As we can see from the output, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-23" - }, - "file": "cancellation.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-23" - }, - "nodes": [ - { - "text": "Listing 1.23", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-23" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "cancellation.md", - "nodes": [ - { - "text": "listener", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function unblocks and exits when the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#CancelFunc", - "href": "https://pkg.go.dev/context#CancelFunc", - "target": "_blank" - }, - "file": "cancellation.md", - "nodes": [ - { - "atom": "code", - "file": "cancellation.md", - "nodes": [ - { - "text": "context.CancelFunc", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#CancelFunc" - } - ], - { - "text": " is called, ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "cancellation.md", - "nodes": [ - { - "text": "cancel()", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-23", - "type": "listing" - }, - "file": "cancellation.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "run", - "main.go" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go run main.go", - "run": "main.go", - "src": "cancellation/src/basic" - }, - "expected_exit": 0, - "file": "cancellation", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run main.go\n\nlistener 2 is waiting\nlistener 4 is waiting\nlistener 3 is waiting\nlistener 0 is waiting\nlistener 1 is waiting\ncanceling the context\nlistener 2 is exiting\nlistener 3 is exiting\nlistener 4 is exiting\nlistener 1 is exiting\nlistener 0 is exiting", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "main.go" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/12-context/cancellation/src/basic", - "stdout": "bGlzdGVuZXIgMiBpcyB3YWl0aW5nCmxpc3RlbmVyIDQgaXMgd2FpdGluZwpsaXN0ZW5lciAzIGlzIHdhaXRpbmcKbGlzdGVuZXIgMCBpcyB3YWl0aW5nCmxpc3RlbmVyIDEgaXMgd2FpdGluZwpjYW5jZWxpbmcgdGhlIGNvbnRleHQKbGlzdGVuZXIgMiBpcyBleGl0aW5nCmxpc3RlbmVyIDMgaXMgZXhpdGluZwpsaXN0ZW5lciA0IGlzIGV4aXRpbmcKbGlzdGVuZXIgMSBpcyBleGl0aW5nCmxpc3RlbmVyIDAgaXMgZXhpdGluZw==", - "duration": 2259160167, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run main.go\n\nlistener 2 is waiting\nlistener 4 is waiting\nlistener 3 is waiting\nlistener 0 is waiting\nlistener 1 is waiting\ncanceling the context\nlistener 2 is exiting\nlistener 3 is exiting\nlistener 4 is exiting\nlistener 1 is exiting\nlistener 0 is exiting", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "main.go" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/12-context/cancellation/src/basic", - "stdout": "bGlzdGVuZXIgMiBpcyB3YWl0aW5nCmxpc3RlbmVyIDQgaXMgd2FpdGluZwpsaXN0ZW5lciAzIGlzIHdhaXRpbmcKbGlzdGVuZXIgMCBpcyB3YWl0aW5nCmxpc3RlbmVyIDEgaXMgd2FpdGluZwpjYW5jZWxpbmcgdGhlIGNvbnRleHQKbGlzdGVuZXIgMiBpcyBleGl0aW5nCmxpc3RlbmVyIDMgaXMgZXhpdGluZwpsaXN0ZW5lciA0IGlzIGV4aXRpbmcKbGlzdGVuZXIgMSBpcyBleGl0aW5nCmxpc3RlbmVyIDAgaXMgZXhpdGluZw==", - "duration": 2259160167, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "cancellation", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.23:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The output of the application.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 23, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h3", - "file": "cancellation.md", - "level": 3, - "nodes": [ - { - "text": "Only Child Nodes of the Context are Cancelled", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "cancellation.md", - "nodes": [ - { - "text": "The illustration in ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-24" - }, - "file": "cancellation.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-24" - }, - "nodes": [ - { - "text": "Listing 1.24", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-24" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": " shows that by cancelling a node in the hierarchy, all its child nodes are also cancelled. Other nodes, such as parent and sibling nodes, in the hierarchy are unaffected.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-24", - "type": "listing" - }, - "file": "cancellation.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "img", - "attributes": { - "src": "cancellation/assets/cancellation.svg" - }, - "file": "cancellation", - "type": "*hype.Image" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "cancellation", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.24:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Cancellation propagation.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 24, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "cancellation.md", - "level": 2, - "nodes": [ - { - "text": "Listening for Cancellation Confirmation", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "cancellation.md", - "nodes": [ - { - "text": "Previously, we have use ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "time#Sleep", - "href": "https://pkg.go.dev/time#Sleep", - "target": "_blank" - }, - "file": "cancellation.md", - "nodes": [ - { - "atom": "code", - "file": "cancellation.md", - "nodes": [ - { - "text": "time.Sleep", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/time#Sleep" - } - ], - { - "text": " to block the execution of the program. This is not a good practice, as it can lead to deadlocks and other problems. Instead, the application should receive a ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "cancellation.md", - "nodes": [ - { - "atom": "code", - "file": "cancellation.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": " cancellation confirmation.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h3", - "file": "cancellation.md", - "level": 3, - "nodes": [ - { - "text": "Starting a Concurrent Monitor", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "cancellation.md", - "nodes": [ - { - "text": "Consider ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-25" - }, - "file": "cancellation.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-25" - }, - "nodes": [ - { - "text": "Listing 1.25", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-25" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ". To start a ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "cancellation.md", - "nodes": [ - { - "text": "Monitor", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " we must use the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "cancellation.md", - "nodes": [ - { - "text": "Start", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " method giving it a ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "cancellation.md", - "nodes": [ - { - "atom": "code", - "file": "cancellation.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": ". In return, the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "cancellation.md", - "nodes": [ - { - "text": "Start", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " method returns a ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "cancellation.md", - "nodes": [ - { - "atom": "code", - "file": "cancellation.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": " that can be listened to by the application to confirm the shutdown of the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "cancellation.md", - "nodes": [ - { - "text": "Monitor", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " later on.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-25", - "type": "listing" - }, - "file": "cancellation.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "cancellation", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "cancellation/src/cancelling/main.go#start" - }, - "lang": "go", - "nodes": [ - { - "content": "type Monitor struct {\n\tcancel context.CancelFunc\n}\n\nfunc (m *Monitor) Start(ctx context.Context) context.Context {\n\n\t// start the monitor with the given context\n\tgo m.listen(ctx)\n\n\t// create a new context that will be canceled\n\t// when the monitor is shut down\n\tctx, cancel := context.WithCancel(context.Background())\n\n\t// hold on to the cancellation function\n\t// when context that started the manager is canceled\n\t// this cancellation function will be called.\n\tm.cancel = cancel\n\n\t// return the new, cancellable, context.\n\t// clients can listen to this context\n\t// for cancellation to ensure the\n\t// monitor is properly shut down.\n\treturn ctx\n}", - "file": "cancellation/src/cancelling/main.go", - "lang": "go", - "name": "start", - "start": 10, - "end": 36, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "cancellation", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.25:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Accepting a ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "cancellation", - "nodes": [ - [ - { - "atom": "code", - "file": "cancellation", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": " and returning a new one.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 25, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "cancellation.md", - "nodes": [ - { - "text": "To prevent the application from blocking, we launch a the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "cancellation.md", - "nodes": [ - { - "text": "listen", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " method in a goroutine with the given ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "cancellation.md", - "nodes": [ - { - "atom": "code", - "file": "cancellation.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": ". Unless this ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "cancellation.md", - "nodes": [ - { - "atom": "code", - "file": "cancellation.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": " is cancelled, the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "cancellation.md", - "nodes": [ - { - "text": "listen", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " method will never stop and will continue to leak resources until the application exits.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "cancellation.md", - "nodes": [ - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#CancelFunc", - "href": "https://pkg.go.dev/context#CancelFunc", - "target": "_blank" - }, - "file": "cancellation.md", - "nodes": [ - { - "atom": "code", - "file": "cancellation.md", - "nodes": [ - { - "text": "context.CancelFunc", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#CancelFunc" - } - ], - { - "text": " is held onto by the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "cancellation.md", - "nodes": [ - { - "text": "Manager", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " so when the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "cancellation.md", - "nodes": [ - { - "text": "Manager", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " is told to cancel by the client, it will also cancel the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "cancellation.md", - "nodes": [ - { - "text": "Monitor", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " context. This will tell the client that the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "cancellation.md", - "nodes": [ - { - "text": "Monitor", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " has been shutdown, confirming the cancellation of the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "cancellation.md", - "nodes": [ - { - "text": "Monitor", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h3", - "file": "cancellation.md", - "level": 3, - "nodes": [ - { - "text": "Monitor Checking", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "cancellation.md", - "nodes": [ - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "cancellation.md", - "nodes": [ - { - "text": "listen", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " method will block until the given ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "cancellation.md", - "nodes": [ - { - "atom": "code", - "file": "cancellation.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": ", given by the application, is cancelled, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-26" - }, - "file": "cancellation.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-26" - }, - "nodes": [ - { - "text": "Listing 1.26", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-26" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ". We first make sure to defer the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#CancelFunc", - "href": "https://pkg.go.dev/context#CancelFunc", - "target": "_blank" - }, - "file": "cancellation.md", - "nodes": [ - { - "atom": "code", - "file": "cancellation.md", - "nodes": [ - { - "text": "context.CancelFunc", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#CancelFunc" - } - ], - { - "text": " in the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "cancellation.md", - "nodes": [ - { - "text": "Monitor", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " to ensure that if any the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "cancellation.md", - "nodes": [ - { - "text": "listen", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " method exits for any reason, clients will be notified that the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "cancellation.md", - "nodes": [ - { - "text": "Monitor", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " has been shutdown.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-26", - "type": "listing" - }, - "file": "cancellation.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "cancellation", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "cancellation/src/cancelling/main.go#listen" - }, - "lang": "go", - "nodes": [ - { - "content": "func (m *Monitor) listen(ctx context.Context) {\n\tdefer m.cancel()\n\n\t// create a new ticker channel to listen to\n\ttick := time.NewTicker(time.Millisecond * 10)\n\tdefer tick.Stop()\n\n\t// use an infinite loop to continue to listen\n\t// to new messages after the select statement\n\t// has been executed\n\tfor {\n\t\tselect {\n\t\tcase \u003c-ctx.Done(): // listen for context cancellation\n\t\t\t// shut down if the context is canceled\n\t\t\tfmt.Println(\"shutting down monitor\")\n\n\t\t\t// if the monitor was told to shut down\n\t\t\t// then it should call its cancel function\n\t\t\t// so the client will know that the monitor\n\t\t\t// has properly shut down.\n\t\t\tm.cancel()\n\n\t\t\t// return from the function\n\t\t\treturn\n\t\tcase \u003c-tick.C: // listen to the ticker channel\n\t\t\t// and print a message every time it ticks\n\t\t\tfmt.Println(\"monitor check\")\n\t\t}\n\t}\n\n}", - "file": "cancellation/src/cancelling/main.go", - "lang": "go", - "name": "listen", - "start": 38, - "end": 71, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "cancellation", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.26:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "cancellation", - "nodes": [ - { - "text": "Monitor", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " will call its ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#CancelFunc", - "href": "https://pkg.go.dev/context#CancelFunc", - "target": "_blank" - }, - "file": "cancellation", - "nodes": [ - [ - { - "atom": "code", - "file": "cancellation", - "nodes": [ - { - "text": "context.CancelFunc", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#CancelFunc" - } - ], - { - "text": " if external ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "cancellation", - "nodes": [ - [ - { - "atom": "code", - "file": "cancellation", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": " is cancelled.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 26, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h3", - "file": "cancellation.md", - "level": 3, - "nodes": [ - { - "text": "Using the Cancellation Confirmation", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "cancellation.md", - "nodes": [ - { - "text": "In ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-27" - }, - "file": "cancellation.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-27" - }, - "nodes": [ - { - "text": "Listing 1.27", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-27" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", the application starts with a ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Background", - "href": "https://pkg.go.dev/context#Background", - "target": "_blank" - }, - "file": "cancellation.md", - "nodes": [ - { - "atom": "code", - "file": "cancellation.md", - "nodes": [ - { - "text": "context.Background", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Background" - } - ], - { - "text": " context and then wraps that with a cancellable ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "cancellation.md", - "nodes": [ - { - "atom": "code", - "file": "cancellation.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": ". The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#CancelFunc", - "href": "https://pkg.go.dev/context#CancelFunc", - "target": "_blank" - }, - "file": "cancellation.md", - "nodes": [ - { - "atom": "code", - "file": "cancellation.md", - "nodes": [ - { - "text": "context.CancelFunc", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#CancelFunc" - } - ], - { - "text": " returned by is immediately deferred to ensure the application doesn't leak any resources. After a short while, in a goroutine, the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "cancellation.md", - "nodes": [ - { - "text": "cancel", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function is called, the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "cancellation.md", - "nodes": [ - { - "atom": "code", - "file": "cancellation.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": " is cancelled.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "cancellation.md", - "nodes": [ - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "cancellation.md", - "nodes": [ - { - "text": "Monitor", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " is then started our cancellable ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "cancellation.md", - "nodes": [ - { - "atom": "code", - "file": "cancellation.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": ". The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "cancellation.md", - "nodes": [ - { - "atom": "code", - "file": "cancellation.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": " returned by the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "cancellation.md", - "nodes": [ - { - "text": "Start", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " method is listened to by the application. When the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "cancellation.md", - "nodes": [ - { - "text": "Monitor", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " is cancelled, the application will be unblocked and can exit. Alternatively, if the application is still running after a couple of seconds the application is forcibly terminated.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-27", - "type": "listing" - }, - "file": "cancellation.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "cancellation", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "cancellation/src/cancelling/main.go#main" - }, - "lang": "go", - "nodes": [ - { - "content": "func main() {\n\n\t// create a new background context\n\tctx := context.Background()\n\n\t// wrap the background context with a\n\t// cancellable context.\n\t// this context can be listened to any\n\t// children of this context for notification\n\t// of application shutdown/cancellation.\n\tctx, cancel := context.WithCancel(ctx)\n\n\t// ensure the cancel function is called\n\t// to shut down the monitor when the program\n\t// is exits\n\tdefer cancel()\n\n\t// launch a goroutine to cancel the application\n\t// context after a short while.\n\tgo func() {\n\t\ttime.Sleep(time.Millisecond * 50)\n\n\t\t// cancel the application context\n\t\t// this will shut the monitor down\n\t\tcancel()\n\t}()\n\n\t// create a new monitor\n\tmon := Monitor{}\n\n\t// start the monitor with the application context\n\t// this will return a context that can be listened to\n\t// for cancellation signaling the monitor has shut down.\n\tctx = mon.Start(ctx)\n\n\t// block the application until either the context\n\t// is canceled or the application times out\n\tselect {\n\tcase \u003c-ctx.Done(): // listen for context cancellation\n\t\t// success shutdown\n\t\tos.Exit(0)\n\tcase \u003c-time.After(time.Second * 2): // timeout after 2 second\n\t\tfmt.Println(\"timed out while trying to shut down the monitor\")\n\n\t\t// check if there was an error from the\n\t\t// monitor's context\n\t\tif err := ctx.Err(); err != nil {\n\t\t\tfmt.Printf(\"error: %s\\n\", err)\n\t\t}\n\n\t\t// non-successful shutdown\n\t\tos.Exit(1)\n\t}\n}", - "file": "cancellation/src/cancelling/main.go", - "lang": "go", - "name": "main", - "start": 73, - "end": 129, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "cancellation", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.27:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Using the cancellation confirmation.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 27, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "cancellation.md", - "nodes": [ - { - "text": "As we can see from the output, in ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-28" - }, - "file": "cancellation.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-28" - }, - "nodes": [ - { - "text": "Listing 1.28", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-28" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", the application waits for the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "cancellation.md", - "nodes": [ - { - "text": "Monitor", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " to properly shutdown before exiting. We were also able to remove the use of ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "time#Sleep", - "href": "https://pkg.go.dev/time#Sleep", - "target": "_blank" - }, - "file": "cancellation.md", - "nodes": [ - { - "atom": "code", - "file": "cancellation.md", - "nodes": [ - { - "text": "time.Sleep", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/time#Sleep" - } - ], - { - "text": " to allow the monitor to finish.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-28", - "type": "listing" - }, - "file": "cancellation.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "run", - "main.go" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go run main.go", - "run": "main.go", - "src": "cancellation/src/cancelling" - }, - "expected_exit": 0, - "file": "cancellation", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run main.go\n\nmonitor check\nmonitor check\nmonitor check\nmonitor check\nmonitor check\nshutting down monitor", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "main.go" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/12-context/cancellation/src/cancelling", - "stdout": "bW9uaXRvciBjaGVjawptb25pdG9yIGNoZWNrCm1vbml0b3IgY2hlY2sKbW9uaXRvciBjaGVjawptb25pdG9yIGNoZWNrCnNodXR0aW5nIGRvd24gbW9uaXRvcg==", - "duration": 1376769000, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run main.go\n\nmonitor check\nmonitor check\nmonitor check\nmonitor check\nmonitor check\nshutting down monitor", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "main.go" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/12-context/cancellation/src/cancelling", - "stdout": "bW9uaXRvciBjaGVjawptb25pdG9yIGNoZWNrCm1vbml0b3IgY2hlY2sKbW9uaXRvciBjaGVjawptb25pdG9yIGNoZWNrCnNodXR0aW5nIGRvd24gbW9uaXRvcg==", - "duration": 1376769000, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "cancellation", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.28:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The output of the application.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 28, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "title": "Cancellation Propagation with Contexts", - "type": "*hype.Page" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "type": "*hype.Include" - } - ], - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "include", - "attributes": { - "src": "timeouts/timeouts.md" - }, - "dir": "timeouts", - "file": "module.md", - "nodes": [ - [ - { - "atom": "page", - "file": "timeouts.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "h1", - "file": "timeouts.md", - "level": 1, - "nodes": [ - { - "text": "Timeouts and Deadlines", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "timeouts.md", - "nodes": [ - { - "text": "In addition to allowing us to manually cancel a ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "timeouts.md", - "nodes": [ - { - "atom": "code", - "file": "timeouts.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": ", the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context", - "href": "https://pkg.go.dev/context", - "target": "_blank" - }, - "file": "timeouts.md", - "nodes": [ - { - "atom": "code", - "file": "timeouts.md", - "nodes": [ - { - "text": "context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context" - } - ], - { - "text": " package also provides mechanisms for creating a ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "timeouts.md", - "nodes": [ - { - "atom": "code", - "file": "timeouts.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": " that will self-cancel after, or at, a given time. Using these mechanics allows us to control how long to run some before we give up and assume that the operation has failed.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "timeouts.md", - "level": 2, - "nodes": [ - { - "text": "Cancelling at a Specific Time", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "timeouts.md", - "nodes": [ - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context", - "href": "https://pkg.go.dev/context", - "target": "_blank" - }, - "file": "timeouts.md", - "nodes": [ - { - "atom": "code", - "file": "timeouts.md", - "nodes": [ - { - "text": "context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context" - } - ], - { - "text": " package provides two functions for creating time based, self-cancelling, a ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "timeouts.md", - "nodes": [ - { - "atom": "code", - "file": "timeouts.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": "; ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#WithTimeout", - "href": "https://pkg.go.dev/context#WithTimeout", - "target": "_blank" - }, - "file": "timeouts.md", - "nodes": [ - { - "atom": "code", - "file": "timeouts.md", - "nodes": [ - { - "text": "context.WithTimeout", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#WithTimeout" - } - ], - { - "text": " and ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#WithDeadline", - "href": "https://pkg.go.dev/context#WithDeadline", - "target": "_blank" - }, - "file": "timeouts.md", - "nodes": [ - { - "atom": "code", - "file": "timeouts.md", - "nodes": [ - { - "text": "context.WithDeadline", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#WithDeadline" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-29", - "type": "listing" - }, - "file": "timeouts.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "doc", - "context.WithDeadline" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "doc": "context.WithDeadline", - "exec": "go doc context.WithDeadline" - }, - "expected_exit": 0, - "file": "timeouts", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc context.WithDeadline\n\npackage context // import \u0026#34;context\u0026#34;\n\nfunc WithDeadline(parent Context, d time.Time) (Context, CancelFunc)\n WithDeadline returns a copy of the parent context with the deadline\n adjusted to be no later than d. If the parent\u0026#39;s deadline is already earlier\n than d, WithDeadline(parent, d) is semantically equivalent to parent.\n The returned [Context.Done] channel is closed when the deadline expires,\n when the returned cancel function is called, or when the parent context\u0026#39;s\n Done channel is closed, whichever happens first.\n\n Canceling this context releases resources associated with it, so code should\n call cancel as soon as the operations running in this Context complete.", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "context.WithDeadline" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBjb250ZXh0IC8vIGltcG9ydCAiY29udGV4dCIKCmZ1bmMgV2l0aERlYWRsaW5lKHBhcmVudCBDb250ZXh0LCBkIHRpbWUuVGltZSkgKENvbnRleHQsIENhbmNlbEZ1bmMpCiAgICBXaXRoRGVhZGxpbmUgcmV0dXJucyBhIGNvcHkgb2YgdGhlIHBhcmVudCBjb250ZXh0IHdpdGggdGhlIGRlYWRsaW5lCiAgICBhZGp1c3RlZCB0byBiZSBubyBsYXRlciB0aGFuIGQuIElmIHRoZSBwYXJlbnQncyBkZWFkbGluZSBpcyBhbHJlYWR5IGVhcmxpZXIKICAgIHRoYW4gZCwgV2l0aERlYWRsaW5lKHBhcmVudCwgZCkgaXMgc2VtYW50aWNhbGx5IGVxdWl2YWxlbnQgdG8gcGFyZW50LgogICAgVGhlIHJldHVybmVkIFtDb250ZXh0LkRvbmVdIGNoYW5uZWwgaXMgY2xvc2VkIHdoZW4gdGhlIGRlYWRsaW5lIGV4cGlyZXMsCiAgICB3aGVuIHRoZSByZXR1cm5lZCBjYW5jZWwgZnVuY3Rpb24gaXMgY2FsbGVkLCBvciB3aGVuIHRoZSBwYXJlbnQgY29udGV4dCdzCiAgICBEb25lIGNoYW5uZWwgaXMgY2xvc2VkLCB3aGljaGV2ZXIgaGFwcGVucyBmaXJzdC4KCiAgICBDYW5jZWxpbmcgdGhpcyBjb250ZXh0IHJlbGVhc2VzIHJlc291cmNlcyBhc3NvY2lhdGVkIHdpdGggaXQsIHNvIGNvZGUgc2hvdWxkCiAgICBjYWxsIGNhbmNlbCBhcyBzb29uIGFzIHRoZSBvcGVyYXRpb25zIHJ1bm5pbmcgaW4gdGhpcyBDb250ZXh0IGNvbXBsZXRlLg==", - "duration": 467507834, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc context.WithDeadline\n\npackage context // import \u0026#34;context\u0026#34;\n\nfunc WithDeadline(parent Context, d time.Time) (Context, CancelFunc)\n WithDeadline returns a copy of the parent context with the deadline\n adjusted to be no later than d. If the parent\u0026#39;s deadline is already earlier\n than d, WithDeadline(parent, d) is semantically equivalent to parent.\n The returned [Context.Done] channel is closed when the deadline expires,\n when the returned cancel function is called, or when the parent context\u0026#39;s\n Done channel is closed, whichever happens first.\n\n Canceling this context releases resources associated with it, so code should\n call cancel as soon as the operations running in this Context complete.", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "context.WithDeadline" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBjb250ZXh0IC8vIGltcG9ydCAiY29udGV4dCIKCmZ1bmMgV2l0aERlYWRsaW5lKHBhcmVudCBDb250ZXh0LCBkIHRpbWUuVGltZSkgKENvbnRleHQsIENhbmNlbEZ1bmMpCiAgICBXaXRoRGVhZGxpbmUgcmV0dXJucyBhIGNvcHkgb2YgdGhlIHBhcmVudCBjb250ZXh0IHdpdGggdGhlIGRlYWRsaW5lCiAgICBhZGp1c3RlZCB0byBiZSBubyBsYXRlciB0aGFuIGQuIElmIHRoZSBwYXJlbnQncyBkZWFkbGluZSBpcyBhbHJlYWR5IGVhcmxpZXIKICAgIHRoYW4gZCwgV2l0aERlYWRsaW5lKHBhcmVudCwgZCkgaXMgc2VtYW50aWNhbGx5IGVxdWl2YWxlbnQgdG8gcGFyZW50LgogICAgVGhlIHJldHVybmVkIFtDb250ZXh0LkRvbmVdIGNoYW5uZWwgaXMgY2xvc2VkIHdoZW4gdGhlIGRlYWRsaW5lIGV4cGlyZXMsCiAgICB3aGVuIHRoZSByZXR1cm5lZCBjYW5jZWwgZnVuY3Rpb24gaXMgY2FsbGVkLCBvciB3aGVuIHRoZSBwYXJlbnQgY29udGV4dCdzCiAgICBEb25lIGNoYW5uZWwgaXMgY2xvc2VkLCB3aGljaGV2ZXIgaGFwcGVucyBmaXJzdC4KCiAgICBDYW5jZWxpbmcgdGhpcyBjb250ZXh0IHJlbGVhc2VzIHJlc291cmNlcyBhc3NvY2lhdGVkIHdpdGggaXQsIHNvIGNvZGUgc2hvdWxkCiAgICBjYWxsIGNhbmNlbCBhcyBzb29uIGFzIHRoZSBvcGVyYXRpb25zIHJ1bm5pbmcgaW4gdGhpcyBDb250ZXh0IGNvbXBsZXRlLg==", - "duration": 467507834, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "timeouts", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.29:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#WithDeadline", - "href": "https://pkg.go.dev/context#WithDeadline", - "target": "_blank" - }, - "file": "timeouts", - "nodes": [ - [ - { - "atom": "code", - "file": "timeouts", - "nodes": [ - { - "text": "context.WithDeadline", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#WithDeadline" - } - ], - { - "text": " function.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 29, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "timeouts.md", - "nodes": [ - { - "text": "When using ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#WithDeadline", - "href": "https://pkg.go.dev/context#WithDeadline", - "target": "_blank" - }, - "file": "timeouts.md", - "nodes": [ - { - "atom": "code", - "file": "timeouts.md", - "nodes": [ - { - "text": "context.WithDeadline", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#WithDeadline" - } - ], - { - "text": ", ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-29" - }, - "file": "timeouts.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-29" - }, - "nodes": [ - { - "text": "Listing 1.29", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-29" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", we need to provide an ", - "type": "hype.Text" - }, - { - "atom": "strong", - "file": "timeouts.md", - "nodes": [ - { - "text": "absolute", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " time at which the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "timeouts.md", - "nodes": [ - { - "atom": "code", - "file": "timeouts.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": " should be cancelled. That means we need an exact date/time we want this ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "timeouts.md", - "nodes": [ - { - "atom": "code", - "file": "timeouts.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": " to be cancelled, for example ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "timeouts.md", - "nodes": [ - { - "text": "March 14, 2029 3:45pm", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "timeouts.md", - "nodes": [ - { - "text": "Consider ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-30" - }, - "file": "timeouts.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-30" - }, - "nodes": [ - { - "text": "Listing 1.30", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-30" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ". In it, we create a new ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "time#Time", - "href": "https://pkg.go.dev/time#Time", - "target": "_blank" - }, - "file": "timeouts.md", - "nodes": [ - { - "atom": "code", - "file": "timeouts.md", - "nodes": [ - { - "text": "time.Time", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/time#Time" - } - ], - { - "text": " for ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "timeouts.md", - "nodes": [ - { - "text": "January 1, 2030 00:00:00", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " and use it to create a ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "timeouts.md", - "nodes": [ - { - "atom": "code", - "file": "timeouts.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": " that will self-cancel at that date and time.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-30", - "type": "listing" - }, - "file": "timeouts.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "timeouts", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "timeouts/src/with-deadline/main.go#example" - }, - "lang": "go", - "nodes": [ - { - "content": "func main() {\n\n\t// create a background context\n\tctx := context.Background()\n\n\t// create an absolute date/time (January 1, 2030)\n\tdeadline := time.Date(2030, 1, 1, 0, 0, 0, 0, time.UTC)\n\tfmt.Println(\"deadline:\", deadline.Format(time.RFC3339))\n\n\t// create a new context with a deadline\n\t// that will cancel at January 1, 2030 00:00:00.\n\tctx, cancel := context.WithDeadline(ctx, deadline)\n\tdefer cancel()\n\n\tprint(ctx)\n}", - "file": "timeouts/src/with-deadline/main.go", - "lang": "go", - "name": "example", - "start": 12, - "end": 30, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "atom": "hr", - "file": "timeouts", - "type": "*hype.Element" - }, - [ - { - "args": [ - "go", - "run", - "." - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go run .", - "run": ".", - "src": "timeouts/src/with-deadline" - }, - "expected_exit": 0, - "file": "timeouts", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\ndeadline: 2030-01-01T00:00:00Z\nWithTimeout(deadline: {wall:0 ext:64029052800 loc:\u0026lt;nil\u0026gt;})\n\t--\u0026gt; context.backgroundCtx", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/12-context/timeouts/src/with-deadline", - "stdout": "ZGVhZGxpbmU6IDIwMzAtMDEtMDFUMDA6MDA6MDBaCldpdGhUaW1lb3V0KGRlYWRsaW5lOiB7d2FsbDowIGV4dDo2NDAyOTA1MjgwMCBsb2M6PG5pbD59KQoJLS0+IGNvbnRleHQuYmFja2dyb3VuZEN0eA==", - "duration": 991547208, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\ndeadline: 2030-01-01T00:00:00Z\nWithTimeout(deadline: {wall:0 ext:64029052800 loc:\u0026lt;nil\u0026gt;})\n\t--\u0026gt; context.backgroundCtx", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/12-context/timeouts/src/with-deadline", - "stdout": "ZGVhZGxpbmU6IDIwMzAtMDEtMDFUMDA6MDA6MDBaCldpdGhUaW1lb3V0KGRlYWRsaW5lOiB7d2FsbDowIGV4dDo2NDAyOTA1MjgwMCBsb2M6PG5pbD59KQoJLS0+IGNvbnRleHQuYmFja2dyb3VuZEN0eA==", - "duration": 991547208, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "timeouts", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.30:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Using ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#WithDeadline", - "href": "https://pkg.go.dev/context#WithDeadline", - "target": "_blank" - }, - "file": "timeouts", - "nodes": [ - [ - { - "atom": "code", - "file": "timeouts", - "nodes": [ - { - "text": "context.WithDeadline", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#WithDeadline" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 30, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "timeouts.md", - "level": 2, - "nodes": [ - { - "text": "Cancelling After a Duration", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "timeouts.md", - "nodes": [ - { - "text": "While being able to cancel a ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "timeouts.md", - "nodes": [ - { - "atom": "code", - "file": "timeouts.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": " at a particular time is useful, more often than not we want to cancel a ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "timeouts.md", - "nodes": [ - { - "atom": "code", - "file": "timeouts.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": " after a certain amount of time has passed.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-31", - "type": "listing" - }, - "file": "timeouts.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "doc", - "context.WithTimeout" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "doc": "context.WithTimeout", - "exec": "go doc context.WithTimeout" - }, - "expected_exit": 0, - "file": "timeouts", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc context.WithTimeout\n\npackage context // import \u0026#34;context\u0026#34;\n\nfunc WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc)\n WithTimeout returns WithDeadline(parent, time.Now().Add(timeout)).\n\n Canceling this context releases resources associated with it, so code should\n call cancel as soon as the operations running in this Context complete:\n\n func slowOperationWithTimeout(ctx context.Context) (Result, error) {\n \tctx, cancel := context.WithTimeout(ctx, 100*time.Millisecond)\n \tdefer cancel() // releases resources if slowOperation completes before timeout elapses\n \treturn slowOperation(ctx)\n }", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "context.WithTimeout" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBjb250ZXh0IC8vIGltcG9ydCAiY29udGV4dCIKCmZ1bmMgV2l0aFRpbWVvdXQocGFyZW50IENvbnRleHQsIHRpbWVvdXQgdGltZS5EdXJhdGlvbikgKENvbnRleHQsIENhbmNlbEZ1bmMpCiAgICBXaXRoVGltZW91dCByZXR1cm5zIFdpdGhEZWFkbGluZShwYXJlbnQsIHRpbWUuTm93KCkuQWRkKHRpbWVvdXQpKS4KCiAgICBDYW5jZWxpbmcgdGhpcyBjb250ZXh0IHJlbGVhc2VzIHJlc291cmNlcyBhc3NvY2lhdGVkIHdpdGggaXQsIHNvIGNvZGUgc2hvdWxkCiAgICBjYWxsIGNhbmNlbCBhcyBzb29uIGFzIHRoZSBvcGVyYXRpb25zIHJ1bm5pbmcgaW4gdGhpcyBDb250ZXh0IGNvbXBsZXRlOgoKICAgICAgICBmdW5jIHNsb3dPcGVyYXRpb25XaXRoVGltZW91dChjdHggY29udGV4dC5Db250ZXh0KSAoUmVzdWx0LCBlcnJvcikgewogICAgICAgIAljdHgsIGNhbmNlbCA6PSBjb250ZXh0LldpdGhUaW1lb3V0KGN0eCwgMTAwKnRpbWUuTWlsbGlzZWNvbmQpCiAgICAgICAgCWRlZmVyIGNhbmNlbCgpICAvLyByZWxlYXNlcyByZXNvdXJjZXMgaWYgc2xvd09wZXJhdGlvbiBjb21wbGV0ZXMgYmVmb3JlIHRpbWVvdXQgZWxhcHNlcwogICAgICAgIAlyZXR1cm4gc2xvd09wZXJhdGlvbihjdHgpCiAgICAgICAgfQ==", - "duration": 398923000, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc context.WithTimeout\n\npackage context // import \u0026#34;context\u0026#34;\n\nfunc WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc)\n WithTimeout returns WithDeadline(parent, time.Now().Add(timeout)).\n\n Canceling this context releases resources associated with it, so code should\n call cancel as soon as the operations running in this Context complete:\n\n func slowOperationWithTimeout(ctx context.Context) (Result, error) {\n \tctx, cancel := context.WithTimeout(ctx, 100*time.Millisecond)\n \tdefer cancel() // releases resources if slowOperation completes before timeout elapses\n \treturn slowOperation(ctx)\n }", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "context.WithTimeout" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBjb250ZXh0IC8vIGltcG9ydCAiY29udGV4dCIKCmZ1bmMgV2l0aFRpbWVvdXQocGFyZW50IENvbnRleHQsIHRpbWVvdXQgdGltZS5EdXJhdGlvbikgKENvbnRleHQsIENhbmNlbEZ1bmMpCiAgICBXaXRoVGltZW91dCByZXR1cm5zIFdpdGhEZWFkbGluZShwYXJlbnQsIHRpbWUuTm93KCkuQWRkKHRpbWVvdXQpKS4KCiAgICBDYW5jZWxpbmcgdGhpcyBjb250ZXh0IHJlbGVhc2VzIHJlc291cmNlcyBhc3NvY2lhdGVkIHdpdGggaXQsIHNvIGNvZGUgc2hvdWxkCiAgICBjYWxsIGNhbmNlbCBhcyBzb29uIGFzIHRoZSBvcGVyYXRpb25zIHJ1bm5pbmcgaW4gdGhpcyBDb250ZXh0IGNvbXBsZXRlOgoKICAgICAgICBmdW5jIHNsb3dPcGVyYXRpb25XaXRoVGltZW91dChjdHggY29udGV4dC5Db250ZXh0KSAoUmVzdWx0LCBlcnJvcikgewogICAgICAgIAljdHgsIGNhbmNlbCA6PSBjb250ZXh0LldpdGhUaW1lb3V0KGN0eCwgMTAwKnRpbWUuTWlsbGlzZWNvbmQpCiAgICAgICAgCWRlZmVyIGNhbmNlbCgpICAvLyByZWxlYXNlcyByZXNvdXJjZXMgaWYgc2xvd09wZXJhdGlvbiBjb21wbGV0ZXMgYmVmb3JlIHRpbWVvdXQgZWxhcHNlcwogICAgICAgIAlyZXR1cm4gc2xvd09wZXJhdGlvbihjdHgpCiAgICAgICAgfQ==", - "duration": 398923000, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "timeouts", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.31:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#WithTimeout", - "href": "https://pkg.go.dev/context#WithTimeout", - "target": "_blank" - }, - "file": "timeouts", - "nodes": [ - [ - { - "atom": "code", - "file": "timeouts", - "nodes": [ - { - "text": "context.WithTimeout", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#WithTimeout" - } - ], - { - "text": " function.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 31, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "timeouts.md", - "nodes": [ - { - "text": "When using ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#WithTimeout", - "href": "https://pkg.go.dev/context#WithTimeout", - "target": "_blank" - }, - "file": "timeouts.md", - "nodes": [ - { - "atom": "code", - "file": "timeouts.md", - "nodes": [ - { - "text": "context.WithTimeout", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#WithTimeout" - } - ], - { - "text": ", ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-31" - }, - "file": "timeouts.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-31" - }, - "nodes": [ - { - "text": "Listing 1.31", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-31" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": "a, we need to provide an ", - "type": "hype.Text" - }, - { - "atom": "strong", - "file": "timeouts.md", - "nodes": [ - { - "text": "relative", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "time#Duration", - "href": "https://pkg.go.dev/time#Duration", - "target": "_blank" - }, - "file": "timeouts.md", - "nodes": [ - { - "atom": "code", - "file": "timeouts.md", - "nodes": [ - { - "text": "time.Duration", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/time#Duration" - } - ], - { - "text": " at which the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "timeouts.md", - "nodes": [ - { - "atom": "code", - "file": "timeouts.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": " should be cancelled.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "timeouts.md", - "nodes": [ - { - "text": "Consider ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-32" - }, - "file": "timeouts.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-32" - }, - "nodes": [ - { - "text": "Listing 1.32", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-32" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ". In it, we create a new self-cancelling ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "timeouts.md", - "nodes": [ - { - "atom": "code", - "file": "timeouts.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": " that will self-cancel after 5 seconds using ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#WithTimeout", - "href": "https://pkg.go.dev/context#WithTimeout", - "target": "_blank" - }, - "file": "timeouts.md", - "nodes": [ - { - "atom": "code", - "file": "timeouts.md", - "nodes": [ - { - "text": "context.WithTimeout", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#WithTimeout" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-32", - "type": "listing" - }, - "file": "timeouts.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "timeouts", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "timeouts/src/with-timeout/main.go#example" - }, - "lang": "go", - "nodes": [ - { - "content": "func main() {\n\n\t// create a background context\n\tctx := context.Background()\n\n\t// create a new context with a timeout\n\t// that will cancel the context after 10ms\n\t// \tequivalent to:\n\t//\t\tcontext.WithDeadline(ctx, time.Now().Add(10 *time.Millisecond))\n\tctx, cancel := context.WithTimeout(ctx, 10*time.Millisecond)\n\tdefer cancel()\n\n\tprint(ctx)\n}", - "file": "timeouts/src/with-timeout/main.go", - "lang": "go", - "name": "example", - "start": 11, - "end": 27, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "atom": "hr", - "file": "timeouts", - "type": "*hype.Element" - }, - [ - { - "args": [ - "go", - "run", - "." - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go run .", - "run": ".", - "src": "timeouts/src/with-timeout" - }, - "expected_exit": 0, - "file": "timeouts", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\nWithTimeout(deadline: {wall:13936422476539130464 ext:10202001 loc:0x1009f5aa0})\n\t--\u0026gt; context.backgroundCtx", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/12-context/timeouts/src/with-timeout", - "stdout": "V2l0aFRpbWVvdXQoZGVhZGxpbmU6IHt3YWxsOjEzOTM2NDIyNDc2NTM5MTMwNDY0IGV4dDoxMDIwMjAwMSBsb2M6MHgxMDA5ZjVhYTB9KQoJLS0+IGNvbnRleHQuYmFja2dyb3VuZEN0eA==", - "duration": 923255208, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\nWithTimeout(deadline: {wall:13936422476539130464 ext:10202001 loc:0x1009f5aa0})\n\t--\u0026gt; context.backgroundCtx", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/12-context/timeouts/src/with-timeout", - "stdout": "V2l0aFRpbWVvdXQoZGVhZGxpbmU6IHt3YWxsOjEzOTM2NDIyNDc2NTM5MTMwNDY0IGV4dDoxMDIwMjAwMSBsb2M6MHgxMDA5ZjVhYTB9KQoJLS0+IGNvbnRleHQuYmFja2dyb3VuZEN0eA==", - "duration": 923255208, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "timeouts", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.32:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Using ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#WithTimeout", - "href": "https://pkg.go.dev/context#WithTimeout", - "target": "_blank" - }, - "file": "timeouts", - "nodes": [ - [ - { - "atom": "code", - "file": "timeouts", - "nodes": [ - { - "text": "context.WithTimeout", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#WithTimeout" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 32, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "timeouts.md", - "nodes": [ - { - "text": "Functionally, we could have used ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#WithDeadline", - "href": "https://pkg.go.dev/context#WithDeadline", - "target": "_blank" - }, - "file": "timeouts.md", - "nodes": [ - { - "atom": "code", - "file": "timeouts.md", - "nodes": [ - { - "text": "context.WithDeadline", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#WithDeadline" - } - ], - { - "text": " instead, but ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#WithTimeout", - "href": "https://pkg.go.dev/context#WithTimeout", - "target": "_blank" - }, - "file": "timeouts.md", - "nodes": [ - { - "atom": "code", - "file": "timeouts.md", - "nodes": [ - { - "text": "context.WithTimeout", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#WithTimeout" - } - ], - { - "text": " is more convenient when we want to cancel a ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "timeouts.md", - "nodes": [ - { - "atom": "code", - "file": "timeouts.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": " after a certain amount of time has passed.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "title": "Timeouts and Deadlines", - "type": "*hype.Page" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "type": "*hype.Include" - } - ], - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "include", - "attributes": { - "src": "errors/errors.md" - }, - "dir": "errors", - "file": "module.md", - "nodes": [ - [ - { - "atom": "page", - "file": "errors.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "h1", - "file": "errors.md", - "level": 1, - "nodes": [ - { - "text": "Context Errors", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "errors.md", - "nodes": [ - { - "text": "In a complex system, or even in a small one, when a ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "errors.md", - "nodes": [ - { - "atom": "code", - "file": "errors.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": " is cancelled, we need a way to know what caused the cancellation. It is possible that ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "errors.md", - "nodes": [ - { - "atom": "code", - "file": "errors.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": " was cancelled by a ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#CancelFunc", - "href": "https://pkg.go.dev/context#CancelFunc", - "target": "_blank" - }, - "file": "errors.md", - "nodes": [ - { - "atom": "code", - "file": "errors.md", - "nodes": [ - { - "text": "context.CancelFunc", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#CancelFunc" - } - ], - { - "text": " successfully, if it was cancelled because it timed out, or some other reason.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "errors.md", - "nodes": [ - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context.Err", - "href": "https://pkg.go.dev/context#Context.Err", - "target": "_blank" - }, - "file": "errors.md", - "nodes": [ - { - "atom": "code", - "file": "errors.md", - "nodes": [ - { - "text": "context.Context.Err", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context.Err" - } - ], - { - "text": " method, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-33" - }, - "file": "errors.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-33" - }, - "nodes": [ - { - "text": "Listing 1.33", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-33" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": " returns the error that caused the context to be cancelled.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-33", - "type": "listing" - }, - "file": "errors.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "doc", - "context.Context.Err" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "doc": "context.Context.Err", - "exec": "go doc context.Context.Err" - }, - "expected_exit": 0, - "file": "errors", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc context.Context.Err\n\npackage context // import \u0026#34;context\u0026#34;\n\ntype Context interface {\n\n\t// If Done is not yet closed, Err returns nil.\n\t// If Done is closed, Err returns a non-nil error explaining why:\n\t// Canceled if the context was canceled\n\t// or DeadlineExceeded if the context\u0026#39;s deadline passed.\n\t// After Err returns a non-nil error, successive calls to Err return the same error.\n\tErr() error\n}", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "context.Context.Err" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBjb250ZXh0IC8vIGltcG9ydCAiY29udGV4dCIKCnR5cGUgQ29udGV4dCBpbnRlcmZhY2UgewoKCS8vIElmIERvbmUgaXMgbm90IHlldCBjbG9zZWQsIEVyciByZXR1cm5zIG5pbC4KCS8vIElmIERvbmUgaXMgY2xvc2VkLCBFcnIgcmV0dXJucyBhIG5vbi1uaWwgZXJyb3IgZXhwbGFpbmluZyB3aHk6CgkvLyBDYW5jZWxlZCBpZiB0aGUgY29udGV4dCB3YXMgY2FuY2VsZWQKCS8vIG9yIERlYWRsaW5lRXhjZWVkZWQgaWYgdGhlIGNvbnRleHQncyBkZWFkbGluZSBwYXNzZWQuCgkvLyBBZnRlciBFcnIgcmV0dXJucyBhIG5vbi1uaWwgZXJyb3IsIHN1Y2Nlc3NpdmUgY2FsbHMgdG8gRXJyIHJldHVybiB0aGUgc2FtZSBlcnJvci4KCUVycigpIGVycm9yCn0=", - "duration": 539380417, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc context.Context.Err\n\npackage context // import \u0026#34;context\u0026#34;\n\ntype Context interface {\n\n\t// If Done is not yet closed, Err returns nil.\n\t// If Done is closed, Err returns a non-nil error explaining why:\n\t// Canceled if the context was canceled\n\t// or DeadlineExceeded if the context\u0026#39;s deadline passed.\n\t// After Err returns a non-nil error, successive calls to Err return the same error.\n\tErr() error\n}", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "context.Context.Err" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBjb250ZXh0IC8vIGltcG9ydCAiY29udGV4dCIKCnR5cGUgQ29udGV4dCBpbnRlcmZhY2UgewoKCS8vIElmIERvbmUgaXMgbm90IHlldCBjbG9zZWQsIEVyciByZXR1cm5zIG5pbC4KCS8vIElmIERvbmUgaXMgY2xvc2VkLCBFcnIgcmV0dXJucyBhIG5vbi1uaWwgZXJyb3IgZXhwbGFpbmluZyB3aHk6CgkvLyBDYW5jZWxlZCBpZiB0aGUgY29udGV4dCB3YXMgY2FuY2VsZWQKCS8vIG9yIERlYWRsaW5lRXhjZWVkZWQgaWYgdGhlIGNvbnRleHQncyBkZWFkbGluZSBwYXNzZWQuCgkvLyBBZnRlciBFcnIgcmV0dXJucyBhIG5vbi1uaWwgZXJyb3IsIHN1Y2Nlc3NpdmUgY2FsbHMgdG8gRXJyIHJldHVybiB0aGUgc2FtZSBlcnJvci4KCUVycigpIGVycm9yCn0=", - "duration": 539380417, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "errors", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.33:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context.Err", - "href": "https://pkg.go.dev/context#Context.Err", - "target": "_blank" - }, - "file": "errors", - "nodes": [ - [ - { - "atom": "code", - "file": "errors", - "nodes": [ - { - "text": "context.Context.Err", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context.Err" - } - ], - { - "text": " method.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 33, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "errors.md", - "level": 2, - "nodes": [ - { - "text": "Context Cancelled Error", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "errors.md", - "nodes": [ - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context", - "href": "https://pkg.go.dev/context", - "target": "_blank" - }, - "file": "errors.md", - "nodes": [ - { - "atom": "code", - "file": "errors.md", - "nodes": [ - { - "text": "context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context" - } - ], - { - "text": " package defines two different ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "builtin#error", - "href": "https://pkg.go.dev/builtin#error", - "target": "_blank" - }, - "file": "errors.md", - "nodes": [ - { - "atom": "code", - "file": "errors.md", - "nodes": [ - { - "text": "error", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/builtin#error" - } - ], - { - "text": " variables that can be used to check an ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "builtin#error", - "href": "https://pkg.go.dev/builtin#error", - "target": "_blank" - }, - "file": "errors.md", - "nodes": [ - { - "atom": "code", - "file": "errors.md", - "nodes": [ - { - "text": "error", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/builtin#error" - } - ], - { - "text": " that was returned from ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context.Err", - "href": "https://pkg.go.dev/context#Context.Err", - "target": "_blank" - }, - "file": "errors.md", - "nodes": [ - { - "atom": "code", - "file": "errors.md", - "nodes": [ - { - "text": "context.Context.Err", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context.Err" - } - ], - { - "text": " method.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "errors.md", - "nodes": [ - { - "text": "The first is ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Canceled", - "href": "https://pkg.go.dev/context#Canceled", - "target": "_blank" - }, - "file": "errors.md", - "nodes": [ - { - "atom": "code", - "file": "errors.md", - "nodes": [ - { - "text": "context.Canceled", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Canceled" - } - ], - { - "text": ", ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-34" - }, - "file": "errors.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-34" - }, - "nodes": [ - { - "text": "Listing 1.34", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-34" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", which is returned when the context is cancelled through the use of a ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#CancelFunc", - "href": "https://pkg.go.dev/context#CancelFunc", - "target": "_blank" - }, - "file": "errors.md", - "nodes": [ - { - "atom": "code", - "file": "errors.md", - "nodes": [ - { - "text": "context.CancelFunc", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#CancelFunc" - } - ], - { - "text": " function. This ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "builtin#error", - "href": "https://pkg.go.dev/builtin#error", - "target": "_blank" - }, - "file": "errors.md", - "nodes": [ - { - "atom": "code", - "file": "errors.md", - "nodes": [ - { - "text": "error", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/builtin#error" - } - ], - { - "text": " is considered to indicate a \"successful\" cancellation.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-34", - "type": "listing" - }, - "file": "errors.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "doc", - "context.Canceled" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "doc": "context.Canceled", - "exec": "go doc context.Canceled" - }, - "expected_exit": 0, - "file": "errors", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc context.Canceled\n\npackage context // import \u0026#34;context\u0026#34;\n\nvar Canceled = errors.New(\u0026#34;context canceled\u0026#34;)\n Canceled is the error returned by [Context.Err] when the context is\n canceled.", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "context.Canceled" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBjb250ZXh0IC8vIGltcG9ydCAiY29udGV4dCIKCnZhciBDYW5jZWxlZCA9IGVycm9ycy5OZXcoImNvbnRleHQgY2FuY2VsZWQiKQogICAgQ2FuY2VsZWQgaXMgdGhlIGVycm9yIHJldHVybmVkIGJ5IFtDb250ZXh0LkVycl0gd2hlbiB0aGUgY29udGV4dCBpcwogICAgY2FuY2VsZWQu", - "duration": 391154208, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc context.Canceled\n\npackage context // import \u0026#34;context\u0026#34;\n\nvar Canceled = errors.New(\u0026#34;context canceled\u0026#34;)\n Canceled is the error returned by [Context.Err] when the context is\n canceled.", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "context.Canceled" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBjb250ZXh0IC8vIGltcG9ydCAiY29udGV4dCIKCnZhciBDYW5jZWxlZCA9IGVycm9ycy5OZXcoImNvbnRleHQgY2FuY2VsZWQiKQogICAgQ2FuY2VsZWQgaXMgdGhlIGVycm9yIHJldHVybmVkIGJ5IFtDb250ZXh0LkVycl0gd2hlbiB0aGUgY29udGV4dCBpcwogICAgY2FuY2VsZWQu", - "duration": 391154208, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "errors", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.34:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Canceled", - "href": "https://pkg.go.dev/context#Canceled", - "target": "_blank" - }, - "file": "errors", - "nodes": [ - [ - { - "atom": "code", - "file": "errors", - "nodes": [ - { - "text": "context.Canceled", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Canceled" - } - ], - { - "text": " ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "builtin#error", - "href": "https://pkg.go.dev/builtin#error", - "target": "_blank" - }, - "file": "errors", - "nodes": [ - [ - { - "atom": "code", - "file": "errors", - "nodes": [ - { - "text": "error", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/builtin#error" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 34, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "errors.md", - "nodes": [ - { - "text": "Consider ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-35" - }, - "file": "errors.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-35" - }, - "nodes": [ - { - "text": "Listing 1.35", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-35" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ". When we first check the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context.Err", - "href": "https://pkg.go.dev/context#Context.Err", - "target": "_blank" - }, - "file": "errors.md", - "nodes": [ - { - "atom": "code", - "file": "errors.md", - "nodes": [ - { - "text": "context.Context.Err", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context.Err" - } - ], - { - "text": " method, it returns ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "errors.md", - "nodes": [ - { - "text": "nil", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ". After we call the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#CancelFunc", - "href": "https://pkg.go.dev/context#CancelFunc", - "target": "_blank" - }, - "file": "errors.md", - "nodes": [ - { - "atom": "code", - "file": "errors.md", - "nodes": [ - { - "text": "context.CancelFunc", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#CancelFunc" - } - ], - { - "text": " function provided by ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#WithCancel", - "href": "https://pkg.go.dev/context#WithCancel", - "target": "_blank" - }, - "file": "errors.md", - "nodes": [ - { - "atom": "code", - "file": "errors.md", - "nodes": [ - { - "text": "context.WithCancel", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#WithCancel" - } - ], - { - "text": ", the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context.Err", - "href": "https://pkg.go.dev/context#Context.Err", - "target": "_blank" - }, - "file": "errors.md", - "nodes": [ - { - "atom": "code", - "file": "errors.md", - "nodes": [ - { - "text": "context.Context.Err", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context.Err" - } - ], - { - "text": " method returns a ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Canceled", - "href": "https://pkg.go.dev/context#Canceled", - "target": "_blank" - }, - "file": "errors.md", - "nodes": [ - { - "atom": "code", - "file": "errors.md", - "nodes": [ - { - "text": "context.Canceled", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Canceled" - } - ], - { - "text": " error.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-35", - "type": "listing" - }, - "file": "errors.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "errors", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "errors/src/canceled/main.go#example" - }, - "lang": "go", - "nodes": [ - { - "content": "func main() {\n\n\t// create a background context\n\tctx := context.Background()\n\n\t// wrap the context with a\n\t// cancellable context\n\tctx, cancel := context.WithCancel(ctx)\n\n\t// check the error:\n\t//\t\u003cnil\u003e\n\tfmt.Println(\"ctx.Err()\", ctx.Err())\n\n\t// cancel the context\n\tcancel()\n\n\t// check the error:\n\t//\tcontext.Canceled\n\tfmt.Println(\"ctx.Err()\", ctx.Err())\n\n\t// check the error again:\n\t//\tcontext.Canceled\n\tfmt.Println(\"ctx.Err()\", ctx.Err())\n}", - "file": "errors/src/canceled/main.go", - "lang": "go", - "name": "example", - "start": 8, - "end": 34, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "atom": "hr", - "file": "errors", - "type": "*hype.Element" - }, - [ - { - "args": [ - "go", - "run", - "." - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go run .", - "run": ".", - "src": "errors/src/canceled" - }, - "expected_exit": 0, - "file": "errors", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\nctx.Err() \u0026lt;nil\u0026gt;\nctx.Err() context canceled\nctx.Err() context canceled", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/12-context/errors/src/canceled", - "stdout": "Y3R4LkVycigpIDxuaWw+CmN0eC5FcnIoKSBjb250ZXh0IGNhbmNlbGVkCmN0eC5FcnIoKSBjb250ZXh0IGNhbmNlbGVk", - "duration": 1124147209, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\nctx.Err() \u0026lt;nil\u0026gt;\nctx.Err() context canceled\nctx.Err() context canceled", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/12-context/errors/src/canceled", - "stdout": "Y3R4LkVycigpIDxuaWw+CmN0eC5FcnIoKSBjb250ZXh0IGNhbmNlbGVkCmN0eC5FcnIoKSBjb250ZXh0IGNhbmNlbGVk", - "duration": 1124147209, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "errors", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.35:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Checking for cancellation errors.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 35, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "errors.md", - "nodes": [ - { - "text": "As we can see from the output in ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-35" - }, - "file": "errors.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-35" - }, - "nodes": [ - { - "text": "Listing 1.35", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-35" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", repeated calls to the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context.Err", - "href": "https://pkg.go.dev/context#Context.Err", - "target": "_blank" - }, - "file": "errors.md", - "nodes": [ - { - "atom": "code", - "file": "errors.md", - "nodes": [ - { - "text": "context.Context.Err", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context.Err" - } - ], - { - "text": " method return the same ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Canceled", - "href": "https://pkg.go.dev/context#Canceled", - "target": "_blank" - }, - "file": "errors.md", - "nodes": [ - { - "atom": "code", - "file": "errors.md", - "nodes": [ - { - "text": "context.Canceled", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Canceled" - } - ], - { - "text": " error.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "errors.md", - "level": 2, - "nodes": [ - { - "text": "Context Deadline Exceeded Error", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "errors.md", - "nodes": [ - { - "text": "When a ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "errors.md", - "nodes": [ - { - "atom": "code", - "file": "errors.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": " is cancelled due to a deadline, or timeout, being exceeded, the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context.Err", - "href": "https://pkg.go.dev/context#Context.Err", - "target": "_blank" - }, - "file": "errors.md", - "nodes": [ - { - "atom": "code", - "file": "errors.md", - "nodes": [ - { - "text": "context.Context.Err", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context.Err" - } - ], - { - "text": " method returns a ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#DeadlineExceeded", - "href": "https://pkg.go.dev/context#DeadlineExceeded", - "target": "_blank" - }, - "file": "errors.md", - "nodes": [ - { - "atom": "code", - "file": "errors.md", - "nodes": [ - { - "text": "context.DeadlineExceeded", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#DeadlineExceeded" - } - ], - { - "text": " error, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-36" - }, - "file": "errors.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-36" - }, - "nodes": [ - { - "text": "Listing 1.36", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-36" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-36", - "type": "listing" - }, - "file": "errors.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "doc", - "context.DeadlineExceeded" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "doc": "context.DeadlineExceeded", - "exec": "go doc context.DeadlineExceeded" - }, - "expected_exit": 0, - "file": "errors", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc context.DeadlineExceeded\n\npackage context // import \u0026#34;context\u0026#34;\n\nvar DeadlineExceeded error = deadlineExceededError{}\n DeadlineExceeded is the error returned by [Context.Err] when the context\u0026#39;s\n deadline passes.", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "context.DeadlineExceeded" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBjb250ZXh0IC8vIGltcG9ydCAiY29udGV4dCIKCnZhciBEZWFkbGluZUV4Y2VlZGVkIGVycm9yID0gZGVhZGxpbmVFeGNlZWRlZEVycm9ye30KICAgIERlYWRsaW5lRXhjZWVkZWQgaXMgdGhlIGVycm9yIHJldHVybmVkIGJ5IFtDb250ZXh0LkVycl0gd2hlbiB0aGUgY29udGV4dCdzCiAgICBkZWFkbGluZSBwYXNzZXMu", - "duration": 533793500, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc context.DeadlineExceeded\n\npackage context // import \u0026#34;context\u0026#34;\n\nvar DeadlineExceeded error = deadlineExceededError{}\n DeadlineExceeded is the error returned by [Context.Err] when the context\u0026#39;s\n deadline passes.", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "context.DeadlineExceeded" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBjb250ZXh0IC8vIGltcG9ydCAiY29udGV4dCIKCnZhciBEZWFkbGluZUV4Y2VlZGVkIGVycm9yID0gZGVhZGxpbmVFeGNlZWRlZEVycm9ye30KICAgIERlYWRsaW5lRXhjZWVkZWQgaXMgdGhlIGVycm9yIHJldHVybmVkIGJ5IFtDb250ZXh0LkVycl0gd2hlbiB0aGUgY29udGV4dCdzCiAgICBkZWFkbGluZSBwYXNzZXMu", - "duration": 533793500, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "errors", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.36:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#DeadlineExceeded", - "href": "https://pkg.go.dev/context#DeadlineExceeded", - "target": "_blank" - }, - "file": "errors", - "nodes": [ - [ - { - "atom": "code", - "file": "errors", - "nodes": [ - { - "text": "context.DeadlineExceeded", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#DeadlineExceeded" - } - ], - { - "text": " ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "builtin#error", - "href": "https://pkg.go.dev/builtin#error", - "target": "_blank" - }, - "file": "errors", - "nodes": [ - [ - { - "atom": "code", - "file": "errors", - "nodes": [ - { - "text": "error", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/builtin#error" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 36, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "errors.md", - "nodes": [ - { - "text": "Consider ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-37" - }, - "file": "errors.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-37" - }, - "nodes": [ - { - "text": "Listing 1.37", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-37" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ". We create a ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "errors.md", - "nodes": [ - { - "atom": "code", - "file": "errors.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": " that will self cancel after 1 second. When we check ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context.Err", - "href": "https://pkg.go.dev/context#Context.Err", - "target": "_blank" - }, - "file": "errors.md", - "nodes": [ - { - "atom": "code", - "file": "errors.md", - "nodes": [ - { - "text": "context.Context.Err", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context.Err" - } - ], - { - "text": " method, before the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "errors.md", - "nodes": [ - { - "atom": "code", - "file": "errors.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": " times out, it returns ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "errors.md", - "nodes": [ - { - "text": "nil", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-37", - "type": "listing" - }, - "file": "errors.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "errors", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "errors/src/deadline/main.go#example" - }, - "lang": "go", - "nodes": [ - { - "content": "func main() {\n\n\t// create a background context\n\tctx := context.Background()\n\n\t// wrap the context that will\n\t// self cancel after 10 milliseconds\n\tctx, cancel := context.WithTimeout(ctx, 10*time.Millisecond)\n\tdefer cancel()\n\n\t// check the error:\n\t//\t\u003cnil\u003e\n\tfmt.Println(\"ctx.Err()\", ctx.Err())\n\n\t// wait for the context to self cancel\n\t\u003c-ctx.Done()\n\n\t// check the error:\n\t//\tcontext.Canceled\n\tfmt.Println(\"ctx.Err()\", ctx.Err())\n\n\t// check the error again:\n\t//\tcontext.DeadlineExceeded\n\tfmt.Println(\"ctx.Err()\", ctx.Err())\n}", - "file": "errors/src/deadline/main.go", - "lang": "go", - "name": "example", - "start": 9, - "end": 36, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "atom": "hr", - "file": "errors", - "type": "*hype.Element" - }, - [ - { - "args": [ - "go", - "run", - "." - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go run .", - "run": ".", - "src": "errors/src/deadline" - }, - "expected_exit": 0, - "file": "errors", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\nctx.Err() \u0026lt;nil\u0026gt;\nctx.Err() context deadline exceeded\nctx.Err() context deadline exceeded", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/12-context/errors/src/deadline", - "stdout": "Y3R4LkVycigpIDxuaWw+CmN0eC5FcnIoKSBjb250ZXh0IGRlYWRsaW5lIGV4Y2VlZGVkCmN0eC5FcnIoKSBjb250ZXh0IGRlYWRsaW5lIGV4Y2VlZGVk", - "duration": 716619125, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\nctx.Err() \u0026lt;nil\u0026gt;\nctx.Err() context deadline exceeded\nctx.Err() context deadline exceeded", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/12-context/errors/src/deadline", - "stdout": "Y3R4LkVycigpIDxuaWw+CmN0eC5FcnIoKSBjb250ZXh0IGRlYWRsaW5lIGV4Y2VlZGVkCmN0eC5FcnIoKSBjb250ZXh0IGRlYWRsaW5lIGV4Y2VlZGVk", - "duration": 716619125, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "errors", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.37:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Checking for deadline exceeded errors.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 37, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "errors.md", - "nodes": [ - { - "text": "As we can see from the output, the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "errors.md", - "nodes": [ - { - "atom": "code", - "file": "errors.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": " times out after the specified time, and the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context.Err", - "href": "https://pkg.go.dev/context#Context.Err", - "target": "_blank" - }, - "file": "errors.md", - "nodes": [ - { - "atom": "code", - "file": "errors.md", - "nodes": [ - { - "text": "context.Context.Err", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context.Err" - } - ], - { - "text": " method returns a ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#DeadlineExceeded", - "href": "https://pkg.go.dev/context#DeadlineExceeded", - "target": "_blank" - }, - "file": "errors.md", - "nodes": [ - { - "atom": "code", - "file": "errors.md", - "nodes": [ - { - "text": "context.DeadlineExceeded", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#DeadlineExceeded" - } - ], - { - "text": " error.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "title": "Context Errors", - "type": "*hype.Page" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "type": "*hype.Include" - } - ], - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "include", - "attributes": { - "src": "signals/signals.md" - }, - "dir": "signals", - "file": "module.md", - "nodes": [ - [ - { - "atom": "page", - "file": "signals.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "h1", - "file": "signals.md", - "level": 1, - "nodes": [ - { - "text": "Listening for System Signals with Context", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "signals.md", - "nodes": [ - { - "text": "Previously, when discussing channels, we saw how to capture system signals, such as ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "signals.md", - "nodes": [ - { - "text": "ctrl-c", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ", using ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "os/signal#Notify", - "href": "https://pkg.go.dev/os/signal#Notify", - "target": "_blank" - }, - "file": "signals.md", - "nodes": [ - { - "atom": "code", - "file": "signals.md", - "nodes": [ - { - "text": "signal.Notify", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/os/signal#Notify" - } - ], - { - "text": ". The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "os/signal#NotifyContext", - "href": "https://pkg.go.dev/os/signal#NotifyContext", - "target": "_blank" - }, - "file": "signals.md", - "nodes": [ - { - "atom": "code", - "file": "signals.md", - "nodes": [ - { - "text": "signal.NotifyContext", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/os/signal#NotifyContext" - } - ], - { - "text": " function, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-38" - }, - "file": "signals.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-38" - }, - "nodes": [ - { - "text": "Listing 1.38", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-38" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", is a variant of ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "os/signal#Notify", - "href": "https://pkg.go.dev/os/signal#Notify", - "target": "_blank" - }, - "file": "signals.md", - "nodes": [ - { - "atom": "code", - "file": "signals.md", - "nodes": [ - { - "text": "signal.Notify", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/os/signal#Notify" - } - ], - { - "text": " that takes a ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "signals.md", - "nodes": [ - { - "atom": "code", - "file": "signals.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": " as an argument. In return, we are given a ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "signals.md", - "nodes": [ - { - "atom": "code", - "file": "signals.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": " that will be canceled when the signal is received.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-38", - "type": "listing" - }, - "file": "signals.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "doc", - "os/signal.NotifyContext" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "doc": "os/signal.NotifyContext", - "exec": "go doc os/signal.NotifyContext" - }, - "expected_exit": 0, - "file": "signals", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc os/signal.NotifyContext\n\npackage signal // import \u0026#34;os/signal\u0026#34;\n\nfunc NotifyContext(parent context.Context, signals ...os.Signal) (ctx context.Context, stop context.CancelFunc)\n NotifyContext returns a copy of the parent context that is marked done (its\n Done channel is closed) when one of the listed signals arrives, when the\n returned stop function is called, or when the parent context\u0026#39;s Done channel\n is closed, whichever happens first.\n\n The stop function unregisters the signal behavior, which, like signal.Reset,\n may restore the default behavior for a given signal. For example,\n the default behavior of a Go program receiving os.Interrupt is to exit.\n Calling NotifyContext(parent, os.Interrupt) will change the behavior to\n cancel the returned context. Future interrupts received will not trigger the\n default (exit) behavior until the returned stop function is called.\n\n The stop function releases resources associated with it, so code should call\n stop as soon as the operations running in this Context complete and signals\n no longer need to be diverted to the context.", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "os/signal.NotifyContext" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBzaWduYWwgLy8gaW1wb3J0ICJvcy9zaWduYWwiCgpmdW5jIE5vdGlmeUNvbnRleHQocGFyZW50IGNvbnRleHQuQ29udGV4dCwgc2lnbmFscyAuLi5vcy5TaWduYWwpIChjdHggY29udGV4dC5Db250ZXh0LCBzdG9wIGNvbnRleHQuQ2FuY2VsRnVuYykKICAgIE5vdGlmeUNvbnRleHQgcmV0dXJucyBhIGNvcHkgb2YgdGhlIHBhcmVudCBjb250ZXh0IHRoYXQgaXMgbWFya2VkIGRvbmUgKGl0cwogICAgRG9uZSBjaGFubmVsIGlzIGNsb3NlZCkgd2hlbiBvbmUgb2YgdGhlIGxpc3RlZCBzaWduYWxzIGFycml2ZXMsIHdoZW4gdGhlCiAgICByZXR1cm5lZCBzdG9wIGZ1bmN0aW9uIGlzIGNhbGxlZCwgb3Igd2hlbiB0aGUgcGFyZW50IGNvbnRleHQncyBEb25lIGNoYW5uZWwKICAgIGlzIGNsb3NlZCwgd2hpY2hldmVyIGhhcHBlbnMgZmlyc3QuCgogICAgVGhlIHN0b3AgZnVuY3Rpb24gdW5yZWdpc3RlcnMgdGhlIHNpZ25hbCBiZWhhdmlvciwgd2hpY2gsIGxpa2Ugc2lnbmFsLlJlc2V0LAogICAgbWF5IHJlc3RvcmUgdGhlIGRlZmF1bHQgYmVoYXZpb3IgZm9yIGEgZ2l2ZW4gc2lnbmFsLiBGb3IgZXhhbXBsZSwKICAgIHRoZSBkZWZhdWx0IGJlaGF2aW9yIG9mIGEgR28gcHJvZ3JhbSByZWNlaXZpbmcgb3MuSW50ZXJydXB0IGlzIHRvIGV4aXQuCiAgICBDYWxsaW5nIE5vdGlmeUNvbnRleHQocGFyZW50LCBvcy5JbnRlcnJ1cHQpIHdpbGwgY2hhbmdlIHRoZSBiZWhhdmlvciB0bwogICAgY2FuY2VsIHRoZSByZXR1cm5lZCBjb250ZXh0LiBGdXR1cmUgaW50ZXJydXB0cyByZWNlaXZlZCB3aWxsIG5vdCB0cmlnZ2VyIHRoZQogICAgZGVmYXVsdCAoZXhpdCkgYmVoYXZpb3IgdW50aWwgdGhlIHJldHVybmVkIHN0b3AgZnVuY3Rpb24gaXMgY2FsbGVkLgoKICAgIFRoZSBzdG9wIGZ1bmN0aW9uIHJlbGVhc2VzIHJlc291cmNlcyBhc3NvY2lhdGVkIHdpdGggaXQsIHNvIGNvZGUgc2hvdWxkIGNhbGwKICAgIHN0b3AgYXMgc29vbiBhcyB0aGUgb3BlcmF0aW9ucyBydW5uaW5nIGluIHRoaXMgQ29udGV4dCBjb21wbGV0ZSBhbmQgc2lnbmFscwogICAgbm8gbG9uZ2VyIG5lZWQgdG8gYmUgZGl2ZXJ0ZWQgdG8gdGhlIGNvbnRleHQu", - "duration": 435073958, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc os/signal.NotifyContext\n\npackage signal // import \u0026#34;os/signal\u0026#34;\n\nfunc NotifyContext(parent context.Context, signals ...os.Signal) (ctx context.Context, stop context.CancelFunc)\n NotifyContext returns a copy of the parent context that is marked done (its\n Done channel is closed) when one of the listed signals arrives, when the\n returned stop function is called, or when the parent context\u0026#39;s Done channel\n is closed, whichever happens first.\n\n The stop function unregisters the signal behavior, which, like signal.Reset,\n may restore the default behavior for a given signal. For example,\n the default behavior of a Go program receiving os.Interrupt is to exit.\n Calling NotifyContext(parent, os.Interrupt) will change the behavior to\n cancel the returned context. Future interrupts received will not trigger the\n default (exit) behavior until the returned stop function is called.\n\n The stop function releases resources associated with it, so code should call\n stop as soon as the operations running in this Context complete and signals\n no longer need to be diverted to the context.", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "os/signal.NotifyContext" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBzaWduYWwgLy8gaW1wb3J0ICJvcy9zaWduYWwiCgpmdW5jIE5vdGlmeUNvbnRleHQocGFyZW50IGNvbnRleHQuQ29udGV4dCwgc2lnbmFscyAuLi5vcy5TaWduYWwpIChjdHggY29udGV4dC5Db250ZXh0LCBzdG9wIGNvbnRleHQuQ2FuY2VsRnVuYykKICAgIE5vdGlmeUNvbnRleHQgcmV0dXJucyBhIGNvcHkgb2YgdGhlIHBhcmVudCBjb250ZXh0IHRoYXQgaXMgbWFya2VkIGRvbmUgKGl0cwogICAgRG9uZSBjaGFubmVsIGlzIGNsb3NlZCkgd2hlbiBvbmUgb2YgdGhlIGxpc3RlZCBzaWduYWxzIGFycml2ZXMsIHdoZW4gdGhlCiAgICByZXR1cm5lZCBzdG9wIGZ1bmN0aW9uIGlzIGNhbGxlZCwgb3Igd2hlbiB0aGUgcGFyZW50IGNvbnRleHQncyBEb25lIGNoYW5uZWwKICAgIGlzIGNsb3NlZCwgd2hpY2hldmVyIGhhcHBlbnMgZmlyc3QuCgogICAgVGhlIHN0b3AgZnVuY3Rpb24gdW5yZWdpc3RlcnMgdGhlIHNpZ25hbCBiZWhhdmlvciwgd2hpY2gsIGxpa2Ugc2lnbmFsLlJlc2V0LAogICAgbWF5IHJlc3RvcmUgdGhlIGRlZmF1bHQgYmVoYXZpb3IgZm9yIGEgZ2l2ZW4gc2lnbmFsLiBGb3IgZXhhbXBsZSwKICAgIHRoZSBkZWZhdWx0IGJlaGF2aW9yIG9mIGEgR28gcHJvZ3JhbSByZWNlaXZpbmcgb3MuSW50ZXJydXB0IGlzIHRvIGV4aXQuCiAgICBDYWxsaW5nIE5vdGlmeUNvbnRleHQocGFyZW50LCBvcy5JbnRlcnJ1cHQpIHdpbGwgY2hhbmdlIHRoZSBiZWhhdmlvciB0bwogICAgY2FuY2VsIHRoZSByZXR1cm5lZCBjb250ZXh0LiBGdXR1cmUgaW50ZXJydXB0cyByZWNlaXZlZCB3aWxsIG5vdCB0cmlnZ2VyIHRoZQogICAgZGVmYXVsdCAoZXhpdCkgYmVoYXZpb3IgdW50aWwgdGhlIHJldHVybmVkIHN0b3AgZnVuY3Rpb24gaXMgY2FsbGVkLgoKICAgIFRoZSBzdG9wIGZ1bmN0aW9uIHJlbGVhc2VzIHJlc291cmNlcyBhc3NvY2lhdGVkIHdpdGggaXQsIHNvIGNvZGUgc2hvdWxkIGNhbGwKICAgIHN0b3AgYXMgc29vbiBhcyB0aGUgb3BlcmF0aW9ucyBydW5uaW5nIGluIHRoaXMgQ29udGV4dCBjb21wbGV0ZSBhbmQgc2lnbmFscwogICAgbm8gbG9uZ2VyIG5lZWQgdG8gYmUgZGl2ZXJ0ZWQgdG8gdGhlIGNvbnRleHQu", - "duration": 435073958, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "signals", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.38:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "os/signal#NotifyContext", - "href": "https://pkg.go.dev/os/signal#NotifyContext", - "target": "_blank" - }, - "file": "signals", - "nodes": [ - [ - { - "atom": "code", - "file": "signals", - "nodes": [ - { - "text": "signal.NotifyContext", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/os/signal#NotifyContext" - } - ], - { - "text": " function.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 38, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "signals.md", - "nodes": [ - { - "text": "Consider ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-39" - }, - "file": "signals.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-39" - }, - "nodes": [ - { - "text": "Listing 1.39", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-39" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ". We use ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "os/signal#NotifyContext", - "href": "https://pkg.go.dev/os/signal#NotifyContext", - "target": "_blank" - }, - "file": "signals.md", - "nodes": [ - { - "atom": "code", - "file": "signals.md", - "nodes": [ - { - "text": "signal.NotifyContext", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/os/signal#NotifyContext" - } - ], - { - "text": " to listen for ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "signals.md", - "nodes": [ - { - "text": "ctrl-c", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ". This function returns a wrapped ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "signals.md", - "nodes": [ - { - "atom": "code", - "file": "signals.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": " that will cancel when the signal is received. It also returns a ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#CancelFunc", - "href": "https://pkg.go.dev/context#CancelFunc", - "target": "_blank" - }, - "file": "signals.md", - "nodes": [ - { - "atom": "code", - "file": "signals.md", - "nodes": [ - { - "text": "context.CancelFunc", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#CancelFunc" - } - ], - { - "text": " that can be used to cancel ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "signals.md", - "nodes": [ - { - "atom": "code", - "file": "signals.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": " when needed.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-39", - "type": "listing" - }, - "file": "signals.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "signals", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "signals/src/signals/main.go#example" - }, - "lang": "go", - "nodes": [ - { - "content": "func main() {\n\n\t// create a background context\n\tctx := context.Background()\n\n\t// wrap the context with a timeout\n\t// of 50 milliseconds to ensure the application\n\t// will eventually exit\n\tctx, cancel := context.WithTimeout(ctx, 50*time.Millisecond)\n\tdefer cancel()\n\n\t// wrap the context with a context\n\t// that will be cancelled when an\n\t// interrupt signal is received (ctrl-c)\n\tctx, cancel = signal.NotifyContext(ctx, os.Interrupt)\n\tdefer cancel()\n\n\t// lauch a goroutine that will\n\t// trigger an interrupt signal\n\t// after 10 milliseconds (ctrl-c)\n\tgo func() {\n\t\ttime.Sleep(10 * time.Millisecond)\n\n\t\tfmt.Println(\"sending ctrl-c\")\n\n\t\t// send the interrupt signal\n\t\t// to the current process\n\t\tsyscall.Kill(syscall.Getpid(), syscall.SIGINT)\n\t}()\n\n\tfmt.Println(\"waiting for context to finish\")\n\n\t// wait for the context to finish\n\t\u003c-ctx.Done()\n\n\tfmt.Printf(\"context finished: %v\\n\", ctx.Err())\n\n}", - "file": "signals/src/signals/main.go", - "lang": "go", - "name": "example", - "start": 12, - "end": 52, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "signals", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.39:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Listening for system signals.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 39, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "signals.md", - "level": 2, - "nodes": [ - { - "text": "Testing Signals", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "signals.md", - "nodes": [ - { - "text": "Testing system signals is tricky and care must be taken not to accidentally exit your running tests. Unfortunately, the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "syscall", - "href": "https://pkg.go.dev/syscall", - "target": "_blank" - }, - "file": "signals.md", - "nodes": [ - { - "atom": "code", - "file": "signals.md", - "nodes": [ - { - "text": "syscall", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/syscall" - } - ], - { - "text": " package does not provide a \"test\" signal, or a way to implement a test signal.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "signals.md", - "nodes": [ - { - "text": "We can use ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "syscall#SIGUSR1", - "href": "https://pkg.go.dev/syscall#SIGUSR1", - "target": "_blank" - }, - "file": "signals.md", - "nodes": [ - { - "atom": "code", - "file": "signals.md", - "nodes": [ - { - "text": "syscall.SIGUSR1", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/syscall#SIGUSR1" - } - ], - { - "text": " or ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "syscall#SIGUSR2", - "href": "https://pkg.go.dev/syscall#SIGUSR2", - "target": "_blank" - }, - "file": "signals.md", - "nodes": [ - { - "atom": "code", - "file": "signals.md", - "nodes": [ - { - "text": "syscall.SIGUSR2", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/syscall#SIGUSR2" - } - ], - { - "text": " in our tests as these are allocated to the developer to use for their own purposes.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "signals.md", - "nodes": [ - { - "text": "When we are testing signals, we are testing a ", - "type": "hype.Text" - }, - { - "atom": "strong", - "file": "signals.md", - "nodes": [ - { - "text": "global", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " signal, that will caught by anyone else who is listening to that signal. Because of this we want to make that when testing signals we aren't running the tests in parallel and that we don't have other tests also listening to the same signal.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "signals.md", - "nodes": [ - { - "text": "Consider ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-40" - }, - "file": "signals.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-40" - }, - "nodes": [ - { - "text": "Listing 1.40", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-40" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ". How do we test that the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "signals.md", - "nodes": [ - { - "text": "Listener", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function will respond properly to a signal? We don't want to make that the responsibility of the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "signals.md", - "nodes": [ - { - "text": "Listener", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function, it already has a ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "signals.md", - "nodes": [ - { - "atom": "code", - "file": "signals.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": " that it can listen to for cancellation. The ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "signals.md", - "nodes": [ - { - "text": "Listener", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function doesn't care why it was told to stop listening, it just needs to stop listening. This could be because we receive an interrupt signal, because a deadline has passed, or because the application no longer needs the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "signals.md", - "nodes": [ - { - "text": "Lister", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function to keep running.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-40", - "type": "listing" - }, - "file": "signals.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "signals", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "signals/src/testing/signals_test.go#func" - }, - "lang": "go", - "nodes": [ - { - "content": "func Listener(ctx context.Context, t testing.TB) {\n\tt.Log(\"waiting for context to finish\")\n\n\t// wait for the context to finish\n\t\u003c-ctx.Done()\n\n}", - "file": "signals/src/testing/signals_test.go", - "lang": "go", - "name": "func", - "start": 13, - "end": 22, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "signals", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.40:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "signals", - "nodes": [ - { - "text": "Listener", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 40, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "signals.md", - "nodes": [ - { - "text": "In, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-41" - }, - "file": "signals.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-41" - }, - "nodes": [ - { - "text": "Listing 1.41", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-41" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", before we call the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "signals.md", - "nodes": [ - { - "text": "Listener", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function, we first create a ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "signals.md", - "nodes": [ - { - "atom": "code", - "file": "signals.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": " that will self-cancel after 5 seconds if nothing else happens. We then wrap that ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "signals.md", - "nodes": [ - { - "atom": "code", - "file": "signals.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": " with one received from the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "os/signal#NotifyContext", - "href": "https://pkg.go.dev/os/signal#NotifyContext", - "target": "_blank" - }, - "file": "signals.md", - "nodes": [ - { - "atom": "code", - "file": "signals.md", - "nodes": [ - { - "text": "signal.NotifyContext", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/os/signal#NotifyContext" - } - ], - { - "text": " function, that will self-cancel when the system receives a ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "signals.md", - "nodes": [ - { - "text": "TEST_SIGNAL", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " signal.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "signals.md", - "nodes": [ - { - "text": "Our test blocks with a ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "signals.md", - "nodes": [ - { - "text": "select", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " waiting for either ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "signals.md", - "nodes": [ - { - "atom": "code", - "file": "signals.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": " to be cancelled, and then respond accordingly.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-41", - "type": "listing" - }, - "file": "signals.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "signals", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "signals/src/testing/signals_test.go#example" - }, - "lang": "go", - "nodes": [ - { - "content": "// use syscall.SIGUSR2 to test\nconst TEST_SIGNAL = syscall.SIGUSR2\n\nfunc Test_Signals(t *testing.T) {\n\n\t// create a background context\n\tctx := context.Background()\n\n\t// wrap the context with a context\n\t// that will self cancel after 5 seconds\n\t// if the context is not finished\n\tctx, cancel := context.WithTimeout(ctx, 5*time.Second)\n\tdefer cancel()\n\n\t// wrap the context with a context\n\t// that will self cancel if the system\n\t// receives a TEST_SIGNAL\n\tsigCtx, cancel := signal.NotifyContext(ctx, TEST_SIGNAL)\n\tdefer cancel()\n\n\tprint(t, sigCtx)\n\n\t// launch a goroutine to wait for the context\n\t// to finish\n\tgo Listener(sigCtx, t)\n\n\t// launch a goroutine to send a TEST_SIGNAL\n\t// to the system after 1 second\n\tgo func() {\n\t\ttime.Sleep(time.Second)\n\n\t\tt.Log(\"sending test signal\")\n\n\t\t// send the TEST_SIGNAL to the system\n\t\tsyscall.Kill(syscall.Getpid(), TEST_SIGNAL)\n\t}()\n\n\t// wait for the context to finish\n\tselect {\n\tcase \u003c-ctx.Done():\n\t\tt.Log(\"context finished\")\n\tcase \u003c-sigCtx.Done():\n\t\tt.Log(\"signal received\")\n\t\tt.Log(\"successfully completed\")\n\t\treturn\n\t}\n\n\terr := ctx.Err()\n\tif err == nil {\n\t\treturn\n\t}\n\n\t// if we receive a DeadlineExceeded error then\n\t// the context timed out and the signal was never\n\t// received.\n\tif err == context.DeadlineExceeded {\n\t\tt.Fatal(\"unexpected error\", err)\n\t}\n\n}", - "file": "signals/src/testing/signals_test.go", - "lang": "go", - "name": "example", - "start": 24, - "end": 89, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "signals", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.41:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Testing the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "signals", - "nodes": [ - { - "text": "Listener", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 41, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "signals.md", - "nodes": [ - { - "text": "Inside the test, in a goroutine, we can trigger the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "signals.md", - "nodes": [ - { - "text": "TEST_SIGNAL", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " signal by sending it to the current process, ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "syscall#Getpid", - "href": "https://pkg.go.dev/syscall#Getpid", - "target": "_blank" - }, - "file": "signals.md", - "nodes": [ - { - "atom": "code", - "file": "signals.md", - "nodes": [ - { - "text": "syscall.Getpid", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/syscall#Getpid" - } - ], - { - "text": ", with the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "syscall#Kill", - "href": "https://pkg.go.dev/syscall#Kill", - "target": "_blank" - }, - "file": "signals.md", - "nodes": [ - { - "atom": "code", - "file": "signals.md", - "nodes": [ - { - "text": "syscall.Kill", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/syscall#Kill" - } - ], - { - "text": " function.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-42", - "type": "listing" - }, - "file": "signals.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "signals", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "signals/src/testing/signals_test.go#kill" - }, - "lang": "go", - "nodes": [ - { - "content": "// launch a goroutine to send a TEST_SIGNAL\n// to the system after 1 second\ngo func() {\n\ttime.Sleep(time.Second)\n\n\tt.Log(\"sending test signal\")\n\n\t// send the TEST_SIGNAL to the system\n\tsyscall.Kill(syscall.Getpid(), TEST_SIGNAL)\n}()", - "file": "signals/src/testing/signals_test.go", - "lang": "go", - "name": "kill", - "start": 52, - "end": 63, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "atom": "hr", - "file": "signals", - "type": "*hype.Element" - }, - [ - { - "args": [ - "go", - "test", - "-v" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go test -v", - "src": "signals/src/testing", - "test": "-v" - }, - "expected_exit": 0, - "file": "signals", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go test -v\n\n=== RUN Test_Signals\n signals_test.go:46: SignalCtx([]os.Signal{31})\n \t--\u0026gt; WithCancel\n \t\t--\u0026gt; WithTimeout(deadline: {wall:13936422481831633584 ext:5000605084 loc:0x102744760})\n \t\t\t--\u0026gt; context.backgroundCtx\n signals_test.go:15: waiting for context to finish\n signals_test.go:58: sending test signal\n signals_test.go:70: signal received\n signals_test.go:71: successfully completed\n--- PASS: Test_Signals (1.00s)\nPASS\nok \tdemo\t1.448s", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "test", - "-v" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/12-context/signals/src/testing", - "stdout": "PT09IFJVTiAgIFRlc3RfU2lnbmFscwogICAgc2lnbmFsc190ZXN0LmdvOjQ2OiBTaWduYWxDdHgoW11vcy5TaWduYWx7MzF9KQogICAgICAgIAktLT4gV2l0aENhbmNlbAogICAgICAgIAkJLS0+IFdpdGhUaW1lb3V0KGRlYWRsaW5lOiB7d2FsbDoxMzkzNjQyMjQ4MTgzMTYzMzU4NCBleHQ6NTAwMDYwNTA4NCBsb2M6MHgxMDI3NDQ3NjB9KQogICAgICAgIAkJCS0tPiBjb250ZXh0LmJhY2tncm91bmRDdHgKICAgIHNpZ25hbHNfdGVzdC5nbzoxNTogd2FpdGluZyBmb3IgY29udGV4dCB0byBmaW5pc2gKICAgIHNpZ25hbHNfdGVzdC5nbzo1ODogc2VuZGluZyB0ZXN0IHNpZ25hbAogICAgc2lnbmFsc190ZXN0LmdvOjcwOiBzaWduYWwgcmVjZWl2ZWQKICAgIHNpZ25hbHNfdGVzdC5nbzo3MTogc3VjY2Vzc2Z1bGx5IGNvbXBsZXRlZAotLS0gUEFTUzogVGVzdF9TaWduYWxzICgxLjAwcykKUEFTUwpvayAgCWRlbW8JMS40NDhz", - "duration": 1879023000, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go test -v\n\n=== RUN Test_Signals\n signals_test.go:46: SignalCtx([]os.Signal{31})\n \t--\u0026gt; WithCancel\n \t\t--\u0026gt; WithTimeout(deadline: {wall:13936422481831633584 ext:5000605084 loc:0x102744760})\n \t\t\t--\u0026gt; context.backgroundCtx\n signals_test.go:15: waiting for context to finish\n signals_test.go:58: sending test signal\n signals_test.go:70: signal received\n signals_test.go:71: successfully completed\n--- PASS: Test_Signals (1.00s)\nPASS\nok \tdemo\t1.448s", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "test", - "-v" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/12-context/signals/src/testing", - "stdout": "PT09IFJVTiAgIFRlc3RfU2lnbmFscwogICAgc2lnbmFsc190ZXN0LmdvOjQ2OiBTaWduYWxDdHgoW11vcy5TaWduYWx7MzF9KQogICAgICAgIAktLT4gV2l0aENhbmNlbAogICAgICAgIAkJLS0+IFdpdGhUaW1lb3V0KGRlYWRsaW5lOiB7d2FsbDoxMzkzNjQyMjQ4MTgzMTYzMzU4NCBleHQ6NTAwMDYwNTA4NCBsb2M6MHgxMDI3NDQ3NjB9KQogICAgICAgIAkJCS0tPiBjb250ZXh0LmJhY2tncm91bmRDdHgKICAgIHNpZ25hbHNfdGVzdC5nbzoxNTogd2FpdGluZyBmb3IgY29udGV4dCB0byBmaW5pc2gKICAgIHNpZ25hbHNfdGVzdC5nbzo1ODogc2VuZGluZyB0ZXN0IHNpZ25hbAogICAgc2lnbmFsc190ZXN0LmdvOjcwOiBzaWduYWwgcmVjZWl2ZWQKICAgIHNpZ25hbHNfdGVzdC5nbzo3MTogc3VjY2Vzc2Z1bGx5IGNvbXBsZXRlZAotLS0gUEFTUzogVGVzdF9TaWduYWxzICgxLjAwcykKUEFTUwpvayAgCWRlbW8JMS40NDhz", - "duration": 1879023000, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "signals", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.42:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Sending a ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "signals", - "nodes": [ - { - "text": "TEST_SIGNAL", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " signal.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 42, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "title": "Listening for System Signals with Context", - "type": "*hype.Page" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "type": "*hype.Include" - } - ], - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "page", - "file": "module.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "h1", - "file": "module.md", - "level": 1, - "nodes": [ - { - "text": "Summary", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "module.md", - "nodes": [ - { - "text": "In this ", - "type": "hype.Text" - }, - { - "atom": "binding", - "attributes": { - "part": "" - }, - "file": "module.md", - "type": "*hype.Element" - }, - { - "text": " we explore the concept of contexts in Go. We learn that contexts are a way to manage cancellation, timeouts, and other request-scoped values across API boundaries and between processes. We also learn how to use contexts to clean up a lot of code involving channels, such as listening for system signals. We discussed the nodal hierarchy of how the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context", - "href": "https://pkg.go.dev/context", - "target": "_blank" - }, - "file": "module.md", - "nodes": [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context" - } - ], - { - "text": " package wraps a new ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "module.md", - "nodes": [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": " around a parent ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "module.md", - "nodes": [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": ". We learned the different was to cancel a ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "module.md", - "nodes": [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": " and how to use multiple ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context#Context", - "href": "https://pkg.go.dev/context#Context", - "target": "_blank" - }, - "file": "module.md", - "nodes": [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "context.Context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context#Context" - } - ], - { - "text": "s to confirm shutdown behavior. The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "context", - "href": "https://pkg.go.dev/context", - "target": "_blank" - }, - "file": "module.md", - "nodes": [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "context", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/context" - } - ], - { - "text": " package, while small, is a very powerful tool for managing concurrency in your application.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "title": "Summary", - "type": "*hype.Page" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "type": "*hype.Body" - } - ] - ], - "type": "*hype.Element" - } - ], - "type": "*hype.Element" - } - ], - "parser": { - "type": "*hype.Parser", - "root": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/12-context", - "section": 1, - "snippets": {} - }, - "root": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/12-context", - "section_id": 1, - "snippets": {}, - "title": "Context", - "type": "*hype.Document", - "filename": "module.md" -} \ No newline at end of file diff --git a/src/testdata/custom.json b/src/testdata/custom.json index 5ceb3f9..92566b1 100644 --- a/src/testdata/custom.json +++ b/src/testdata/custom.json @@ -1,15 +1,9 @@ { + "type": "hype.Document", + "title": "Custom Tags", "nodes": [ { - "type": "CustomTag", - "atom": "custom", - "file": "custom.md", - "nodes": [] + "type": "hype.CustomTag" } - ], - "parser": {}, - "root": "testdata", - "title": "Custom Tags", - "type": "*hype.Document", - "filename": "module.md" + ] } \ No newline at end of file diff --git a/src/testdata/errors.json b/src/testdata/errors.json deleted file mode 100644 index 6a5a13a..0000000 --- a/src/testdata/errors.json +++ /dev/null @@ -1,23057 +0,0 @@ -{ - "nodes": [ - { - "file": "module.md", - "nodes": [ - { - "atom": "html", - "file": "module.md", - "nodes": [ - { - "atom": "head", - "file": "module.md", - "type": "*hype.Element" - }, - [ - { - "atom": "body", - "file": "module.md", - "nodes": [ - [ - { - "atom": "page", - "file": "module.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "h1", - "file": "module.md", - "level": 1, - "nodes": [ - { - "text": "Errors", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "module.md", - "nodes": [ - { - "text": "This ", - "type": "hype.Text" - }, - { - "atom": "binding", - "attributes": { - "part": "" - }, - "file": "module.md", - "type": "*hype.Element" - }, - { - "text": " will cover the benefits of how Go's error model results in more reliable code. We will cover how to handle basic errors and return errors as an interface that satisfies the error type. Additionally, concepts such as custom error types, panics, recovering from panics, and sentinel errors are also covered.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "title": "Errors", - "type": "*hype.Page" - } - ], - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "include", - "attributes": { - "src": "errors/basics.md" - }, - "dir": "errors", - "file": "module.md", - "nodes": [ - [ - { - "atom": "page", - "file": "errors/basics.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "h1", - "file": "errors/basics.md", - "level": 1, - "nodes": [ - { - "text": "Errors", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "errors/basics.md", - "nodes": [ - { - "text": "A lot of languages use the concept of ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "href": "https://en.wikipedia.org/wiki/Exception_handling", - "target": "_blank" - }, - "file": "errors/basics.md", - "nodes": [ - { - "text": "exceptions", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "https://en.wikipedia.org/wiki/Exception_handling" - } - ], - { - "text": ". When something goes wrong, an exception will be thrown. This exception then needs to be caught. When catching an exception you have the opportunity to log the exception and possibly move on with an alternate code path, or re-raise the exception and let the developer upstream deal with the problem.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "errors/basics.md", - "nodes": [ - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-1" - }, - "file": "errors/basics.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-1" - }, - "nodes": [ - { - "text": "Listing 1.1", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-1" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": " shows an example of how to handle exceptions in Java.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-1", - "type": "listing" - }, - "file": "errors/basics.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "errors", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-java", - "language": "java", - "src": "errors/src/handling-java/main.java#example" - }, - "lang": "java", - "nodes": [ - { - "content": "public static void main(String args[]) {\n try {\n // Open the file\n FileInputStream fstream = new FileInputStream(\"example.txt\");\n\n // Get the object of DataInputStream\n DataInputStream in = new DataInputStream(fstream);\n BufferedReader br = new BufferedReader(new InputStreamReader(in));\n String strLine;\n\n // Read File Line By Line\n while ((strLine = br.readLine()) != null) {\n // Print the content on the console\n System.out.println(strLine);\n }\n\n // Close the input stream\n in.close();\n } catch (IOException e) {\n System.err.println(\"IO Error: \" + e.getMessage());\n } catch (Exception e) {\n // Catch exception if any\n System.err.println(\"Error: \" + e.getMessage());\n }\n}", - "file": "errors/src/handling-java/main.java", - "lang": "java", - "name": "example", - "start": 5, - "end": 31, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "errors", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.1:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Exceptions in Java.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 1, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "errors/basics.md", - "nodes": [ - { - "text": "Go takes a different approach and treats errors as values. These values are returned and managed instead of throwing and capturing exceptions, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-2" - }, - "file": "errors/basics.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-2" - }, - "nodes": [ - { - "text": "Listing 1.2", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-2" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-2", - "type": "listing" - }, - "file": "errors/basics.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "errors", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "errors/src/handling/main.go#example" - }, - "lang": "go", - "nodes": [ - { - "content": "func readFile() error {\n\n\t// open the file\n\tf, err := os.Open(\"example.txt\")\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// close the file when done\n\tdefer f.Close()\n\n\t// open buffered scanner with file\n\tscanner := bufio.NewScanner(f)\n\n\t// scan through each line of the file\n\tfor scanner.Scan() {\n\n\t\t// print line to the console\n\t\tfmt.Println(scanner.Text())\n\t}\n\n\t// if there was an error while scanning\n\t// return the error to the calling function\n\tif err := scanner.Err(); err != nil {\n\t\treturn err\n\t}\n\n\t// everything was good, return nil\n\treturn nil\n}", - "file": "errors/src/handling/main.go", - "lang": "go", - "name": "example", - "start": 17, - "end": 49, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "errors", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.2:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Errors in Go.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 2, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "errors/basics.md", - "level": 2, - "nodes": [ - { - "text": "The \"error\" Interface", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "errors/basics.md", - "nodes": [ - { - "text": "In Go errors are represented by the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "builtin#error", - "href": "https://pkg.go.dev/builtin#error", - "target": "_blank" - }, - "file": "errors/basics.md", - "nodes": [ - { - "atom": "code", - "file": "errors/basics.md", - "nodes": [ - { - "text": "error", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/builtin#error" - } - ], - { - "text": " interface.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-3", - "type": "listing" - }, - "file": "errors/basics.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "doc", - "builtin.error" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "doc": "builtin.error", - "exec": "go doc builtin.error" - }, - "expected_exit": 0, - "file": "errors", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc builtin.error\n\npackage builtin // import \u0026#34;builtin\u0026#34;\n\ntype error interface {\n\tError() string\n}\n The error built-in interface type is the conventional interface for\n representing an error condition, with the nil value representing no error.", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "builtin.error" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBidWlsdGluIC8vIGltcG9ydCAiYnVpbHRpbiIKCnR5cGUgZXJyb3IgaW50ZXJmYWNlIHsKCUVycm9yKCkgc3RyaW5nCn0KICAgIFRoZSBlcnJvciBidWlsdC1pbiBpbnRlcmZhY2UgdHlwZSBpcyB0aGUgY29udmVudGlvbmFsIGludGVyZmFjZSBmb3IKICAgIHJlcHJlc2VudGluZyBhbiBlcnJvciBjb25kaXRpb24sIHdpdGggdGhlIG5pbCB2YWx1ZSByZXByZXNlbnRpbmcgbm8gZXJyb3Iu", - "duration": 2024474042, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc builtin.error\n\npackage builtin // import \u0026#34;builtin\u0026#34;\n\ntype error interface {\n\tError() string\n}\n The error built-in interface type is the conventional interface for\n representing an error condition, with the nil value representing no error.", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "builtin.error" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBidWlsdGluIC8vIGltcG9ydCAiYnVpbHRpbiIKCnR5cGUgZXJyb3IgaW50ZXJmYWNlIHsKCUVycm9yKCkgc3RyaW5nCn0KICAgIFRoZSBlcnJvciBidWlsdC1pbiBpbnRlcmZhY2UgdHlwZSBpcyB0aGUgY29udmVudGlvbmFsIGludGVyZmFjZSBmb3IKICAgIHJlcHJlc2VudGluZyBhbiBlcnJvciBjb25kaXRpb24sIHdpdGggdGhlIG5pbCB2YWx1ZSByZXByZXNlbnRpbmcgbm8gZXJyb3Iu", - "duration": 2024474042, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "errors", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.3:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "builtin#error", - "href": "https://pkg.go.dev/builtin#error", - "target": "_blank" - }, - "file": "errors", - "nodes": [ - [ - { - "atom": "code", - "file": "errors", - "nodes": [ - { - "text": "error", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/builtin#error" - } - ], - { - "text": " interface.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 3, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h3", - "file": "errors/basics.md", - "level": 3, - "nodes": [ - { - "text": "Creating Errors with \"errors.New\"", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "errors/basics.md", - "nodes": [ - { - "text": "Go provides two quick ways to implement the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "builtin#error", - "href": "https://pkg.go.dev/builtin#error", - "target": "_blank" - }, - "file": "errors/basics.md", - "nodes": [ - { - "atom": "code", - "file": "errors/basics.md", - "nodes": [ - { - "text": "error", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/builtin#error" - } - ], - { - "text": " interface in our code.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "errors/basics.md", - "nodes": [ - { - "text": "The first is through the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "errors#New", - "href": "https://pkg.go.dev/errors#New", - "target": "_blank" - }, - "file": "errors/basics.md", - "nodes": [ - { - "atom": "code", - "file": "errors/basics.md", - "nodes": [ - { - "text": "errors.New", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/errors#New" - } - ], - { - "text": " function, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-4" - }, - "file": "errors/basics.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-4" - }, - "nodes": [ - { - "text": "Listing 1.4", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-4" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ". This function takes a string and returns an implementation of ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "builtin#error", - "href": "https://pkg.go.dev/builtin#error", - "target": "_blank" - }, - "file": "errors/basics.md", - "nodes": [ - { - "atom": "code", - "file": "errors/basics.md", - "nodes": [ - { - "text": "error", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/builtin#error" - } - ], - { - "text": " that uses the supplied string as the error message.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-4", - "type": "listing" - }, - "file": "errors/basics.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "doc", - "errors.New" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "doc": "errors.New", - "exec": "go doc errors.New" - }, - "expected_exit": 0, - "file": "errors", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc errors.New\n\npackage errors // import \u0026#34;errors\u0026#34;\n\nfunc New(text string) error\n New returns an error that formats as the given text. Each call to New\n returns a distinct error value even if the text is identical.", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "errors.New" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBlcnJvcnMgLy8gaW1wb3J0ICJlcnJvcnMiCgpmdW5jIE5ldyh0ZXh0IHN0cmluZykgZXJyb3IKICAgIE5ldyByZXR1cm5zIGFuIGVycm9yIHRoYXQgZm9ybWF0cyBhcyB0aGUgZ2l2ZW4gdGV4dC4gRWFjaCBjYWxsIHRvIE5ldwogICAgcmV0dXJucyBhIGRpc3RpbmN0IGVycm9yIHZhbHVlIGV2ZW4gaWYgdGhlIHRleHQgaXMgaWRlbnRpY2FsLg==", - "duration": 2320422833, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc errors.New\n\npackage errors // import \u0026#34;errors\u0026#34;\n\nfunc New(text string) error\n New returns an error that formats as the given text. Each call to New\n returns a distinct error value even if the text is identical.", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "errors.New" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBlcnJvcnMgLy8gaW1wb3J0ICJlcnJvcnMiCgpmdW5jIE5ldyh0ZXh0IHN0cmluZykgZXJyb3IKICAgIE5ldyByZXR1cm5zIGFuIGVycm9yIHRoYXQgZm9ybWF0cyBhcyB0aGUgZ2l2ZW4gdGV4dC4gRWFjaCBjYWxsIHRvIE5ldwogICAgcmV0dXJucyBhIGRpc3RpbmN0IGVycm9yIHZhbHVlIGV2ZW4gaWYgdGhlIHRleHQgaXMgaWRlbnRpY2FsLg==", - "duration": 2320422833, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "errors", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.4:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "errors#New", - "href": "https://pkg.go.dev/errors#New", - "target": "_blank" - }, - "file": "errors", - "nodes": [ - [ - { - "atom": "code", - "file": "errors", - "nodes": [ - { - "text": "errors.New", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/errors#New" - } - ], - { - "text": " function.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 4, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h3", - "file": "errors/basics.md", - "level": 3, - "nodes": [ - { - "text": "Creating Errors with \"fmt.Errorf\" (Recommended)", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "errors/basics.md", - "nodes": [ - { - "text": "When creating errors, it is common to want to create a string that contains the error message and the values of variables that caused the error.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-5", - "type": "listing" - }, - "file": "errors/basics.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "errors", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "errors/src/newing/main.go#new" - }, - "lang": "go", - "nodes": [ - { - "content": "err = errors.New(fmt.Sprintf(\"error at %s\", time.Now()))", - "file": "errors/src/newing/main.go", - "lang": "go", - "name": "new", - "start": 18, - "end": 20, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "errors", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.5:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Creating errors with ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "errors#New", - "href": "https://pkg.go.dev/errors#New", - "target": "_blank" - }, - "file": "errors", - "nodes": [ - [ - { - "atom": "code", - "file": "errors", - "nodes": [ - { - "text": "errors.New", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/errors#New" - } - ], - { - "text": " and ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "fmt#Sprintf", - "href": "https://pkg.go.dev/fmt#Sprintf", - "target": "_blank" - }, - "file": "errors", - "nodes": [ - [ - { - "atom": "code", - "file": "errors", - "nodes": [ - { - "text": "fmt.Sprintf", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/fmt#Sprintf" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 5, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "errors/basics.md", - "nodes": [ - { - "text": "To clean up the pattern seen in ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-5" - }, - "file": "errors/basics.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-5" - }, - "nodes": [ - { - "text": "Listing 1.5", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-5" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "fmt#Errorf", - "href": "https://pkg.go.dev/fmt#Errorf", - "target": "_blank" - }, - "file": "errors/basics.md", - "nodes": [ - { - "atom": "code", - "file": "errors/basics.md", - "nodes": [ - { - "text": "fmt.Errorf", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/fmt#Errorf" - } - ], - { - "text": " method, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-6" - }, - "file": "errors/basics.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-6" - }, - "nodes": [ - { - "text": "Listing 1.6", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-6" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", can be used.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-6", - "type": "listing" - }, - "file": "errors/basics.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "doc", - "fmt.Errorf" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "doc": "fmt.Errorf", - "exec": "go doc fmt.Errorf" - }, - "expected_exit": 0, - "file": "errors", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc fmt.Errorf\n\npackage fmt // import \u0026#34;fmt\u0026#34;\n\nfunc Errorf(format string, a ...any) error\n Errorf formats according to a format specifier and returns the string as a\n value that satisfies error.\n\n If the format specifier includes a %w verb with an error operand,\n the returned error will implement an Unwrap method returning the operand.\n If there is more than one %w verb, the returned error will implement an\n Unwrap method returning a []error containing all the %w operands in the\n order they appear in the arguments. It is invalid to supply the %w verb\n with an operand that does not implement the error interface. The %w verb is\n otherwise a synonym for %v.", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "fmt.Errorf" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBmbXQgLy8gaW1wb3J0ICJmbXQiCgpmdW5jIEVycm9yZihmb3JtYXQgc3RyaW5nLCBhIC4uLmFueSkgZXJyb3IKICAgIEVycm9yZiBmb3JtYXRzIGFjY29yZGluZyB0byBhIGZvcm1hdCBzcGVjaWZpZXIgYW5kIHJldHVybnMgdGhlIHN0cmluZyBhcyBhCiAgICB2YWx1ZSB0aGF0IHNhdGlzZmllcyBlcnJvci4KCiAgICBJZiB0aGUgZm9ybWF0IHNwZWNpZmllciBpbmNsdWRlcyBhICV3IHZlcmIgd2l0aCBhbiBlcnJvciBvcGVyYW5kLAogICAgdGhlIHJldHVybmVkIGVycm9yIHdpbGwgaW1wbGVtZW50IGFuIFVud3JhcCBtZXRob2QgcmV0dXJuaW5nIHRoZSBvcGVyYW5kLgogICAgSWYgdGhlcmUgaXMgbW9yZSB0aGFuIG9uZSAldyB2ZXJiLCB0aGUgcmV0dXJuZWQgZXJyb3Igd2lsbCBpbXBsZW1lbnQgYW4KICAgIFVud3JhcCBtZXRob2QgcmV0dXJuaW5nIGEgW11lcnJvciBjb250YWluaW5nIGFsbCB0aGUgJXcgb3BlcmFuZHMgaW4gdGhlCiAgICBvcmRlciB0aGV5IGFwcGVhciBpbiB0aGUgYXJndW1lbnRzLiBJdCBpcyBpbnZhbGlkIHRvIHN1cHBseSB0aGUgJXcgdmVyYgogICAgd2l0aCBhbiBvcGVyYW5kIHRoYXQgZG9lcyBub3QgaW1wbGVtZW50IHRoZSBlcnJvciBpbnRlcmZhY2UuIFRoZSAldyB2ZXJiIGlzCiAgICBvdGhlcndpc2UgYSBzeW5vbnltIGZvciAldi4=", - "duration": 2070643625, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc fmt.Errorf\n\npackage fmt // import \u0026#34;fmt\u0026#34;\n\nfunc Errorf(format string, a ...any) error\n Errorf formats according to a format specifier and returns the string as a\n value that satisfies error.\n\n If the format specifier includes a %w verb with an error operand,\n the returned error will implement an Unwrap method returning the operand.\n If there is more than one %w verb, the returned error will implement an\n Unwrap method returning a []error containing all the %w operands in the\n order they appear in the arguments. It is invalid to supply the %w verb\n with an operand that does not implement the error interface. The %w verb is\n otherwise a synonym for %v.", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "fmt.Errorf" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBmbXQgLy8gaW1wb3J0ICJmbXQiCgpmdW5jIEVycm9yZihmb3JtYXQgc3RyaW5nLCBhIC4uLmFueSkgZXJyb3IKICAgIEVycm9yZiBmb3JtYXRzIGFjY29yZGluZyB0byBhIGZvcm1hdCBzcGVjaWZpZXIgYW5kIHJldHVybnMgdGhlIHN0cmluZyBhcyBhCiAgICB2YWx1ZSB0aGF0IHNhdGlzZmllcyBlcnJvci4KCiAgICBJZiB0aGUgZm9ybWF0IHNwZWNpZmllciBpbmNsdWRlcyBhICV3IHZlcmIgd2l0aCBhbiBlcnJvciBvcGVyYW5kLAogICAgdGhlIHJldHVybmVkIGVycm9yIHdpbGwgaW1wbGVtZW50IGFuIFVud3JhcCBtZXRob2QgcmV0dXJuaW5nIHRoZSBvcGVyYW5kLgogICAgSWYgdGhlcmUgaXMgbW9yZSB0aGFuIG9uZSAldyB2ZXJiLCB0aGUgcmV0dXJuZWQgZXJyb3Igd2lsbCBpbXBsZW1lbnQgYW4KICAgIFVud3JhcCBtZXRob2QgcmV0dXJuaW5nIGEgW11lcnJvciBjb250YWluaW5nIGFsbCB0aGUgJXcgb3BlcmFuZHMgaW4gdGhlCiAgICBvcmRlciB0aGV5IGFwcGVhciBpbiB0aGUgYXJndW1lbnRzLiBJdCBpcyBpbnZhbGlkIHRvIHN1cHBseSB0aGUgJXcgdmVyYgogICAgd2l0aCBhbiBvcGVyYW5kIHRoYXQgZG9lcyBub3QgaW1wbGVtZW50IHRoZSBlcnJvciBpbnRlcmZhY2UuIFRoZSAldyB2ZXJiIGlzCiAgICBvdGhlcndpc2UgYSBzeW5vbnltIGZvciAldi4=", - "duration": 2070643625, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "errors", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.6:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "fmt#Errorf", - "href": "https://pkg.go.dev/fmt#Errorf", - "target": "_blank" - }, - "file": "errors", - "nodes": [ - [ - { - "atom": "code", - "file": "errors", - "nodes": [ - { - "text": "fmt.Errorf", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/fmt#Errorf" - } - ], - { - "text": " method.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 6, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "errors/basics.md", - "nodes": [ - { - "text": "In ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-7" - }, - "file": "errors/basics.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-7" - }, - "nodes": [ - { - "text": "Listing 1.7", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-7" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": " the code is now cleaner and more readable than in ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-5" - }, - "file": "errors/basics.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-5" - }, - "nodes": [ - { - "text": "Listing 1.5", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-5" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-7", - "type": "listing" - }, - "file": "errors/basics.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "errors", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "errors/src/newing/main.go#errorf" - }, - "lang": "go", - "nodes": [ - { - "content": "err = fmt.Errorf(\"error at %s\", time.Now())", - "file": "errors/src/newing/main.go", - "lang": "go", - "name": "errorf", - "start": 12, - "end": 14, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "errors", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.7:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Creating errors with ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "fmt#Errorf", - "href": "https://pkg.go.dev/fmt#Errorf", - "target": "_blank" - }, - "file": "errors", - "nodes": [ - [ - { - "atom": "code", - "file": "errors", - "nodes": [ - { - "text": "fmt.Errorf", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/fmt#Errorf" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 7, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - { - "atom": "blockquote", - "file": "errors/basics.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "errors/basics.md", - "nodes": [ - { - "text": "Using ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "fmt#Errorf", - "href": "https://pkg.go.dev/fmt#Errorf", - "target": "_blank" - }, - "file": "errors/basics.md", - "nodes": [ - { - "atom": "code", - "file": "errors/basics.md", - "nodes": [ - { - "text": "fmt.Errorf", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/fmt#Errorf" - } - ], - { - "text": " will handle ", - "type": "hype.Text" - }, - { - "atom": "strong", - "file": "errors/basics.md", - "nodes": [ - { - "text": "most", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " use cases for creating errors.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "errors/basics.md", - "level": 2, - "nodes": [ - { - "text": "Handling Errors", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "errors/basics.md", - "nodes": [ - { - "text": "With errors being a type in the Go type system, in this case an ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "errors/basics.md", - "nodes": [ - { - "text": "interface", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " type, errors can be returned from, and accepted as, function arguments.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "errors/basics.md", - "nodes": [ - { - "text": "In Go, if an error is returned from the function, it should ", - "type": "hype.Text" - }, - { - "atom": "strong", - "file": "errors/basics.md", - "nodes": [ - { - "text": "always", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " be returned as the last argument. While the Go compiler won't enforce this, it is the expected idiom in the Go ecosystem.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-8", - "type": "listing" - }, - "file": "errors/basics.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "errors", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go" - }, - "file": "errors", - "lang": "go", - "nodes": [ - { - "text": "// good\nfunc one() error {}\nfunc two() (int, error) {}\n\n// bad\nfunc bad() (error, int) {}\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "errors", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.8:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Good and bad examples of return an ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "builtin#error", - "href": "https://pkg.go.dev/builtin#error", - "target": "_blank" - }, - "file": "errors", - "nodes": [ - [ - { - "atom": "code", - "file": "errors", - "nodes": [ - { - "text": "error", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/builtin#error" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 8, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "errors/basics.md", - "nodes": [ - { - "text": "As with all interfaces in Go, the zero value of the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "builtin#error", - "href": "https://pkg.go.dev/builtin#error", - "target": "_blank" - }, - "file": "errors/basics.md", - "nodes": [ - { - "atom": "code", - "file": "errors/basics.md", - "nodes": [ - { - "text": "error", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/builtin#error" - } - ], - { - "text": " interface is ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "errors/basics.md", - "nodes": [ - { - "text": "nil", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ". Error checking in Go is done by checking if the returned error is ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "errors/basics.md", - "nodes": [ - { - "text": "nil", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " or not.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-9", - "type": "listing" - }, - "file": "errors/basics.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "errors", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go" - }, - "file": "errors", - "lang": "go", - "nodes": [ - { - "text": "err := boom()\nif err != nil {\n // the error was not nil\n // do something with the error\n}\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "errors", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.9:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Checking for errors by assert against ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "errors", - "nodes": [ - { - "text": "nil", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 9, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "errors/basics.md", - "level": 2, - "nodes": [ - { - "text": "Using Errors", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "errors/basics.md", - "nodes": [ - { - "text": "In ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-10" - }, - "file": "errors/basics.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-10" - }, - "nodes": [ - { - "text": "Listing 1.10", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-10" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": " if the key being requested in the map is found, its value will be returned and a ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "errors/basics.md", - "nodes": [ - { - "text": "nil", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " will be returned instead of an argument. If the key is not found in the map an empty string and an error, created with ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "fmt#Errorf", - "href": "https://pkg.go.dev/fmt#Errorf", - "target": "_blank" - }, - "file": "errors/basics.md", - "nodes": [ - { - "atom": "code", - "file": "errors/basics.md", - "nodes": [ - { - "text": "fmt.Errorf", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/fmt#Errorf" - } - ], - { - "text": ", are returned.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-10", - "type": "listing" - }, - "file": "errors/basics.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "errors", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "errors/src/using/using.go#example" - }, - "lang": "go", - "nodes": [ - { - "content": "func Get(key string) (string, error) {\n\tm := map[string]string{\n\t\t\"a\": \"A\",\n\t\t\"b\": \"B\",\n\t}\n\n\tif v, ok := m[key]; ok {\n\t\treturn v, nil\n\t}\n\n\treturn \"\", fmt.Errorf(\"no key found %s\", key)\n}", - "file": "errors/src/using/using.go", - "lang": "go", - "name": "example", - "start": 5, - "end": 19, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "errors", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.10:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "A function that might return an ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "builtin#error", - "href": "https://pkg.go.dev/builtin#error", - "target": "_blank" - }, - "file": "errors", - "nodes": [ - [ - { - "atom": "code", - "file": "errors", - "nodes": [ - { - "text": "error", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/builtin#error" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 10, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "errors/basics.md", - "nodes": [ - { - "text": "A test for the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "errors/basics.md", - "nodes": [ - { - "text": "Get", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-11" - }, - "file": "errors/basics.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-11" - }, - "nodes": [ - { - "text": "Listing 1.11", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-11" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", demonstrates the error checking pattern in action.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-11", - "type": "listing" - }, - "file": "errors/basics.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "errors", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "errors/src/using/using_test.go#test" - }, - "lang": "go", - "nodes": [ - { - "content": "func Test_Get(t *testing.T) {\n\tt.Parallel()\n\n\tact, err := Get(\"a\")\n\tif err != nil {\n\t\tt.Fatalf(\"expect no error, got %s\", err)\n\t}\n\n\texp := \"A\"\n\tif act != exp {\n\t\tt.Fatalf(\"expected %s, got %s\", exp, act)\n\t}\n\n\t_, err = Get(\"?\")\n\tif err == nil {\n\t\tt.Fatalf(\"expected an error, got nil\")\n\t}\n}", - "file": "errors/src/using/using_test.go", - "lang": "go", - "name": "test", - "start": 5, - "end": 25, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "errors", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.11:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "A test for the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "errors", - "nodes": [ - { - "text": "Get", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 11, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "title": "Errors", - "type": "*hype.Page" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "type": "*hype.Include" - } - ], - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "include", - "attributes": { - "src": "panic/panic.md" - }, - "dir": "panic", - "file": "module.md", - "nodes": [ - [ - { - "atom": "page", - "file": "panic.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "h1", - "file": "panic.md", - "level": 1, - "nodes": [ - { - "text": "Panic", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - { - "atom": "blockquote", - "file": "panic.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "panic.md", - "nodes": [ - { - "text": "\"", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "href": "https://bit.ly/3jqqUk3", - "target": "_blank" - }, - "file": "panic.md", - "nodes": [ - { - "text": "The Hitchhiker's Guide to the Galaxy", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "https://bit.ly/3jqqUk3" - } - ], - { - "text": " itself has outsold the Encyclopedia Galactica because it is slightly cheaper, and because it has the words ‘DON'T PANIC' in large, friendly letters on the cover.\"", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "panic.md", - "nodes": [ - { - "text": "Arthur C. Clarke said Douglas Adams' use of ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "href": "https://en.wikipedia.org/wiki/Phrases_from_The_Hitchhiker%27s_Guide_to_the_Galaxy#Don't_Panic", - "target": "_blank" - }, - "file": "panic.md", - "nodes": [ - { - "text": "\"don't panic\"", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "https://en.wikipedia.org/wiki/Phrases_from_The_Hitchhiker%27s_Guide_to_the_Galaxy#Don't_Panic" - } - ], - { - "text": " was perhaps the best advice that could be given to humanity.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "panic.md", - "level": 2, - "nodes": [ - { - "text": "What is a Panic?", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "panic.md", - "nodes": [ - { - "text": "Occasionally, your code you will do something that the Go runtime does not like. For example, in ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-12" - }, - "file": "panic.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-12" - }, - "nodes": [ - { - "text": "Listing 1.12", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-12" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", if we try to insert a value into an array or slice that is beyond the bounds of the array or slice, the runtime will panic.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-12", - "type": "listing" - }, - "file": "panic.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "panic", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "panic/src/basics/main.go#example" - }, - "lang": "go", - "nodes": [ - { - "content": "func main() {\n\ta := []string{}\n\ta[42] = \"Bring a towel\"\n}", - "file": "panic/src/basics/main.go", - "lang": "go", - "name": "example", - "start": 3, - "end": 9, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "atom": "hr", - "file": "panic", - "type": "*hype.Element" - }, - [ - { - "args": [ - "go", - "run", - "." - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go run .", - "exit": "-1", - "run": ".", - "src": "panic/src/basics" - }, - "expected_exit": -1, - "file": "panic", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\npanic: runtime error: index out of range [42] with length 0\n\ngoroutine 1 [running]:\nmain.main()\n\t./main.go:6 +0x24\nexit status 2", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/basics", - "err": { - "Stderr": null - }, - "exit": 1, - "stderr": "cGFuaWM6IHJ1bnRpbWUgZXJyb3I6IGluZGV4IG91dCBvZiByYW5nZSBbNDJdIHdpdGggbGVuZ3RoIDAKCmdvcm91dGluZSAxIFtydW5uaW5nXToKbWFpbi5tYWluKCkKCS9Vc2Vycy9tYXJrYmF0ZXMvTGlicmFyeS9DbG91ZFN0b3JhZ2UvRHJvcGJveC9kZXYvZ3VpZGVzL2NvbnRlbnQvYm9vay9jaGFwdGVycy8wOS1lcnJvcnMvcGFuaWMvc3JjL2Jhc2ljcy9tYWluLmdvOjYgKzB4MjQKZXhpdCBzdGF0dXMgMg==", - "duration": 3531196500, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\npanic: runtime error: index out of range [42] with length 0\n\ngoroutine 1 [running]:\nmain.main()\n\t./main.go:6 +0x24\nexit status 2", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/basics", - "err": { - "Stderr": null - }, - "exit": 1, - "stderr": "cGFuaWM6IHJ1bnRpbWUgZXJyb3I6IGluZGV4IG91dCBvZiByYW5nZSBbNDJdIHdpdGggbGVuZ3RoIDAKCmdvcm91dGluZSAxIFtydW5uaW5nXToKbWFpbi5tYWluKCkKCS9Vc2Vycy9tYXJrYmF0ZXMvTGlicmFyeS9DbG91ZFN0b3JhZ2UvRHJvcGJveC9kZXYvZ3VpZGVzL2NvbnRlbnQvYm9vay9jaGFwdGVycy8wOS1lcnJvcnMvcGFuaWMvc3JjL2Jhc2ljcy9tYWluLmdvOjYgKzB4MjQKZXhpdCBzdGF0dXMgMg==", - "duration": 3531196500, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "panic", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.12:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "A panic caused by an out of bounds index.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 12, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "panic.md", - "level": 2, - "nodes": [ - { - "text": "Raising a Panic", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "panic.md", - "nodes": [ - { - "text": "A panic in Go can be raised using the built-in ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "builtin#panic", - "href": "https://pkg.go.dev/builtin#panic", - "target": "_blank" - }, - "file": "panic.md", - "nodes": [ - { - "atom": "code", - "file": "panic.md", - "nodes": [ - { - "text": "panic", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/builtin#panic" - } - ], - { - "text": " function, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-13" - }, - "file": "panic.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-13" - }, - "nodes": [ - { - "text": "Listing 1.13", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-13" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ". The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "builtin#panic", - "href": "https://pkg.go.dev/builtin#panic", - "target": "_blank" - }, - "file": "panic.md", - "nodes": [ - { - "atom": "code", - "file": "panic.md", - "nodes": [ - { - "text": "panic", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/builtin#panic" - } - ], - { - "text": " function takes ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "panic.md", - "nodes": [ - { - "text": "any", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " value as an argument.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-13", - "type": "listing" - }, - "file": "panic.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "doc", - "builtin.panic" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "doc": "builtin.panic", - "exec": "go doc builtin.panic" - }, - "expected_exit": 0, - "file": "panic", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc builtin.panic\n\npackage builtin // import \u0026#34;builtin\u0026#34;\n\nfunc panic(v any)\n The panic built-in function stops normal execution of the current goroutine.\n When a function F calls panic, normal execution of F stops immediately.\n Any functions whose execution was deferred by F are run in the usual way,\n and then F returns to its caller. To the caller G, the invocation of F then\n behaves like a call to panic, terminating G\u0026#39;s execution and running any\n deferred functions. This continues until all functions in the executing\n goroutine have stopped, in reverse order. At that point, the program is\n terminated with a non-zero exit code. This termination sequence is called\n panicking and can be controlled by the built-in function recover.\n\n Starting in Go 1.21, calling panic with a nil interface value or an untyped\n nil causes a run-time error (a different panic). The GODEBUG setting\n panicnil=1 disables the run-time error.", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "builtin.panic" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBidWlsdGluIC8vIGltcG9ydCAiYnVpbHRpbiIKCmZ1bmMgcGFuaWModiBhbnkpCiAgICBUaGUgcGFuaWMgYnVpbHQtaW4gZnVuY3Rpb24gc3RvcHMgbm9ybWFsIGV4ZWN1dGlvbiBvZiB0aGUgY3VycmVudCBnb3JvdXRpbmUuCiAgICBXaGVuIGEgZnVuY3Rpb24gRiBjYWxscyBwYW5pYywgbm9ybWFsIGV4ZWN1dGlvbiBvZiBGIHN0b3BzIGltbWVkaWF0ZWx5LgogICAgQW55IGZ1bmN0aW9ucyB3aG9zZSBleGVjdXRpb24gd2FzIGRlZmVycmVkIGJ5IEYgYXJlIHJ1biBpbiB0aGUgdXN1YWwgd2F5LAogICAgYW5kIHRoZW4gRiByZXR1cm5zIHRvIGl0cyBjYWxsZXIuIFRvIHRoZSBjYWxsZXIgRywgdGhlIGludm9jYXRpb24gb2YgRiB0aGVuCiAgICBiZWhhdmVzIGxpa2UgYSBjYWxsIHRvIHBhbmljLCB0ZXJtaW5hdGluZyBHJ3MgZXhlY3V0aW9uIGFuZCBydW5uaW5nIGFueQogICAgZGVmZXJyZWQgZnVuY3Rpb25zLiBUaGlzIGNvbnRpbnVlcyB1bnRpbCBhbGwgZnVuY3Rpb25zIGluIHRoZSBleGVjdXRpbmcKICAgIGdvcm91dGluZSBoYXZlIHN0b3BwZWQsIGluIHJldmVyc2Ugb3JkZXIuIEF0IHRoYXQgcG9pbnQsIHRoZSBwcm9ncmFtIGlzCiAgICB0ZXJtaW5hdGVkIHdpdGggYSBub24temVybyBleGl0IGNvZGUuIFRoaXMgdGVybWluYXRpb24gc2VxdWVuY2UgaXMgY2FsbGVkCiAgICBwYW5pY2tpbmcgYW5kIGNhbiBiZSBjb250cm9sbGVkIGJ5IHRoZSBidWlsdC1pbiBmdW5jdGlvbiByZWNvdmVyLgoKICAgIFN0YXJ0aW5nIGluIEdvIDEuMjEsIGNhbGxpbmcgcGFuaWMgd2l0aCBhIG5pbCBpbnRlcmZhY2UgdmFsdWUgb3IgYW4gdW50eXBlZAogICAgbmlsIGNhdXNlcyBhIHJ1bi10aW1lIGVycm9yIChhIGRpZmZlcmVudCBwYW5pYykuIFRoZSBHT0RFQlVHIHNldHRpbmcKICAgIHBhbmljbmlsPTEgZGlzYWJsZXMgdGhlIHJ1bi10aW1lIGVycm9yLg==", - "duration": 2271779833, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc builtin.panic\n\npackage builtin // import \u0026#34;builtin\u0026#34;\n\nfunc panic(v any)\n The panic built-in function stops normal execution of the current goroutine.\n When a function F calls panic, normal execution of F stops immediately.\n Any functions whose execution was deferred by F are run in the usual way,\n and then F returns to its caller. To the caller G, the invocation of F then\n behaves like a call to panic, terminating G\u0026#39;s execution and running any\n deferred functions. This continues until all functions in the executing\n goroutine have stopped, in reverse order. At that point, the program is\n terminated with a non-zero exit code. This termination sequence is called\n panicking and can be controlled by the built-in function recover.\n\n Starting in Go 1.21, calling panic with a nil interface value or an untyped\n nil causes a run-time error (a different panic). The GODEBUG setting\n panicnil=1 disables the run-time error.", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "builtin.panic" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBidWlsdGluIC8vIGltcG9ydCAiYnVpbHRpbiIKCmZ1bmMgcGFuaWModiBhbnkpCiAgICBUaGUgcGFuaWMgYnVpbHQtaW4gZnVuY3Rpb24gc3RvcHMgbm9ybWFsIGV4ZWN1dGlvbiBvZiB0aGUgY3VycmVudCBnb3JvdXRpbmUuCiAgICBXaGVuIGEgZnVuY3Rpb24gRiBjYWxscyBwYW5pYywgbm9ybWFsIGV4ZWN1dGlvbiBvZiBGIHN0b3BzIGltbWVkaWF0ZWx5LgogICAgQW55IGZ1bmN0aW9ucyB3aG9zZSBleGVjdXRpb24gd2FzIGRlZmVycmVkIGJ5IEYgYXJlIHJ1biBpbiB0aGUgdXN1YWwgd2F5LAogICAgYW5kIHRoZW4gRiByZXR1cm5zIHRvIGl0cyBjYWxsZXIuIFRvIHRoZSBjYWxsZXIgRywgdGhlIGludm9jYXRpb24gb2YgRiB0aGVuCiAgICBiZWhhdmVzIGxpa2UgYSBjYWxsIHRvIHBhbmljLCB0ZXJtaW5hdGluZyBHJ3MgZXhlY3V0aW9uIGFuZCBydW5uaW5nIGFueQogICAgZGVmZXJyZWQgZnVuY3Rpb25zLiBUaGlzIGNvbnRpbnVlcyB1bnRpbCBhbGwgZnVuY3Rpb25zIGluIHRoZSBleGVjdXRpbmcKICAgIGdvcm91dGluZSBoYXZlIHN0b3BwZWQsIGluIHJldmVyc2Ugb3JkZXIuIEF0IHRoYXQgcG9pbnQsIHRoZSBwcm9ncmFtIGlzCiAgICB0ZXJtaW5hdGVkIHdpdGggYSBub24temVybyBleGl0IGNvZGUuIFRoaXMgdGVybWluYXRpb24gc2VxdWVuY2UgaXMgY2FsbGVkCiAgICBwYW5pY2tpbmcgYW5kIGNhbiBiZSBjb250cm9sbGVkIGJ5IHRoZSBidWlsdC1pbiBmdW5jdGlvbiByZWNvdmVyLgoKICAgIFN0YXJ0aW5nIGluIEdvIDEuMjEsIGNhbGxpbmcgcGFuaWMgd2l0aCBhIG5pbCBpbnRlcmZhY2UgdmFsdWUgb3IgYW4gdW50eXBlZAogICAgbmlsIGNhdXNlcyBhIHJ1bi10aW1lIGVycm9yIChhIGRpZmZlcmVudCBwYW5pYykuIFRoZSBHT0RFQlVHIHNldHRpbmcKICAgIHBhbmljbmlsPTEgZGlzYWJsZXMgdGhlIHJ1bi10aW1lIGVycm9yLg==", - "duration": 2271779833, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "panic", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.13:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "builtin#panic", - "href": "https://pkg.go.dev/builtin#panic", - "target": "_blank" - }, - "file": "panic", - "nodes": [ - [ - { - "atom": "code", - "file": "panic", - "nodes": [ - { - "text": "panic", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/builtin#panic" - } - ], - { - "text": " function.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 13, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "panic.md", - "level": 2, - "nodes": [ - { - "text": "Recovering From A Panic", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "panic.md", - "nodes": [ - { - "text": "With a combination of the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "panic.md", - "nodes": [ - { - "text": "defer", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " keyword and the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "builtin#recover", - "href": "https://pkg.go.dev/builtin#recover", - "target": "_blank" - }, - "file": "panic.md", - "nodes": [ - { - "atom": "code", - "file": "panic.md", - "nodes": [ - { - "text": "recover", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/builtin#recover" - } - ], - { - "text": " function we can recover from panics in our applications and gracefully handle them.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-14", - "type": "listing" - }, - "file": "panic.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "doc", - "builtin.recover" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "doc": "builtin.recover", - "exec": "go doc builtin.recover" - }, - "expected_exit": 0, - "file": "panic", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc builtin.recover\n\npackage builtin // import \u0026#34;builtin\u0026#34;\n\nfunc recover() any\n The recover built-in function allows a program to manage behavior of\n a panicking goroutine. Executing a call to recover inside a deferred\n function (but not any function called by it) stops the panicking sequence\n by restoring normal execution and retrieves the error value passed to the\n call of panic. If recover is called outside the deferred function it will\n not stop a panicking sequence. In this case, or when the goroutine is not\n panicking, or if the argument supplied to panic was nil, recover returns\n nil. Thus the return value from recover reports whether the goroutine is\n panicking.", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "builtin.recover" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBidWlsdGluIC8vIGltcG9ydCAiYnVpbHRpbiIKCmZ1bmMgcmVjb3ZlcigpIGFueQogICAgVGhlIHJlY292ZXIgYnVpbHQtaW4gZnVuY3Rpb24gYWxsb3dzIGEgcHJvZ3JhbSB0byBtYW5hZ2UgYmVoYXZpb3Igb2YKICAgIGEgcGFuaWNraW5nIGdvcm91dGluZS4gRXhlY3V0aW5nIGEgY2FsbCB0byByZWNvdmVyIGluc2lkZSBhIGRlZmVycmVkCiAgICBmdW5jdGlvbiAoYnV0IG5vdCBhbnkgZnVuY3Rpb24gY2FsbGVkIGJ5IGl0KSBzdG9wcyB0aGUgcGFuaWNraW5nIHNlcXVlbmNlCiAgICBieSByZXN0b3Jpbmcgbm9ybWFsIGV4ZWN1dGlvbiBhbmQgcmV0cmlldmVzIHRoZSBlcnJvciB2YWx1ZSBwYXNzZWQgdG8gdGhlCiAgICBjYWxsIG9mIHBhbmljLiBJZiByZWNvdmVyIGlzIGNhbGxlZCBvdXRzaWRlIHRoZSBkZWZlcnJlZCBmdW5jdGlvbiBpdCB3aWxsCiAgICBub3Qgc3RvcCBhIHBhbmlja2luZyBzZXF1ZW5jZS4gSW4gdGhpcyBjYXNlLCBvciB3aGVuIHRoZSBnb3JvdXRpbmUgaXMgbm90CiAgICBwYW5pY2tpbmcsIG9yIGlmIHRoZSBhcmd1bWVudCBzdXBwbGllZCB0byBwYW5pYyB3YXMgbmlsLCByZWNvdmVyIHJldHVybnMKICAgIG5pbC4gVGh1cyB0aGUgcmV0dXJuIHZhbHVlIGZyb20gcmVjb3ZlciByZXBvcnRzIHdoZXRoZXIgdGhlIGdvcm91dGluZSBpcwogICAgcGFuaWNraW5nLg==", - "duration": 2024148333, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc builtin.recover\n\npackage builtin // import \u0026#34;builtin\u0026#34;\n\nfunc recover() any\n The recover built-in function allows a program to manage behavior of\n a panicking goroutine. Executing a call to recover inside a deferred\n function (but not any function called by it) stops the panicking sequence\n by restoring normal execution and retrieves the error value passed to the\n call of panic. If recover is called outside the deferred function it will\n not stop a panicking sequence. In this case, or when the goroutine is not\n panicking, or if the argument supplied to panic was nil, recover returns\n nil. Thus the return value from recover reports whether the goroutine is\n panicking.", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "builtin.recover" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBidWlsdGluIC8vIGltcG9ydCAiYnVpbHRpbiIKCmZ1bmMgcmVjb3ZlcigpIGFueQogICAgVGhlIHJlY292ZXIgYnVpbHQtaW4gZnVuY3Rpb24gYWxsb3dzIGEgcHJvZ3JhbSB0byBtYW5hZ2UgYmVoYXZpb3Igb2YKICAgIGEgcGFuaWNraW5nIGdvcm91dGluZS4gRXhlY3V0aW5nIGEgY2FsbCB0byByZWNvdmVyIGluc2lkZSBhIGRlZmVycmVkCiAgICBmdW5jdGlvbiAoYnV0IG5vdCBhbnkgZnVuY3Rpb24gY2FsbGVkIGJ5IGl0KSBzdG9wcyB0aGUgcGFuaWNraW5nIHNlcXVlbmNlCiAgICBieSByZXN0b3Jpbmcgbm9ybWFsIGV4ZWN1dGlvbiBhbmQgcmV0cmlldmVzIHRoZSBlcnJvciB2YWx1ZSBwYXNzZWQgdG8gdGhlCiAgICBjYWxsIG9mIHBhbmljLiBJZiByZWNvdmVyIGlzIGNhbGxlZCBvdXRzaWRlIHRoZSBkZWZlcnJlZCBmdW5jdGlvbiBpdCB3aWxsCiAgICBub3Qgc3RvcCBhIHBhbmlja2luZyBzZXF1ZW5jZS4gSW4gdGhpcyBjYXNlLCBvciB3aGVuIHRoZSBnb3JvdXRpbmUgaXMgbm90CiAgICBwYW5pY2tpbmcsIG9yIGlmIHRoZSBhcmd1bWVudCBzdXBwbGllZCB0byBwYW5pYyB3YXMgbmlsLCByZWNvdmVyIHJldHVybnMKICAgIG5pbC4gVGh1cyB0aGUgcmV0dXJuIHZhbHVlIGZyb20gcmVjb3ZlciByZXBvcnRzIHdoZXRoZXIgdGhlIGdvcm91dGluZSBpcwogICAgcGFuaWNraW5nLg==", - "duration": 2024148333, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "panic", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.14:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "builtin#recover", - "href": "https://pkg.go.dev/builtin#recover", - "target": "_blank" - }, - "file": "panic", - "nodes": [ - [ - { - "atom": "code", - "file": "panic", - "nodes": [ - { - "text": "recover", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/builtin#recover" - } - ], - { - "text": " function.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 14, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "panic.md", - "nodes": [ - { - "text": "In ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-15" - }, - "file": "panic.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-15" - }, - "nodes": [ - { - "text": "Listing 1.15", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-15" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", before we run the code that will panic, we use the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "panic.md", - "nodes": [ - { - "text": "defer", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " keyword to execute an anonymous function that will run before the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "panic.md", - "nodes": [ - { - "text": "main", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function exits. Inside of the deferred function we can call the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "builtin#recover", - "href": "https://pkg.go.dev/builtin#recover", - "target": "_blank" - }, - "file": "panic.md", - "nodes": [ - { - "atom": "code", - "file": "panic.md", - "nodes": [ - { - "text": "recover", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/builtin#recover" - } - ], - { - "text": " function and check its return value for ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "panic.md", - "nodes": [ - { - "text": "nil", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ". A non-", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "panic.md", - "nodes": [ - { - "text": "nil", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " value will be returned from the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "builtin#recover", - "href": "https://pkg.go.dev/builtin#recover", - "target": "_blank" - }, - "file": "panic.md", - "nodes": [ - { - "atom": "code", - "file": "panic.md", - "nodes": [ - { - "text": "recover", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/builtin#recover" - } - ], - { - "text": " function if a panic occurred.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "panic.md", - "nodes": [ - { - "text": "Now, when the panic occurs, it is caught by the deferred ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "builtin#recover", - "href": "https://pkg.go.dev/builtin#recover", - "target": "_blank" - }, - "file": "panic.md", - "nodes": [ - { - "atom": "code", - "file": "panic.md", - "nodes": [ - { - "text": "recover", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/builtin#recover" - } - ], - { - "text": " and can be handled gracefully.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-15", - "type": "listing" - }, - "file": "panic.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "panic", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "panic/src/recover/main.go#example" - }, - "lang": "go", - "nodes": [ - { - "content": "func main() {\n\tdefer func() {\n\t\tif i := recover(); i != nil {\n\t\t\tfmt.Println(\"oh no, a panic occurred:\", i)\n\t\t}\n\t}()\n\n\ta := []string{}\n\ta[42] = \"Bring a towel\"\n}", - "file": "panic/src/recover/main.go", - "lang": "go", - "name": "example", - "start": 5, - "end": 17, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "atom": "hr", - "file": "panic", - "type": "*hype.Element" - }, - [ - { - "args": [ - "go", - "run", - "." - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go run .", - "run": ".", - "src": "panic/src/recover" - }, - "expected_exit": 0, - "file": "panic", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\noh no, a panic occurred: runtime error: index out of range [42] with length 0", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/recover", - "stdout": "b2ggbm8sIGEgcGFuaWMgb2NjdXJyZWQ6IHJ1bnRpbWUgZXJyb3I6IGluZGV4IG91dCBvZiByYW5nZSBbNDJdIHdpdGggbGVuZ3RoIDA=", - "duration": 3066097208, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\noh no, a panic occurred: runtime error: index out of range [42] with length 0", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/recover", - "stdout": "b2ggbm8sIGEgcGFuaWMgb2NjdXJyZWQ6IHJ1bnRpbWUgZXJyb3I6IGluZGV4IG91dCBvZiByYW5nZSBbNDJdIHdpdGggbGVuZ3RoIDA=", - "duration": 3066097208, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "panic", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.15:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Recovering from a panic.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 15, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "panic.md", - "nodes": [ - { - "text": "While this is not the common use case for using ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "builtin#recover", - "href": "https://pkg.go.dev/builtin#recover", - "target": "_blank" - }, - "file": "panic.md", - "nodes": [ - { - "atom": "code", - "file": "panic.md", - "nodes": [ - { - "text": "recover", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/builtin#recover" - } - ], - { - "text": ", it does show the mechanics of how it works. It is more common to use recover when your application calls a user defined function that is passed in as an argument.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "panic.md", - "nodes": [ - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-16" - }, - "file": "panic.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-16" - }, - "nodes": [ - { - "text": "Listing 1.16", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-16" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": " is an example of a function that takes a user defined function to match a specific string. If the function passed in panics, it will result in the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "panic.md", - "nodes": [ - { - "text": "sanitize", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function panicking as well.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-16", - "type": "listing" - }, - "file": "panic.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "panic", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "panic/src/matcher/bad/main.go#matcher" - }, - "lang": "go", - "nodes": [ - { - "content": "type matcher func(rune) bool\n\nfunc sanitize(m matcher, s string) (string, error) {\n\tvar val string\n\n\t// iterate over the runes in the string\n\tfor _, c := range s {\n\n\t\t// call the matcher function\n\t\t// with the rune as the argument\n\t\tif m(c) {\n\t\t\t// append `*` to the result\n\t\t\tval = val + \"*\"\n\t\t\t// continue to the next rune\n\t\t\tcontinue\n\t\t}\n\n\t\t// append the rune to the result\n\t\tval = val + string(c)\n\t}\n\n\t// return the sanitized string\n\treturn val, nil\n}", - "file": "panic/src/matcher/bad/main.go", - "lang": "go", - "name": "matcher", - "start": 33, - "end": 59, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "panic", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "panic/src/matcher/bad/main.go#bad" - }, - "lang": "go", - "nodes": [ - { - "content": "func main() {\n\n\t// create a matcher function\n\tm := func(r rune) bool {\n\t\t// simulate doing something bad...\n\t\tpanic(\"hahaha\")\n\n\t\t// unreachable code\n\t\treturn false\n\t}\n\n\t// sanitize the string\n\ts, err := sanitize(m, \"go is awesome\")\n\tif err != nil {\n\t\t// handle the error\n\t\tlog.Fatal(err)\n\t}\n\n\t// print the sanitized string\n\tfmt.Println(s)\n}", - "file": "panic/src/matcher/bad/main.go", - "lang": "go", - "name": "bad", - "start": 8, - "end": 31, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "atom": "hr", - "file": "panic", - "type": "*hype.Element" - }, - [ - { - "args": [ - "go", - "run", - "." - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go run .", - "exit": "-1", - "run": ".", - "src": "panic/src/matcher/bad" - }, - "expected_exit": -1, - "file": "panic", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\npanic: hahaha\n\ngoroutine 1 [running]:\nmain.main.func1(0xa41ee0?)\n\t./main.go:14 +0x2c\nmain.sanitize(0x10099af00, {0x10095ea20, 0xd})\n\t./main.go:44 +0xa4\nmain.main()\n\t./main.go:21 +0x30\nexit status 2", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/matcher/bad", - "err": { - "Stderr": null - }, - "exit": 1, - "stderr": "cGFuaWM6IGhhaGFoYQoKZ29yb3V0aW5lIDEgW3J1bm5pbmddOgptYWluLm1haW4uZnVuYzEoMHhhNDFlZTA/KQoJL1VzZXJzL21hcmtiYXRlcy9MaWJyYXJ5L0Nsb3VkU3RvcmFnZS9Ecm9wYm94L2Rldi9ndWlkZXMvY29udGVudC9ib29rL2NoYXB0ZXJzLzA5LWVycm9ycy9wYW5pYy9zcmMvbWF0Y2hlci9iYWQvbWFpbi5nbzoxNCArMHgyYwptYWluLnNhbml0aXplKDB4MTAwOTlhZjAwLCB7MHgxMDA5NWVhMjAsIDB4ZH0pCgkvVXNlcnMvbWFya2JhdGVzL0xpYnJhcnkvQ2xvdWRTdG9yYWdlL0Ryb3Bib3gvZGV2L2d1aWRlcy9jb250ZW50L2Jvb2svY2hhcHRlcnMvMDktZXJyb3JzL3BhbmljL3NyYy9tYXRjaGVyL2JhZC9tYWluLmdvOjQ0ICsweGE0Cm1haW4ubWFpbigpCgkvVXNlcnMvbWFya2JhdGVzL0xpYnJhcnkvQ2xvdWRTdG9yYWdlL0Ryb3Bib3gvZGV2L2d1aWRlcy9jb250ZW50L2Jvb2svY2hhcHRlcnMvMDktZXJyb3JzL3BhbmljL3NyYy9tYXRjaGVyL2JhZC9tYWluLmdvOjIxICsweDMwCmV4aXQgc3RhdHVzIDI=", - "duration": 2516479917, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\npanic: hahaha\n\ngoroutine 1 [running]:\nmain.main.func1(0xa41ee0?)\n\t./main.go:14 +0x2c\nmain.sanitize(0x10099af00, {0x10095ea20, 0xd})\n\t./main.go:44 +0xa4\nmain.main()\n\t./main.go:21 +0x30\nexit status 2", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/matcher/bad", - "err": { - "Stderr": null - }, - "exit": 1, - "stderr": "cGFuaWM6IGhhaGFoYQoKZ29yb3V0aW5lIDEgW3J1bm5pbmddOgptYWluLm1haW4uZnVuYzEoMHhhNDFlZTA/KQoJL1VzZXJzL21hcmtiYXRlcy9MaWJyYXJ5L0Nsb3VkU3RvcmFnZS9Ecm9wYm94L2Rldi9ndWlkZXMvY29udGVudC9ib29rL2NoYXB0ZXJzLzA5LWVycm9ycy9wYW5pYy9zcmMvbWF0Y2hlci9iYWQvbWFpbi5nbzoxNCArMHgyYwptYWluLnNhbml0aXplKDB4MTAwOTlhZjAwLCB7MHgxMDA5NWVhMjAsIDB4ZH0pCgkvVXNlcnMvbWFya2JhdGVzL0xpYnJhcnkvQ2xvdWRTdG9yYWdlL0Ryb3Bib3gvZGV2L2d1aWRlcy9jb250ZW50L2Jvb2svY2hhcHRlcnMvMDktZXJyb3JzL3BhbmljL3NyYy9tYXRjaGVyL2JhZC9tYWluLmdvOjQ0ICsweGE0Cm1haW4ubWFpbigpCgkvVXNlcnMvbWFya2JhdGVzL0xpYnJhcnkvQ2xvdWRTdG9yYWdlL0Ryb3Bib3gvZGV2L2d1aWRlcy9jb250ZW50L2Jvb2svY2hhcHRlcnMvMDktZXJyb3JzL3BhbmljL3NyYy9tYXRjaGVyL2JhZC9tYWluLmdvOjIxICsweDMwCmV4aXQgc3RhdHVzIDI=", - "duration": 2516479917, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "panic", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.16:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "A function that sanitizes a given string.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 16, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "panic.md", - "nodes": [ - { - "text": "However, if we use a ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "builtin#recover", - "href": "https://pkg.go.dev/builtin#recover", - "target": "_blank" - }, - "file": "panic.md", - "nodes": [ - { - "atom": "code", - "file": "panic.md", - "nodes": [ - { - "text": "recover", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/builtin#recover" - } - ], - { - "text": " in the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "panic.md", - "nodes": [ - { - "text": "sanitize", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function, we can gracefully handle any potential panic that the user provided function may create. In ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-17" - }, - "file": "panic.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-17" - }, - "nodes": [ - { - "text": "Listing 1.17", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-17" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", we use the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "builtin#recover", - "href": "https://pkg.go.dev/builtin#recover", - "target": "_blank" - }, - "file": "panic.md", - "nodes": [ - { - "atom": "code", - "file": "panic.md", - "nodes": [ - { - "text": "recover", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/builtin#recover" - } - ], - { - "text": " to handle panics in the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "panic.md", - "nodes": [ - { - "text": "sanitize", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-17", - "type": "listing" - }, - "file": "panic.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "panic", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "panic/src/matcher/good/main.go#matcher" - }, - "lang": "go", - "nodes": [ - { - "content": "func sanitize(m matcher, s string) (val string, err error) {\n\t// guard against an invalid matcher that could panic\n\tdefer func() {\n\t\tif e := recover(); e != nil {\n\t\t\terr = fmt.Errorf(\"invalid matcher. panic occurred: %v\", e)\n\t\t}\n\t}()\n\n\tfor _, c := range s {\n\t\tif m(c) {\n\t\t\tval = val + \"*\"\n\t\t\tcontinue\n\t\t}\n\t\tval = val + string(c)\n\t}\n\treturn\n}", - "file": "panic/src/matcher/good/main.go", - "lang": "go", - "name": "matcher", - "start": 25, - "end": 44, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "atom": "hr", - "file": "panic", - "type": "*hype.Element" - }, - [ - { - "args": [ - "go", - "run", - "." - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go run .", - "run": ".", - "src": "panic/src/matcher/good" - }, - "expected_exit": 0, - "file": "panic", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\ninvalid matcher. panic occurred: hahaha", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/matcher/good", - "stdout": "aW52YWxpZCBtYXRjaGVyLiBwYW5pYyBvY2N1cnJlZDogaGFoYWhh", - "duration": 2408103666, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\ninvalid matcher. panic occurred: hahaha", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/matcher/good", - "stdout": "aW52YWxpZCBtYXRjaGVyLiBwYW5pYyBvY2N1cnJlZDogaGFoYWhh", - "duration": 2408103666, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "panic", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.17:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "A function that sanitizes a given string.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 17, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "panic.md", - "nodes": [ - { - "text": "Now, if a user inadvertently raises a panic in the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "panic.md", - "nodes": [ - { - "text": "matcher", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function provided, the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "panic.md", - "nodes": [ - { - "text": "sanitize", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function will handle it gracefully and return an error, instead of panicking as well.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "panic.md", - "level": 2, - "nodes": [ - { - "text": "Capturing and Returning Panic Values", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "panic.md", - "nodes": [ - { - "text": "When something panics in Go you have three options for how to handle the panic. ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-18" - }, - "file": "panic.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-18" - }, - "nodes": [ - { - "text": "Listing 1.18", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-18" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": " lists the three options.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-18", - "type": "listing" - }, - "file": "panic.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "ol", - "file": "panic", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "li", - "file": "panic", - "list-type": "ol", - "nodes": [ - { - "text": "You can let the panic crash the application and deal with the fall out.", - "type": "hype.Text" - } - ], - "type": "*hype.LI" - } - ], - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "li", - "file": "panic", - "list-type": "ol", - "nodes": [ - { - "text": "You can recover from the panic, log it, and move on.", - "type": "hype.Text" - } - ], - "type": "*hype.LI" - } - ], - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "li", - "file": "panic", - "list-type": "ol", - "nodes": [ - { - "text": "You can properly capture the panicked value and return it as an error.", - "type": "hype.Text" - } - ], - "type": "*hype.LI" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "type": "*hype.OL" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "panic", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.18:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Three options for handling panics.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 18, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "panic.md", - "nodes": [ - { - "text": "This last option, in ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-18" - }, - "file": "panic.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-18" - }, - "nodes": [ - { - "text": "Listing 1.18", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-18" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", gives you the most control over recovering from panics. However, it requires a number of steps, and functions, to make this happen.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "panic.md", - "nodes": [ - { - "text": "Consider the function, ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "panic.md", - "nodes": [ - { - "text": "DoSomething(int)", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ", in ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-19" - }, - "file": "panic.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-19" - }, - "nodes": [ - { - "text": "Listing 1.19", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-19" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": " that takes an integer and either returns ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "panic.md", - "nodes": [ - { - "text": "nil", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " or panics.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-19", - "type": "listing" - }, - "file": "panic.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "panic", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "panic/src/recover-broken/recover.go#example" - }, - "lang": "go", - "nodes": [ - { - "content": "func DoSomething(input int) error {\n\tswitch input {\n\tcase 0:\n\t\t// input was 0, return no error (nil)\n\t\treturn nil\n\tcase 1:\n\t\t// input was 1, panic with the string \"one\"\n\t\tpanic(\"one\")\n\t}\n\n\t// no case was matched\n\treturn nil\n}", - "file": "panic/src/recover-broken/recover.go", - "lang": "go", - "name": "example", - "start": 3, - "end": 18, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "panic", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.19:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "A function that returns ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "panic", - "nodes": [ - { - "text": "nil", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " or panics.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 19, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "panic.md", - "nodes": [ - { - "text": "In ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-20" - }, - "file": "panic.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-20" - }, - "nodes": [ - { - "text": "Listing 1.20", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-20" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": " we have a test for the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "panic.md", - "nodes": [ - { - "text": "DoSomething(int)", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function. When we call the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "panic.md", - "nodes": [ - { - "text": "DoSomething(int)", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function with the value ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "panic.md", - "nodes": [ - { - "text": "1", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ", the test panics.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-20", - "type": "listing" - }, - "file": "panic.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "panic", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "panic/src/recover-broken/recover_test.go#test" - }, - "lang": "go", - "nodes": [ - { - "content": "func Test_DoSomething(t *testing.T) {\n\tt.Parallel()\n\n\terr := DoSomething(0)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\terr = DoSomething(1)\n\n\tif err != nil {\n\t\tt.Fatal(\"expected nil, got\", err)\n\t}\n}", - "file": "panic/src/recover-broken/recover_test.go", - "lang": "go", - "name": "test", - "start": 7, - "end": 23, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "atom": "hr", - "file": "panic", - "type": "*hype.Element" - }, - [ - { - "args": [ - "go", - "test", - "-v" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go test -v", - "exit": "-1", - "src": "panic/src/recover-broken", - "test": "-v" - }, - "expected_exit": -1, - "file": "panic", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go test -v\n\n=== RUN Test_DoSomething\n=== PAUSE Test_DoSomething\n=== CONT Test_DoSomething\n--- FAIL: Test_DoSomething (0.00s)\npanic: one [recovered]\n\tpanic: one\n\ngoroutine 5 [running]:\ntesting.tRunner.func1.2({0x1003b4ee0, 0x1003db8c8})\n\t/usr/local/go/src/testing/testing.go:1545 +0x1c4\ntesting.tRunner.func1()\n\t/usr/local/go/src/testing/testing.go:1548 +0x360\npanic({0x1003b4ee0?, 0x1003db8c8?})\n\t/usr/local/go/src/runtime/panic.go:914 +0x218\ndemo.DoSomething(...)\n\t./recover.go:11\ndemo.Test_DoSomething(0x0?)\n\t./recover_test.go:16 +0x34\ntesting.tRunner(0x14000003860, 0x1003db0c0)\n\t/usr/local/go/src/testing/testing.go:1595 +0xe8\ncreated by testing.(*T).Run in goroutine 1\n\t/usr/local/go/src/testing/testing.go:1648 +0x33c\nexit status 2\nFAIL\tdemo\t1.854s", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "test", - "-v" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/recover-broken", - "err": { - "Stderr": null - }, - "exit": 1, - "stdout": "PT09IFJVTiAgIFRlc3RfRG9Tb21ldGhpbmcKPT09IFBBVVNFIFRlc3RfRG9Tb21ldGhpbmcKPT09IENPTlQgIFRlc3RfRG9Tb21ldGhpbmcKLS0tIEZBSUw6IFRlc3RfRG9Tb21ldGhpbmcgKDAuMDBzKQpwYW5pYzogb25lIFtyZWNvdmVyZWRdCglwYW5pYzogb25lCgpnb3JvdXRpbmUgNSBbcnVubmluZ106CnRlc3RpbmcudFJ1bm5lci5mdW5jMS4yKHsweDEwMDNiNGVlMCwgMHgxMDAzZGI4Yzh9KQoJL3Vzci9sb2NhbC9nby9zcmMvdGVzdGluZy90ZXN0aW5nLmdvOjE1NDUgKzB4MWM0CnRlc3RpbmcudFJ1bm5lci5mdW5jMSgpCgkvdXNyL2xvY2FsL2dvL3NyYy90ZXN0aW5nL3Rlc3RpbmcuZ286MTU0OCArMHgzNjAKcGFuaWMoezB4MTAwM2I0ZWUwPywgMHgxMDAzZGI4Yzg/fSkKCS91c3IvbG9jYWwvZ28vc3JjL3J1bnRpbWUvcGFuaWMuZ286OTE0ICsweDIxOApkZW1vLkRvU29tZXRoaW5nKC4uLikKCS9Vc2Vycy9tYXJrYmF0ZXMvTGlicmFyeS9DbG91ZFN0b3JhZ2UvRHJvcGJveC9kZXYvZ3VpZGVzL2NvbnRlbnQvYm9vay9jaGFwdGVycy8wOS1lcnJvcnMvcGFuaWMvc3JjL3JlY292ZXItYnJva2VuL3JlY292ZXIuZ286MTEKZGVtby5UZXN0X0RvU29tZXRoaW5nKDB4MD8pCgkvVXNlcnMvbWFya2JhdGVzL0xpYnJhcnkvQ2xvdWRTdG9yYWdlL0Ryb3Bib3gvZGV2L2d1aWRlcy9jb250ZW50L2Jvb2svY2hhcHRlcnMvMDktZXJyb3JzL3BhbmljL3NyYy9yZWNvdmVyLWJyb2tlbi9yZWNvdmVyX3Rlc3QuZ286MTYgKzB4MzQKdGVzdGluZy50UnVubmVyKDB4MTQwMDAwMDM4NjAsIDB4MTAwM2RiMGMwKQoJL3Vzci9sb2NhbC9nby9zcmMvdGVzdGluZy90ZXN0aW5nLmdvOjE1OTUgKzB4ZTgKY3JlYXRlZCBieSB0ZXN0aW5nLigqVCkuUnVuIGluIGdvcm91dGluZSAxCgkvdXNyL2xvY2FsL2dvL3NyYy90ZXN0aW5nL3Rlc3RpbmcuZ286MTY0OCArMHgzM2MKZXhpdCBzdGF0dXMgMgpGQUlMCWRlbW8JMS44NTRz", - "duration": 4698238959, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go test -v\n\n=== RUN Test_DoSomething\n=== PAUSE Test_DoSomething\n=== CONT Test_DoSomething\n--- FAIL: Test_DoSomething (0.00s)\npanic: one [recovered]\n\tpanic: one\n\ngoroutine 5 [running]:\ntesting.tRunner.func1.2({0x1003b4ee0, 0x1003db8c8})\n\t/usr/local/go/src/testing/testing.go:1545 +0x1c4\ntesting.tRunner.func1()\n\t/usr/local/go/src/testing/testing.go:1548 +0x360\npanic({0x1003b4ee0?, 0x1003db8c8?})\n\t/usr/local/go/src/runtime/panic.go:914 +0x218\ndemo.DoSomething(...)\n\t./recover.go:11\ndemo.Test_DoSomething(0x0?)\n\t./recover_test.go:16 +0x34\ntesting.tRunner(0x14000003860, 0x1003db0c0)\n\t/usr/local/go/src/testing/testing.go:1595 +0xe8\ncreated by testing.(*T).Run in goroutine 1\n\t/usr/local/go/src/testing/testing.go:1648 +0x33c\nexit status 2\nFAIL\tdemo\t1.854s", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "test", - "-v" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/recover-broken", - "err": { - "Stderr": null - }, - "exit": 1, - "stdout": "PT09IFJVTiAgIFRlc3RfRG9Tb21ldGhpbmcKPT09IFBBVVNFIFRlc3RfRG9Tb21ldGhpbmcKPT09IENPTlQgIFRlc3RfRG9Tb21ldGhpbmcKLS0tIEZBSUw6IFRlc3RfRG9Tb21ldGhpbmcgKDAuMDBzKQpwYW5pYzogb25lIFtyZWNvdmVyZWRdCglwYW5pYzogb25lCgpnb3JvdXRpbmUgNSBbcnVubmluZ106CnRlc3RpbmcudFJ1bm5lci5mdW5jMS4yKHsweDEwMDNiNGVlMCwgMHgxMDAzZGI4Yzh9KQoJL3Vzci9sb2NhbC9nby9zcmMvdGVzdGluZy90ZXN0aW5nLmdvOjE1NDUgKzB4MWM0CnRlc3RpbmcudFJ1bm5lci5mdW5jMSgpCgkvdXNyL2xvY2FsL2dvL3NyYy90ZXN0aW5nL3Rlc3RpbmcuZ286MTU0OCArMHgzNjAKcGFuaWMoezB4MTAwM2I0ZWUwPywgMHgxMDAzZGI4Yzg/fSkKCS91c3IvbG9jYWwvZ28vc3JjL3J1bnRpbWUvcGFuaWMuZ286OTE0ICsweDIxOApkZW1vLkRvU29tZXRoaW5nKC4uLikKCS9Vc2Vycy9tYXJrYmF0ZXMvTGlicmFyeS9DbG91ZFN0b3JhZ2UvRHJvcGJveC9kZXYvZ3VpZGVzL2NvbnRlbnQvYm9vay9jaGFwdGVycy8wOS1lcnJvcnMvcGFuaWMvc3JjL3JlY292ZXItYnJva2VuL3JlY292ZXIuZ286MTEKZGVtby5UZXN0X0RvU29tZXRoaW5nKDB4MD8pCgkvVXNlcnMvbWFya2JhdGVzL0xpYnJhcnkvQ2xvdWRTdG9yYWdlL0Ryb3Bib3gvZGV2L2d1aWRlcy9jb250ZW50L2Jvb2svY2hhcHRlcnMvMDktZXJyb3JzL3BhbmljL3NyYy9yZWNvdmVyLWJyb2tlbi9yZWNvdmVyX3Rlc3QuZ286MTYgKzB4MzQKdGVzdGluZy50UnVubmVyKDB4MTQwMDAwMDM4NjAsIDB4MTAwM2RiMGMwKQoJL3Vzci9sb2NhbC9nby9zcmMvdGVzdGluZy90ZXN0aW5nLmdvOjE1OTUgKzB4ZTgKY3JlYXRlZCBieSB0ZXN0aW5nLigqVCkuUnVuIGluIGdvcm91dGluZSAxCgkvdXNyL2xvY2FsL2dvL3NyYy90ZXN0aW5nL3Rlc3RpbmcuZ286MTY0OCArMHgzM2MKZXhpdCBzdGF0dXMgMgpGQUlMCWRlbW8JMS44NTRz", - "duration": 4698238959, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "panic", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.20:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "A test for the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "panic", - "nodes": [ - { - "text": "DoSomething(1)", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function in ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-19" - }, - "file": "panic", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-19" - }, - "nodes": [ - { - "text": "Listing 1.19", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-19" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 20, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "panic.md", - "nodes": [ - { - "text": "To fix this problem we need to properly recover from the panic being raised in the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "panic.md", - "nodes": [ - { - "text": "DoSomething(int)", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function. ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-21" - }, - "file": "panic.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-21" - }, - "nodes": [ - { - "text": "Listing 1.21", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-21" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": " outlines the steps required to properly recover from a panic.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-21", - "type": "listing" - }, - "file": "panic.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "ol", - "file": "panic", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "li", - "file": "panic", - "list-type": "ol", - "nodes": [ - { - "text": "Use a ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "panic", - "nodes": [ - { - "text": "defer", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " with a ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "builtin#recover", - "href": "https://pkg.go.dev/builtin#recover", - "target": "_blank" - }, - "file": "panic", - "nodes": [ - [ - { - "atom": "code", - "file": "panic", - "nodes": [ - { - "text": "recover", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/builtin#recover" - } - ], - { - "text": " to catch the panic.", - "type": "hype.Text" - } - ], - "type": "*hype.LI" - } - ], - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "li", - "file": "panic", - "list-type": "ol", - "nodes": [ - { - "text": "Use type assertion on the value returned from the panic to see if it was an ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "builtin#error", - "href": "https://pkg.go.dev/builtin#error", - "target": "_blank" - }, - "file": "panic", - "nodes": [ - [ - { - "atom": "code", - "file": "panic", - "nodes": [ - { - "text": "error", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/builtin#error" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.LI" - } - ], - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "li", - "file": "panic", - "list-type": "ol", - "nodes": [ - { - "text": "Use a ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "panic", - "nodes": [ - { - "text": "named", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " return to allow sending back of the error from the deferred recover.", - "type": "hype.Text" - } - ], - "type": "*hype.LI" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "type": "*hype.OL" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "panic", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.21:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Steps for recovering from a panic.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 21, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "panic.md", - "nodes": [ - { - "text": "In ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-22" - }, - "file": "panic.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-22" - }, - "nodes": [ - { - "text": "Listing 1.22", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-22" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", we implement the steps outlined in ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-21" - }, - "file": "panic.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-21" - }, - "nodes": [ - { - "text": "Listing 1.21", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-21" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": " to properly recover from the panic. As we see in ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-22" - }, - "file": "panic.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-22" - }, - "nodes": [ - { - "text": "Listing 1.22", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-22" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", we implemented the fix in the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "panic.md", - "nodes": [ - { - "text": "DoSomething(int)", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function, and not in the test. This is because it is the responsibility of the function that panics to properly recover from it.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-22", - "type": "listing" - }, - "file": "panic.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "panic", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "panic/src/recover-named/recover.go#example" - }, - "lang": "go", - "nodes": [ - { - "content": "func DoSomething(input int) (err error) {\n\t// defer a function to recover from the panic\n\tdefer func() {\n\t\tp := recover()\n\t\tif p == nil {\n\t\t\t// a nil was return, no panic was raised\n\t\t\t// return from the deferred function.\n\t\t\treturn\n\t\t}\n\n\t\t// check if the recovered value is already an error\n\t\tif e, ok := p.(error); ok {\n\t\t\t// assign the recovered error to the perr variable\n\t\t\t// outside of the anonymous function scope\n\t\t\terr = e\n\t\t\treturn\n\t\t}\n\n\t\t// a non-error value was recovered\n\t\t// create a new error, `ErrNonErrCaught`, with\n\t\t// information about the recovered value\n\t\tmsg := fmt.Sprintf(\"non-error panic type %T %s\", p, p)\n\t\terr = ErrNonErrCaught(msg)\n\t}()\n\n\tswitch input {\n\tcase 0:\n\t\t// input was 0, return no error (nil)\n\t\treturn nil\n\tcase 1:\n\t\t// input was 1, panic with the string \"one\"\n\t\tpanic(\"one\")\n\t}\n\n\t// no case was matched\n\treturn nil\n}\n\ntype ErrNonErrCaught string\n\nfunc (e ErrNonErrCaught) Error() string {\n\treturn string(e)\n}", - "file": "panic/src/recover-named/recover.go", - "lang": "go", - "name": "example", - "start": 7, - "end": 52, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "panic", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.22:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Properly returning from a panic.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 22, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "panic.md", - "nodes": [ - { - "text": "First, we have changed our function signature to use a named return for the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "builtin#error", - "href": "https://pkg.go.dev/builtin#error", - "target": "_blank" - }, - "file": "panic.md", - "nodes": [ - { - "atom": "code", - "file": "panic.md", - "nodes": [ - { - "text": "error", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/builtin#error" - } - ], - { - "text": ", ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "panic.md", - "nodes": [ - { - "text": "(err error)", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ". This will allow us to set the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "builtin#error", - "href": "https://pkg.go.dev/builtin#error", - "target": "_blank" - }, - "file": "panic.md", - "nodes": [ - { - "atom": "code", - "file": "panic.md", - "nodes": [ - { - "text": "error", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/builtin#error" - } - ], - { - "text": " value inside the deferred function. Once inside the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "panic.md", - "nodes": [ - { - "text": "DoSomething(int)", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function, we use the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "panic.md", - "nodes": [ - { - "text": "defer", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " keyword and an anonymous function to catch the panic. Inside of the anonymous function, we use the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "builtin#recover", - "href": "https://pkg.go.dev/builtin#recover", - "target": "_blank" - }, - "file": "panic.md", - "nodes": [ - { - "atom": "code", - "file": "panic.md", - "nodes": [ - { - "text": "recover", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/builtin#recover" - } - ], - { - "text": " function to recover from the panic, and assign the value returned to the variable ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "panic.md", - "nodes": [ - { - "text": "p", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "panic.md", - "nodes": [ - { - "text": "As we see in ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-14" - }, - "file": "panic.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-14" - }, - "nodes": [ - { - "text": "Listing 1.14", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-14" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "builtin#recover", - "href": "https://pkg.go.dev/builtin#recover", - "target": "_blank" - }, - "file": "panic.md", - "nodes": [ - { - "atom": "code", - "file": "panic.md", - "nodes": [ - { - "text": "recover", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/builtin#recover" - } - ], - { - "text": " function returns ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "panic.md", - "nodes": [ - { - "text": "any", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ". This means that the value can be of any type, a ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "panic.md", - "nodes": [ - { - "text": "string", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ", ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "panic.md", - "nodes": [ - { - "text": "int", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ", an ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "builtin#error", - "href": "https://pkg.go.dev/builtin#error", - "target": "_blank" - }, - "file": "panic.md", - "nodes": [ - { - "atom": "code", - "file": "panic.md", - "nodes": [ - { - "text": "error", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/builtin#error" - } - ], - { - "text": ", or ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "panic.md", - "nodes": [ - { - "text": "nil", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ". As result, we must use type assertions to check the type of the value returned from the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "builtin#recover", - "href": "https://pkg.go.dev/builtin#recover", - "target": "_blank" - }, - "file": "panic.md", - "nodes": [ - { - "atom": "code", - "file": "panic.md", - "nodes": [ - { - "text": "recover", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/builtin#recover" - } - ], - { - "text": " function. If the value is an ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "builtin#error", - "href": "https://pkg.go.dev/builtin#error", - "target": "_blank" - }, - "file": "panic.md", - "nodes": [ - { - "atom": "code", - "file": "panic.md", - "nodes": [ - { - "text": "error", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/builtin#error" - } - ], - { - "text": ", we can use the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "panic.md", - "nodes": [ - { - "text": "named", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " return to send the value back to the caller. If not, we create a new ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "builtin#error", - "href": "https://pkg.go.dev/builtin#error", - "target": "_blank" - }, - "file": "panic.md", - "nodes": [ - { - "atom": "code", - "file": "panic.md", - "nodes": [ - { - "text": "error", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/builtin#error" - } - ], - { - "text": " with the value returned from the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "builtin#recover", - "href": "https://pkg.go.dev/builtin#recover", - "target": "_blank" - }, - "file": "panic.md", - "nodes": [ - { - "atom": "code", - "file": "panic.md", - "nodes": [ - { - "text": "recover", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/builtin#recover" - } - ], - { - "text": " function.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "panic.md", - "nodes": [ - { - "text": "As we see in ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-23" - }, - "file": "panic.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-23" - }, - "nodes": [ - { - "text": "Listing 1.23", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-23" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", when run the tests now are no longer panicking, and the test passes.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-23", - "type": "listing" - }, - "file": "panic.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "panic", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "panic/src/recover-named/recover_test.go#test" - }, - "lang": "go", - "nodes": [ - { - "content": "func Test_DoSomething(t *testing.T) {\n\tt.Parallel()\n\n\terr := DoSomething(0)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\terr = DoSomething(1)\n\n\tif err != ErrNonErrCaught(\"non-error panic type string one\") {\n\t\tt.Fatal(\"expected ErrNonErrCaught, got\", err)\n\t}\n}", - "file": "panic/src/recover-named/recover_test.go", - "lang": "go", - "name": "test", - "start": 7, - "end": 23, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "atom": "hr", - "file": "panic", - "type": "*hype.Element" - }, - [ - { - "args": [ - "go", - "test", - "-v" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go test -v", - "src": "panic/src/recover-named", - "test": "-v" - }, - "expected_exit": 0, - "file": "panic", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go test -v\n\n=== RUN Test_DoSomething\n=== PAUSE Test_DoSomething\n=== CONT Test_DoSomething\n--- PASS: Test_DoSomething (0.00s)\nPASS\nok \tdemo\t2.224s", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "test", - "-v" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/recover-named", - "stdout": "PT09IFJVTiAgIFRlc3RfRG9Tb21ldGhpbmcKPT09IFBBVVNFIFRlc3RfRG9Tb21ldGhpbmcKPT09IENPTlQgIFRlc3RfRG9Tb21ldGhpbmcKLS0tIFBBU1M6IFRlc3RfRG9Tb21ldGhpbmcgKDAuMDBzKQpQQVNTCm9rICAJZGVtbwkyLjIyNHM=", - "duration": 5095207459, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go test -v\n\n=== RUN Test_DoSomething\n=== PAUSE Test_DoSomething\n=== CONT Test_DoSomething\n--- PASS: Test_DoSomething (0.00s)\nPASS\nok \tdemo\t2.224s", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "test", - "-v" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/recover-named", - "stdout": "PT09IFJVTiAgIFRlc3RfRG9Tb21ldGhpbmcKPT09IFBBVVNFIFRlc3RfRG9Tb21ldGhpbmcKPT09IENPTlQgIFRlc3RfRG9Tb21ldGhpbmcKLS0tIFBBU1M6IFRlc3RfRG9Tb21ldGhpbmcgKDAuMDBzKQpQQVNTCm9rICAJZGVtbwkyLjIyNHM=", - "duration": 5095207459, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "panic", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.23:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Tests now pass after proper panic recovery.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 23, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "title": "Panic", - "type": "*hype.Page" - } - ], - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "include", - "attributes": { - "src": "panic/_dont.md" - }, - "dir": ".", - "file": "panic.md", - "nodes": [ - [ - { - "atom": "page", - "file": "panic/_dont.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "h1", - "file": "panic/_dont.md", - "level": 1, - "nodes": [ - { - "text": "Don't Panic", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - { - "atom": "blockquote", - "file": "panic/_dont.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "strong", - "file": "panic/_dont.md", - "nodes": [ - { - "text": "NEVER RAISE A PANIC IN YOUR CODE", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": "\n", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "panic/_dont.md", - "nodes": [ - { - "text": "Ok, maybe ", - "type": "hype.Text" - }, - { - "atom": "strong", - "file": "panic/_dont.md", - "nodes": [ - { - "text": "never", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " is too strong of a stance. However, in general, it's considered non-idiomatic to panic instead of returning an error outside of specific conditions.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "panic/_dont.md", - "nodes": [ - { - "text": "When a panic occurs, unless there is a recover in place, the program will shut down (usually not gracefully). It is usually a much better practice to return an error, and let the code upstream handle the error.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "panic/_dont.md", - "nodes": [ - { - "text": "The general rule is that if you are writing a package, you should not panic. The reason for this is that the caller should always have control of the program, and a package should not dictate control flow of a program.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "panic/_dont.md", - "nodes": [ - { - "text": "On the other hand, if you are the caller (maybe you are in control of the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "panic/_dont.md", - "nodes": [ - { - "text": "main", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function in the program), then you already have total control of the program flow, and if needed, a panic may be appropriate. Many times this is manifested in the form of a ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "log#Fatal", - "href": "https://pkg.go.dev/log#Fatal", - "target": "_blank" - }, - "file": "panic/_dont.md", - "nodes": [ - { - "atom": "code", - "file": "panic/_dont.md", - "nodes": [ - { - "text": "log.Fatal", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/log#Fatal" - } - ], - { - "text": ", ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-24" - }, - "file": "panic/_dont.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-24" - }, - "nodes": [ - { - "text": "Listing 1.24", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-24" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", which will exit the program with a non-zero exit code.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-24", - "type": "listing" - }, - "file": "panic/_dont.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "doc", - "log.Fatal" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "doc": "log.Fatal", - "exec": "go doc log.Fatal" - }, - "expected_exit": 0, - "file": "panic", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc log.Fatal\n\npackage log // import \u0026#34;log\u0026#34;\n\nfunc Fatal(v ...any)\n Fatal is equivalent to Print() followed by a call to os.Exit(1).", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "log.Fatal" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBsb2cgLy8gaW1wb3J0ICJsb2ciCgpmdW5jIEZhdGFsKHYgLi4uYW55KQogICAgRmF0YWwgaXMgZXF1aXZhbGVudCB0byBQcmludCgpIGZvbGxvd2VkIGJ5IGEgY2FsbCB0byBvcy5FeGl0KDEpLg==", - "duration": 2630507334, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc log.Fatal\n\npackage log // import \u0026#34;log\u0026#34;\n\nfunc Fatal(v ...any)\n Fatal is equivalent to Print() followed by a call to os.Exit(1).", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "log.Fatal" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBsb2cgLy8gaW1wb3J0ICJsb2ciCgpmdW5jIEZhdGFsKHYgLi4uYW55KQogICAgRmF0YWwgaXMgZXF1aXZhbGVudCB0byBQcmludCgpIGZvbGxvd2VkIGJ5IGEgY2FsbCB0byBvcy5FeGl0KDEpLg==", - "duration": 2630507334, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "panic", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.24:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "log#Fatal", - "href": "https://pkg.go.dev/log#Fatal", - "target": "_blank" - }, - "file": "panic", - "nodes": [ - [ - { - "atom": "code", - "file": "panic", - "nodes": [ - { - "text": "log.Fatal", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/log#Fatal" - } - ], - { - "text": " function.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 24, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "panic/_dont.md", - "nodes": [ - { - "text": "Lastly, any code that panics may be more difficult to test. For all of these reasons, it is best to consider alternatives to a panicking. After all, most panics can be prevented by sensible code and well designed tests.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "panic/_dont.md", - "level": 2, - "nodes": [ - { - "text": "Checking for Nil", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "panic/_dont.md", - "nodes": [ - { - "text": "The most common source of panics in Go are calls being made on ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "panic/_dont.md", - "nodes": [ - { - "text": "nil", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " values. Any type in go that has a zero value of ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "panic/_dont.md", - "nodes": [ - { - "text": "nil", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " can be a source of these panics. Types such as interfaces, maps, pointers, channels, and functions all fall into this category. Checking whether these types are ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "panic/_dont.md", - "nodes": [ - { - "text": "nil", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " before using them can easily avoid these panics.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "panic/_dont.md", - "nodes": [ - { - "text": "A common example of this is when a type has an embedded type that is a pointer. In ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-25" - }, - "file": "panic/_dont.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-25" - }, - "nodes": [ - { - "text": "Listing 1.25", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-25" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "panic/_dont.md", - "nodes": [ - { - "text": "User", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " is embedded in ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "panic/_dont.md", - "nodes": [ - { - "text": "Admin", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " as a pointer. Because it's embedded, the methods are promoted. This means that the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "panic/_dont.md", - "nodes": [ - { - "text": "Admin", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " type now has a ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "panic/_dont.md", - "nodes": [ - { - "text": "String", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " method. However, on the last line of code where ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "panic/_dont.md", - "nodes": [ - { - "text": "a.String()", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " is being called, the receiver to the method is actually the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "panic/_dont.md", - "nodes": [ - { - "text": "User", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ". Because ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "panic/_dont.md", - "nodes": [ - { - "text": "User", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " is ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "panic/_dont.md", - "nodes": [ - { - "text": "nil", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ", it was never set, the code will panic when it tries to access the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "panic/_dont.md", - "nodes": [ - { - "text": "String", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " method.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-25", - "type": "listing" - }, - "file": "panic/_dont.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "panic", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "panic/src/nil/main.go" - }, - "lang": "go", - "nodes": [ - { - "text": "package main\n\nimport \u0026#34;fmt\u0026#34;\n\ntype User struct {\n\tname string\n}\n\nfunc (u User) String() string {\n\treturn u.name\n}\n\ntype Admin struct {\n\t*User\n\tPerms map[string]bool\n}\n\nfunc main() {\n\ta := \u0026amp;Admin{}\n\tfmt.Println(a.String())\n}\n", - "type": "hype.Text" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "atom": "hr", - "file": "panic", - "type": "*hype.Element" - }, - [ - { - "args": [ - "go", - "run", - "." - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go run .", - "exit": "-1", - "run": ".", - "src": "panic/src/nil" - }, - "expected_exit": -1, - "file": "panic", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\npanic: runtime error: invalid memory address or nil pointer dereference\n[signal SIGSEGV: segmentation violation code=0x2 addr=0x0 pc=0x10277abbc]\n\ngoroutine 1 [running]:\nmain.main()\n\t./main.go:20 +0x1c\nexit status 2", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/nil", - "err": { - "Stderr": null - }, - "exit": 1, - "stderr": "cGFuaWM6IHJ1bnRpbWUgZXJyb3I6IGludmFsaWQgbWVtb3J5IGFkZHJlc3Mgb3IgbmlsIHBvaW50ZXIgZGVyZWZlcmVuY2UKW3NpZ25hbCBTSUdTRUdWOiBzZWdtZW50YXRpb24gdmlvbGF0aW9uIGNvZGU9MHgyIGFkZHI9MHgwIHBjPTB4MTAyNzdhYmJjXQoKZ29yb3V0aW5lIDEgW3J1bm5pbmddOgptYWluLm1haW4oKQoJL1VzZXJzL21hcmtiYXRlcy9MaWJyYXJ5L0Nsb3VkU3RvcmFnZS9Ecm9wYm94L2Rldi9ndWlkZXMvY29udGVudC9ib29rL2NoYXB0ZXJzLzA5LWVycm9ycy9wYW5pYy9zcmMvbmlsL21haW4uZ286MjAgKzB4MWMKZXhpdCBzdGF0dXMgMg==", - "duration": 3342830750, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\npanic: runtime error: invalid memory address or nil pointer dereference\n[signal SIGSEGV: segmentation violation code=0x2 addr=0x0 pc=0x10277abbc]\n\ngoroutine 1 [running]:\nmain.main()\n\t./main.go:20 +0x1c\nexit status 2", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/nil", - "err": { - "Stderr": null - }, - "exit": 1, - "stderr": "cGFuaWM6IHJ1bnRpbWUgZXJyb3I6IGludmFsaWQgbWVtb3J5IGFkZHJlc3Mgb3IgbmlsIHBvaW50ZXIgZGVyZWZlcmVuY2UKW3NpZ25hbCBTSUdTRUdWOiBzZWdtZW50YXRpb24gdmlvbGF0aW9uIGNvZGU9MHgyIGFkZHI9MHgwIHBjPTB4MTAyNzdhYmJjXQoKZ29yb3V0aW5lIDEgW3J1bm5pbmddOgptYWluLm1haW4oKQoJL1VzZXJzL21hcmtiYXRlcy9MaWJyYXJ5L0Nsb3VkU3RvcmFnZS9Ecm9wYm94L2Rldi9ndWlkZXMvY29udGVudC9ib29rL2NoYXB0ZXJzLzA5LWVycm9ycy9wYW5pYy9zcmMvbmlsL21haW4uZ286MjAgKzB4MWMKZXhpdCBzdGF0dXMgMg==", - "duration": 3342830750, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "panic", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.25:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "A panic when calling a method on a ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "panic", - "nodes": [ - { - "text": "nil", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " value.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 25, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "panic/_dont.md", - "nodes": [ - { - "text": "In ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-26" - }, - "file": "panic/_dont.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-26" - }, - "nodes": [ - { - "text": "Listing 1.26", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-26" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "panic/_dont.md", - "nodes": [ - { - "text": "Admin", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " type is properly initialized with a ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "panic/_dont.md", - "nodes": [ - { - "text": "User", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ". Now, when the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "panic/_dont.md", - "nodes": [ - { - "text": "String", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " method is called, the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "panic/_dont.md", - "nodes": [ - { - "text": "User", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " is not ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "panic/_dont.md", - "nodes": [ - { - "text": "nil", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ", and the method properly executes.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-26", - "type": "listing" - }, - "file": "panic/_dont.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "panic", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "panic/src/non-nil/main.go" - }, - "lang": "go", - "nodes": [ - { - "text": "package main\n\nimport \u0026#34;fmt\u0026#34;\n\ntype User struct {\n\tname string\n}\n\nfunc (u User) String() string {\n\treturn u.name\n}\n\ntype Admin struct {\n\t*User\n\tPerms map[string]bool\n}\n\nfunc main() {\n\ta := \u0026amp;Admin{\n\t\tUser: \u0026amp;User{name: \u0026#34;Kurt\u0026#34;},\n\t}\n\tfmt.Println(a.String())\n}\n", - "type": "hype.Text" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "atom": "hr", - "file": "panic", - "type": "*hype.Element" - }, - [ - { - "args": [ - "go", - "run", - "." - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go run .", - "run": ".", - "src": "panic/src/non-nil" - }, - "expected_exit": 0, - "file": "panic", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\nKurt", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/non-nil", - "stdout": "S3VydA==", - "duration": 3929781834, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\nKurt", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/non-nil", - "stdout": "S3VydA==", - "duration": 3929781834, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "panic", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.26:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Proper initialization to prevent panicking.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 26, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "panic/_dont.md", - "level": 2, - "nodes": [ - { - "text": "Maps", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "panic/_dont.md", - "nodes": [ - { - "text": "When creating maps, it is required to ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "panic/_dont.md", - "nodes": [ - { - "text": "initialize", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " the memory space behind them. Consider ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-27" - }, - "file": "panic/_dont.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-27" - }, - "nodes": [ - { - "text": "Listing 1.27", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-27" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": " as an example. We have created a map variable, but we have not initialized it. This causes a panic when we try to access the map.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-27", - "type": "listing" - }, - "file": "panic/_dont.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "panic", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "panic/src/maps/broken/main.go" - }, - "lang": "go", - "nodes": [ - { - "text": "package main\n\nimport \u0026#34;fmt\u0026#34;\n\nfunc main() {\n\n\t// create a new map variable\n\tvar m map[string]int\n\n\t// insert a key-value pair\n\tm[\u0026#34;Amy\u0026#34;] = 27\n\n\t// print the map\n\tfmt.Printf(\u0026#34;%+v\\n\u0026#34;, m)\n}\n", - "type": "hype.Text" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "atom": "hr", - "file": "panic", - "type": "*hype.Element" - }, - [ - { - "args": [ - "go", - "run", - "." - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go run .", - "exit": "-1", - "run": ".", - "src": "panic/src/maps/broken" - }, - "expected_exit": -1, - "file": "panic", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\npanic: assignment to entry in nil map\n\ngoroutine 1 [running]:\nmain.main()\n\t./main.go:11 +0x34\nexit status 2", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/maps/broken", - "err": { - "Stderr": null - }, - "exit": 1, - "stderr": "cGFuaWM6IGFzc2lnbm1lbnQgdG8gZW50cnkgaW4gbmlsIG1hcAoKZ29yb3V0aW5lIDEgW3J1bm5pbmddOgptYWluLm1haW4oKQoJL1VzZXJzL21hcmtiYXRlcy9MaWJyYXJ5L0Nsb3VkU3RvcmFnZS9Ecm9wYm94L2Rldi9ndWlkZXMvY29udGVudC9ib29rL2NoYXB0ZXJzLzA5LWVycm9ycy9wYW5pYy9zcmMvbWFwcy9icm9rZW4vbWFpbi5nbzoxMSArMHgzNApleGl0IHN0YXR1cyAy", - "duration": 4325997292, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\npanic: assignment to entry in nil map\n\ngoroutine 1 [running]:\nmain.main()\n\t./main.go:11 +0x34\nexit status 2", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/maps/broken", - "err": { - "Stderr": null - }, - "exit": 1, - "stderr": "cGFuaWM6IGFzc2lnbm1lbnQgdG8gZW50cnkgaW4gbmlsIG1hcAoKZ29yb3V0aW5lIDEgW3J1bm5pbmddOgptYWluLm1haW4oKQoJL1VzZXJzL21hcmtiYXRlcy9MaWJyYXJ5L0Nsb3VkU3RvcmFnZS9Ecm9wYm94L2Rldi9ndWlkZXMvY29udGVudC9ib29rL2NoYXB0ZXJzLzA5LWVycm9ycy9wYW5pYy9zcmMvbWFwcy9icm9rZW4vbWFpbi5nbzoxMSArMHgzNApleGl0IHN0YXR1cyAy", - "duration": 4325997292, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "panic", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.27:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "A panic when creating a map with a nil value.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 27, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "panic/_dont.md", - "nodes": [ - { - "text": "The easiest solution is to use the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "panic/_dont.md", - "nodes": [ - { - "text": ":=", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " operator to initialize the map when the variable is declared. In ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-28" - }, - "file": "panic/_dont.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-28" - }, - "nodes": [ - { - "text": "Listing 1.28", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-28" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", we have initialized the map and the code runs successfully.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-28", - "type": "listing" - }, - "file": "panic/_dont.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "panic", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "panic/src/maps/init/main.go" - }, - "lang": "go", - "nodes": [ - { - "text": "package main\n\nimport \u0026#34;fmt\u0026#34;\n\nfunc main() {\n\n\t// initialize a new map\n\tm := map[string]int{}\n\n\t// insert a key-value pair\n\tm[\u0026#34;Amy\u0026#34;] = 27\n\n\t// print the map\n\tfmt.Printf(\u0026#34;%+v\\n\u0026#34;, m)\n}\n", - "type": "hype.Text" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "atom": "hr", - "file": "panic", - "type": "*hype.Element" - }, - [ - { - "args": [ - "go", - "run", - "." - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go run .", - "run": ".", - "src": "panic/src/maps/init" - }, - "expected_exit": 0, - "file": "panic", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\nmap[Amy:27]", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/maps/init", - "stdout": "bWFwW0FteToyN10=", - "duration": 4531300125, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\nmap[Amy:27]", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/maps/init", - "stdout": "bWFwW0FteToyN10=", - "duration": 4531300125, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "panic", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.28:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Avoiding panics when creating maps.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 28, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "panic/_dont.md", - "nodes": [ - { - "text": "However, if a map is declared with long variable declaration, and not initialized, later in the code the map will need to be initialized or it will panic when used.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-29", - "type": "listing" - }, - "file": "panic/_dont.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "panic", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "panic/src/maps/check/main.go" - }, - "lang": "go", - "nodes": [ - { - "text": "package main\n\nimport \u0026#34;fmt\u0026#34;\n\nfunc main() {\n\n\t// create a new map variable\n\tvar m map[string]int\n\n\tif m == nil {\n\t\t// initialize the map\n\t\tm = map[string]int{}\n\t}\n\n\t// insert a key-value pair\n\tm[\u0026#34;Amy\u0026#34;] = 27\n\n\t// print the map\n\tfmt.Printf(\u0026#34;%+v\\n\u0026#34;, m)\n}\n", - "type": "hype.Text" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "atom": "hr", - "file": "panic", - "type": "*hype.Element" - }, - [ - { - "args": [ - "go", - "run", - "." - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go run .", - "run": ".", - "src": "panic/src/maps/check" - }, - "expected_exit": 0, - "file": "panic", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\nmap[Amy:27]", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/maps/check", - "stdout": "bWFwW0FteToyN10=", - "duration": 4467087792, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\nmap[Amy:27]", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/maps/check", - "stdout": "bWFwW0FteToyN10=", - "duration": 4467087792, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "panic", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.29:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Checking a map for ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "panic", - "nodes": [ - { - "text": "nil", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " before accessing.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 29, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "panic/_dont.md", - "nodes": [ - { - "text": "Finally, as in ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-30" - }, - "file": "panic/_dont.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-30" - }, - "nodes": [ - { - "text": "Listing 1.30", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-30" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", we can use the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "builtin#make", - "href": "https://pkg.go.dev/builtin#make", - "target": "_blank" - }, - "file": "panic/_dont.md", - "nodes": [ - { - "atom": "code", - "file": "panic/_dont.md", - "nodes": [ - { - "text": "make", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/builtin#make" - } - ], - { - "text": " function to initialize the map. While this works, it is consider non-idiomatic to use ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "builtin#make", - "href": "https://pkg.go.dev/builtin#make", - "target": "_blank" - }, - "file": "panic/_dont.md", - "nodes": [ - { - "atom": "code", - "file": "panic/_dont.md", - "nodes": [ - { - "text": "make", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/builtin#make" - } - ], - { - "text": " to initialize a map.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-30", - "type": "listing" - }, - "file": "panic/_dont.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "panic", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "panic/src/maps/make/main.go" - }, - "lang": "go", - "nodes": [ - { - "text": "package main\n\nimport \u0026#34;fmt\u0026#34;\n\nfunc main() {\n\n\t// initialize a new map\n\tm := make(map[string]int)\n\n\t// insert a key-value pair\n\tm[\u0026#34;Amy\u0026#34;] = 27\n\n\t// print the map\n\tfmt.Printf(\u0026#34;%+v\\n\u0026#34;, m)\n}\n", - "type": "hype.Text" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "atom": "hr", - "file": "panic", - "type": "*hype.Element" - }, - [ - { - "args": [ - "go", - "run", - "." - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go run .", - "run": ".", - "src": "panic/src/maps/make" - }, - "expected_exit": 0, - "file": "panic", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\nmap[Amy:27]", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/maps/make", - "stdout": "bWFwW0FteToyN10=", - "duration": 3659204125, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\nmap[Amy:27]", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/maps/make", - "stdout": "bWFwW0FteToyN10=", - "duration": 3659204125, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "panic", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.30:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Using ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "builtin#make", - "href": "https://pkg.go.dev/builtin#make", - "target": "_blank" - }, - "file": "panic", - "nodes": [ - [ - { - "atom": "code", - "file": "panic", - "nodes": [ - { - "text": "make", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/builtin#make" - } - ], - { - "text": " to initialize a map.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 30, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "panic/_dont.md", - "level": 2, - "nodes": [ - { - "text": "Pointers", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "panic/_dont.md", - "nodes": [ - { - "text": "Before a pointer can be used, it has to be initialized. The following code checks to see if a pointer is ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "panic/_dont.md", - "nodes": [ - { - "text": "nil", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ", not initialized, and then properly initializes it.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-31", - "type": "listing" - }, - "file": "panic/_dont.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "panic", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "panic/src/pointers/broken/main.go" - }, - "lang": "go", - "nodes": [ - { - "text": "package main\n\nimport (\n\t\u0026#34;bytes\u0026#34;\n\t\u0026#34;fmt\u0026#34;\n)\n\nfunc main() {\n\n\t// create a new pointer\n\t// to a bytes.Buffer\n\tvar bb *bytes.Buffer\n\n\t// use the pointer to\n\t// write data to the buffer\n\tbb.WriteString(\u0026#34;Hello, world!\u0026#34;)\n\n\t// print the buffer\n\tfmt.Println(bb.String())\n}\n", - "type": "hype.Text" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "atom": "hr", - "file": "panic", - "type": "*hype.Element" - }, - [ - { - "args": [ - "go", - "run", - "." - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go run .", - "exit": "-1", - "run": ".", - "src": "panic/src/pointers/broken" - }, - "expected_exit": -1, - "file": "panic", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\npanic: runtime error: invalid memory address or nil pointer dereference\n[signal SIGSEGV: segmentation violation code=0x2 addr=0x20 pc=0x102e0ffbc]\n\ngoroutine 1 [running]:\nbytes.(*Buffer).WriteString(0x1400006a728?, {0x102e34439?, 0x60?})\n\t/usr/local/go/src/bytes/buffer.go:188 +0x1c\nmain.main()\n\t./main.go:16 +0x2c\nexit status 2", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/pointers/broken", - "err": { - "Stderr": null - }, - "exit": 1, - "stderr": "cGFuaWM6IHJ1bnRpbWUgZXJyb3I6IGludmFsaWQgbWVtb3J5IGFkZHJlc3Mgb3IgbmlsIHBvaW50ZXIgZGVyZWZlcmVuY2UKW3NpZ25hbCBTSUdTRUdWOiBzZWdtZW50YXRpb24gdmlvbGF0aW9uIGNvZGU9MHgyIGFkZHI9MHgyMCBwYz0weDEwMmUwZmZiY10KCmdvcm91dGluZSAxIFtydW5uaW5nXToKYnl0ZXMuKCpCdWZmZXIpLldyaXRlU3RyaW5nKDB4MTQwMDAwNmE3Mjg/LCB7MHgxMDJlMzQ0Mzk/LCAweDYwP30pCgkvdXNyL2xvY2FsL2dvL3NyYy9ieXRlcy9idWZmZXIuZ286MTg4ICsweDFjCm1haW4ubWFpbigpCgkvVXNlcnMvbWFya2JhdGVzL0xpYnJhcnkvQ2xvdWRTdG9yYWdlL0Ryb3Bib3gvZGV2L2d1aWRlcy9jb250ZW50L2Jvb2svY2hhcHRlcnMvMDktZXJyb3JzL3BhbmljL3NyYy9wb2ludGVycy9icm9rZW4vbWFpbi5nbzoxNiArMHgyYwpleGl0IHN0YXR1cyAy", - "duration": 3276466167, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\npanic: runtime error: invalid memory address or nil pointer dereference\n[signal SIGSEGV: segmentation violation code=0x2 addr=0x20 pc=0x102e0ffbc]\n\ngoroutine 1 [running]:\nbytes.(*Buffer).WriteString(0x1400006a728?, {0x102e34439?, 0x60?})\n\t/usr/local/go/src/bytes/buffer.go:188 +0x1c\nmain.main()\n\t./main.go:16 +0x2c\nexit status 2", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/pointers/broken", - "err": { - "Stderr": null - }, - "exit": 1, - "stderr": "cGFuaWM6IHJ1bnRpbWUgZXJyb3I6IGludmFsaWQgbWVtb3J5IGFkZHJlc3Mgb3IgbmlsIHBvaW50ZXIgZGVyZWZlcmVuY2UKW3NpZ25hbCBTSUdTRUdWOiBzZWdtZW50YXRpb24gdmlvbGF0aW9uIGNvZGU9MHgyIGFkZHI9MHgyMCBwYz0weDEwMmUwZmZiY10KCmdvcm91dGluZSAxIFtydW5uaW5nXToKYnl0ZXMuKCpCdWZmZXIpLldyaXRlU3RyaW5nKDB4MTQwMDAwNmE3Mjg/LCB7MHgxMDJlMzQ0Mzk/LCAweDYwP30pCgkvdXNyL2xvY2FsL2dvL3NyYy9ieXRlcy9idWZmZXIuZ286MTg4ICsweDFjCm1haW4ubWFpbigpCgkvVXNlcnMvbWFya2JhdGVzL0xpYnJhcnkvQ2xvdWRTdG9yYWdlL0Ryb3Bib3gvZGV2L2d1aWRlcy9jb250ZW50L2Jvb2svY2hhcHRlcnMvMDktZXJyb3JzL3BhbmljL3NyYy9wb2ludGVycy9icm9rZW4vbWFpbi5nbzoxNiArMHgyYwpleGl0IHN0YXR1cyAy", - "duration": 3276466167, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "panic", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.31:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "A panic caused by a ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "panic", - "nodes": [ - { - "text": "nil", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " pointer.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 31, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-32", - "type": "listing" - }, - "file": "panic/_dont.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "panic", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "panic/src/pointers/fixed/main.go" - }, - "lang": "go", - "nodes": [ - { - "text": "package main\n\nimport (\n\t\u0026#34;bytes\u0026#34;\n\t\u0026#34;fmt\u0026#34;\n)\n\nfunc main() {\n\n\t// create and initialize\n\t// a new pointer\n\t// to a bytes.Buffer\n\tbb := \u0026amp;bytes.Buffer{}\n\n\t// use the pointer to\n\t// write data to the buffer\n\tbb.WriteString(\u0026#34;Hello, world!\u0026#34;)\n\n\t// print the buffer\n\tfmt.Println(bb.String())\n}\n", - "type": "hype.Text" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "atom": "hr", - "file": "panic", - "type": "*hype.Element" - }, - [ - { - "args": [ - "go", - "run", - "." - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go run .", - "run": ".", - "src": "panic/src/pointers/fixed" - }, - "expected_exit": 0, - "file": "panic", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\nHello, world!", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/pointers/fixed", - "stdout": "SGVsbG8sIHdvcmxkIQ==", - "duration": 2789895125, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\nHello, world!", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/pointers/fixed", - "stdout": "SGVsbG8sIHdvcmxkIQ==", - "duration": 2789895125, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "panic", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.32:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Properly initializing a pointer before use.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 32, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "panic/_dont.md", - "level": 2, - "nodes": [ - { - "text": "Interfaces", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "panic/_dont.md", - "nodes": [ - { - "text": "In ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-33" - }, - "file": "panic/_dont.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-33" - }, - "nodes": [ - { - "text": "Listing 1.33", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-33" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", we have create a new variable, ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "panic/_dont.md", - "nodes": [ - { - "text": "w", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ", of type ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "io#Writer", - "href": "https://pkg.go.dev/io#Writer", - "target": "_blank" - }, - "file": "panic/_dont.md", - "nodes": [ - { - "atom": "code", - "file": "panic/_dont.md", - "nodes": [ - { - "text": "io.Writer", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/io#Writer" - } - ], - { - "text": ". This variable has not be initialized with an implementation of the interface. This causes a panic when we try to use the variable.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-33", - "type": "listing" - }, - "file": "panic/_dont.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "panic", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "panic/src/interface/broken/main.go" - }, - "lang": "go", - "nodes": [ - { - "text": "package main\n\nimport (\n\t\u0026#34;fmt\u0026#34;\n\t\u0026#34;io\u0026#34;\n)\n\nfunc main() {\n\n\t// create a new writer variable\n\tvar w io.Writer\n\n\t// print to the writer\n\tfmt.Fprintln(w, \u0026#34;Hello, world!\u0026#34;)\n}\n", - "type": "hype.Text" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "atom": "hr", - "file": "panic", - "type": "*hype.Element" - }, - [ - { - "args": [ - "go", - "run", - "." - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go run .", - "exit": "-1", - "run": ".", - "src": "panic/src/interface/broken" - }, - "expected_exit": -1, - "file": "panic", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\npanic: runtime error: invalid memory address or nil pointer dereference\n[signal SIGSEGV: segmentation violation code=0x2 addr=0x18 pc=0x1000a8e38]\n\ngoroutine 1 [running]:\nfmt.Fprintln({0x0, 0x0}, {0x140000a4f18, 0x1, 0x1})\n\t/usr/local/go/src/fmt/print.go:305 +0x48\nmain.main()\n\t./main.go:14 +0x4c\nexit status 2", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/interface/broken", - "err": { - "Stderr": null - }, - "exit": 1, - "stderr": "cGFuaWM6IHJ1bnRpbWUgZXJyb3I6IGludmFsaWQgbWVtb3J5IGFkZHJlc3Mgb3IgbmlsIHBvaW50ZXIgZGVyZWZlcmVuY2UKW3NpZ25hbCBTSUdTRUdWOiBzZWdtZW50YXRpb24gdmlvbGF0aW9uIGNvZGU9MHgyIGFkZHI9MHgxOCBwYz0weDEwMDBhOGUzOF0KCmdvcm91dGluZSAxIFtydW5uaW5nXToKZm10LkZwcmludGxuKHsweDAsIDB4MH0sIHsweDE0MDAwMGE0ZjE4LCAweDEsIDB4MX0pCgkvdXNyL2xvY2FsL2dvL3NyYy9mbXQvcHJpbnQuZ286MzA1ICsweDQ4Cm1haW4ubWFpbigpCgkvVXNlcnMvbWFya2JhdGVzL0xpYnJhcnkvQ2xvdWRTdG9yYWdlL0Ryb3Bib3gvZGV2L2d1aWRlcy9jb250ZW50L2Jvb2svY2hhcHRlcnMvMDktZXJyb3JzL3BhbmljL3NyYy9pbnRlcmZhY2UvYnJva2VuL21haW4uZ286MTQgKzB4NGMKZXhpdCBzdGF0dXMgMg==", - "duration": 3472134250, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\npanic: runtime error: invalid memory address or nil pointer dereference\n[signal SIGSEGV: segmentation violation code=0x2 addr=0x18 pc=0x1000a8e38]\n\ngoroutine 1 [running]:\nfmt.Fprintln({0x0, 0x0}, {0x140000a4f18, 0x1, 0x1})\n\t/usr/local/go/src/fmt/print.go:305 +0x48\nmain.main()\n\t./main.go:14 +0x4c\nexit status 2", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/interface/broken", - "err": { - "Stderr": null - }, - "exit": 1, - "stderr": "cGFuaWM6IHJ1bnRpbWUgZXJyb3I6IGludmFsaWQgbWVtb3J5IGFkZHJlc3Mgb3IgbmlsIHBvaW50ZXIgZGVyZWZlcmVuY2UKW3NpZ25hbCBTSUdTRUdWOiBzZWdtZW50YXRpb24gdmlvbGF0aW9uIGNvZGU9MHgyIGFkZHI9MHgxOCBwYz0weDEwMDBhOGUzOF0KCmdvcm91dGluZSAxIFtydW5uaW5nXToKZm10LkZwcmludGxuKHsweDAsIDB4MH0sIHsweDE0MDAwMGE0ZjE4LCAweDEsIDB4MX0pCgkvdXNyL2xvY2FsL2dvL3NyYy9mbXQvcHJpbnQuZ286MzA1ICsweDQ4Cm1haW4ubWFpbigpCgkvVXNlcnMvbWFya2JhdGVzL0xpYnJhcnkvQ2xvdWRTdG9yYWdlL0Ryb3Bib3gvZGV2L2d1aWRlcy9jb250ZW50L2Jvb2svY2hhcHRlcnMvMDktZXJyb3JzL3BhbmljL3NyYy9pbnRlcmZhY2UvYnJva2VuL21haW4uZ286MTQgKzB4NGMKZXhpdCBzdGF0dXMgMg==", - "duration": 3472134250, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "panic", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.33:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "A panic caused by a ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "panic", - "nodes": [ - { - "text": "nil", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " interface.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 33, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "panic/_dont.md", - "nodes": [ - { - "text": "In ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-34" - }, - "file": "panic/_dont.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-34" - }, - "nodes": [ - { - "text": "Listing 1.34", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-34" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", we have initialized the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "panic/_dont.md", - "nodes": [ - { - "text": "w", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " variable with an implementation of the interface, in this case ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "io#Stdout", - "href": "https://pkg.go.dev/io#Stdout", - "target": "_blank" - }, - "file": "panic/_dont.md", - "nodes": [ - { - "atom": "code", - "file": "panic/_dont.md", - "nodes": [ - { - "text": "io.Stdout", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/io#Stdout" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-34", - "type": "listing" - }, - "file": "panic/_dont.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "panic", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "panic/src/interface/fixed/main.go" - }, - "lang": "go", - "nodes": [ - { - "text": "package main\n\nimport (\n\t\u0026#34;fmt\u0026#34;\n\t\u0026#34;os\u0026#34;\n)\n\nfunc main() {\n\n\t// create a new writer variable\n\t// with STDOUT as the\n\t// writer implementation\n\tw := os.Stdout\n\n\t// print to the writer\n\tfmt.Fprintln(w, \u0026#34;Hello, world!\u0026#34;)\n}\n", - "type": "hype.Text" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "atom": "hr", - "file": "panic", - "type": "*hype.Element" - }, - [ - { - "args": [ - "go", - "run", - "." - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go run .", - "run": ".", - "src": "panic/src/interface/fixed" - }, - "expected_exit": 0, - "file": "panic", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\nHello, world!", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/interface/fixed", - "stdout": "SGVsbG8sIHdvcmxkIQ==", - "duration": 3993461042, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\nHello, world!", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/interface/fixed", - "stdout": "SGVsbG8sIHdvcmxkIQ==", - "duration": 3993461042, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "panic", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.34:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Initializing an interface before use.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 34, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "panic/_dont.md", - "nodes": [ - { - "text": "More commonly, a panic will occur when an interface is embedded into a type, and that interface was not backed by an instance.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "panic/_dont.md", - "nodes": [ - { - "text": "In ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-35" - }, - "file": "panic/_dont.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-35" - }, - "nodes": [ - { - "text": "Listing 1.35", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-35" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": " we are defining a ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "panic/_dont.md", - "nodes": [ - { - "text": "Stream", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " struct that embeds the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "io#Writer", - "href": "https://pkg.go.dev/io#Writer", - "target": "_blank" - }, - "file": "panic/_dont.md", - "nodes": [ - { - "atom": "code", - "file": "panic/_dont.md", - "nodes": [ - { - "text": "io.Writer", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/io#Writer" - } - ], - { - "text": " interface. By embedding the interface, the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "panic/_dont.md", - "nodes": [ - { - "text": "Stream", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " type is now also an implementation ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "io#Writer", - "href": "https://pkg.go.dev/io#Writer", - "target": "_blank" - }, - "file": "panic/_dont.md", - "nodes": [ - { - "atom": "code", - "file": "panic/_dont.md", - "nodes": [ - { - "text": "io.Writer", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/io#Writer" - } - ], - { - "text": " as the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "io#Writer.Write", - "href": "https://pkg.go.dev/io#Writer.Write", - "target": "_blank" - }, - "file": "panic/_dont.md", - "nodes": [ - { - "atom": "code", - "file": "panic/_dont.md", - "nodes": [ - { - "text": "io.Writer.Write", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/io#Writer.Write" - } - ], - { - "text": " method is promoted to the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "panic/_dont.md", - "nodes": [ - { - "text": "Stream", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " type.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-35", - "type": "listing" - }, - "file": "panic/_dont.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "panic", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "panic/src/interface/empty/main.go#type" - }, - "lang": "go", - "nodes": [ - { - "content": "type Stream struct {\n\tio.Writer\n}", - "file": "panic/src/interface/empty/main.go", - "lang": "go", - "name": "type", - "start": 8, - "end": 13, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "panic", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.35:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "A custom type that embeds an interface.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 35, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "panic/_dont.md", - "nodes": [ - { - "text": "However, if an instance of a writer is never assigned to the embedded ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "io#Writer", - "href": "https://pkg.go.dev/io#Writer", - "target": "_blank" - }, - "file": "panic/_dont.md", - "nodes": [ - { - "atom": "code", - "file": "panic/_dont.md", - "nodes": [ - { - "text": "io.Writer", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/io#Writer" - } - ], - { - "text": ", as in ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-36" - }, - "file": "panic/_dont.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-36" - }, - "nodes": [ - { - "text": "Listing 1.36", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-36" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", the code will panic when it tries to call the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "io#Writer.Write", - "href": "https://pkg.go.dev/io#Writer.Write", - "target": "_blank" - }, - "file": "panic/_dont.md", - "nodes": [ - { - "atom": "code", - "file": "panic/_dont.md", - "nodes": [ - { - "text": "io.Writer.Write", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/io#Writer.Write" - } - ], - { - "text": " method, as the receiver is ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "panic/_dont.md", - "nodes": [ - { - "text": "nil", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-36", - "type": "listing" - }, - "file": "panic/_dont.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "panic", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "panic/src/interface/empty/main.go#example" - }, - "lang": "go", - "nodes": [ - { - "content": "func main() {\n\n\t// initialize a stream\n\t// without a writer\n\ts := Stream{}\n\n\tfmt.Fprintf(s, \"Hello Gophers!\")\n}", - "file": "panic/src/interface/empty/main.go", - "lang": "go", - "name": "example", - "start": 15, - "end": 25, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "atom": "hr", - "file": "panic", - "type": "*hype.Element" - }, - [ - { - "args": [ - "go", - "run", - "." - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go run .", - "exit": "-1", - "run": ".", - "src": "panic/src/interface/empty" - }, - "expected_exit": -1, - "file": "panic", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\npanic: runtime error: invalid memory address or nil pointer dereference\n[signal SIGSEGV: segmentation violation code=0x2 addr=0x18 pc=0x102d0f33c]\n\ngoroutine 1 [running]:\nmain.(*Stream).Write(0x14000128410?, {0x1400011a020?, 0xe?, 0x0?})\n\t\u0026lt;autogenerated\u0026gt;:1 +0x2c\nfmt.Fprintf({0x102d4ea08, 0x1400010a020}, {0x102d108f9, 0xe}, {0x0, 0x0, 0x0})\n\t/usr/local/go/src/fmt/print.go:225 +0x84\nmain.main()\n\t./main.go:22 +0x54\nexit status 2", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/interface/empty", - "err": { - "Stderr": null - }, - "exit": 1, - "stderr": "cGFuaWM6IHJ1bnRpbWUgZXJyb3I6IGludmFsaWQgbWVtb3J5IGFkZHJlc3Mgb3IgbmlsIHBvaW50ZXIgZGVyZWZlcmVuY2UKW3NpZ25hbCBTSUdTRUdWOiBzZWdtZW50YXRpb24gdmlvbGF0aW9uIGNvZGU9MHgyIGFkZHI9MHgxOCBwYz0weDEwMmQwZjMzY10KCmdvcm91dGluZSAxIFtydW5uaW5nXToKbWFpbi4oKlN0cmVhbSkuV3JpdGUoMHgxNDAwMDEyODQxMD8sIHsweDE0MDAwMTFhMDIwPywgMHhlPywgMHgwP30pCgk8YXV0b2dlbmVyYXRlZD46MSArMHgyYwpmbXQuRnByaW50Zih7MHgxMDJkNGVhMDgsIDB4MTQwMDAxMGEwMjB9LCB7MHgxMDJkMTA4ZjksIDB4ZX0sIHsweDAsIDB4MCwgMHgwfSkKCS91c3IvbG9jYWwvZ28vc3JjL2ZtdC9wcmludC5nbzoyMjUgKzB4ODQKbWFpbi5tYWluKCkKCS9Vc2Vycy9tYXJrYmF0ZXMvTGlicmFyeS9DbG91ZFN0b3JhZ2UvRHJvcGJveC9kZXYvZ3VpZGVzL2NvbnRlbnQvYm9vay9jaGFwdGVycy8wOS1lcnJvcnMvcGFuaWMvc3JjL2ludGVyZmFjZS9lbXB0eS9tYWluLmdvOjIyICsweDU0CmV4aXQgc3RhdHVzIDI=", - "duration": 4127398459, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\npanic: runtime error: invalid memory address or nil pointer dereference\n[signal SIGSEGV: segmentation violation code=0x2 addr=0x18 pc=0x102d0f33c]\n\ngoroutine 1 [running]:\nmain.(*Stream).Write(0x14000128410?, {0x1400011a020?, 0xe?, 0x0?})\n\t\u0026lt;autogenerated\u0026gt;:1 +0x2c\nfmt.Fprintf({0x102d4ea08, 0x1400010a020}, {0x102d108f9, 0xe}, {0x0, 0x0, 0x0})\n\t/usr/local/go/src/fmt/print.go:225 +0x84\nmain.main()\n\t./main.go:22 +0x54\nexit status 2", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/interface/empty", - "err": { - "Stderr": null - }, - "exit": 1, - "stderr": "cGFuaWM6IHJ1bnRpbWUgZXJyb3I6IGludmFsaWQgbWVtb3J5IGFkZHJlc3Mgb3IgbmlsIHBvaW50ZXIgZGVyZWZlcmVuY2UKW3NpZ25hbCBTSUdTRUdWOiBzZWdtZW50YXRpb24gdmlvbGF0aW9uIGNvZGU9MHgyIGFkZHI9MHgxOCBwYz0weDEwMmQwZjMzY10KCmdvcm91dGluZSAxIFtydW5uaW5nXToKbWFpbi4oKlN0cmVhbSkuV3JpdGUoMHgxNDAwMDEyODQxMD8sIHsweDE0MDAwMTFhMDIwPywgMHhlPywgMHgwP30pCgk8YXV0b2dlbmVyYXRlZD46MSArMHgyYwpmbXQuRnByaW50Zih7MHgxMDJkNGVhMDgsIDB4MTQwMDAxMGEwMjB9LCB7MHgxMDJkMTA4ZjksIDB4ZX0sIHsweDAsIDB4MCwgMHgwfSkKCS91c3IvbG9jYWwvZ28vc3JjL2ZtdC9wcmludC5nbzoyMjUgKzB4ODQKbWFpbi5tYWluKCkKCS9Vc2Vycy9tYXJrYmF0ZXMvTGlicmFyeS9DbG91ZFN0b3JhZ2UvRHJvcGJveC9kZXYvZ3VpZGVzL2NvbnRlbnQvYm9vay9jaGFwdGVycy8wOS1lcnJvcnMvcGFuaWMvc3JjL2ludGVyZmFjZS9lbXB0eS9tYWluLmdvOjIyICsweDU0CmV4aXQgc3RhdHVzIDI=", - "duration": 4127398459, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "panic", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.36:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "A panic caused by a ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "panic", - "nodes": [ - { - "text": "nil", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " interface.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 36, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "panic/_dont.md", - "nodes": [ - { - "text": "In ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-37" - }, - "file": "panic/_dont.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-37" - }, - "nodes": [ - { - "text": "Listing 1.37", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-37" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", we fix the code by properly assigning an implementation of an ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "io#Writer", - "href": "https://pkg.go.dev/io#Writer", - "target": "_blank" - }, - "file": "panic/_dont.md", - "nodes": [ - { - "atom": "code", - "file": "panic/_dont.md", - "nodes": [ - { - "text": "io.Writer", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/io#Writer" - } - ], - { - "text": " interface, in this case ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "os#Stdout", - "href": "https://pkg.go.dev/os#Stdout", - "target": "_blank" - }, - "file": "panic/_dont.md", - "nodes": [ - { - "atom": "code", - "file": "panic/_dont.md", - "nodes": [ - { - "text": "os.Stdout", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/os#Stdout" - } - ], - { - "text": " to the embedded ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "io#Writer", - "href": "https://pkg.go.dev/io#Writer", - "target": "_blank" - }, - "file": "panic/_dont.md", - "nodes": [ - { - "atom": "code", - "file": "panic/_dont.md", - "nodes": [ - { - "text": "io.Writer", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/io#Writer" - } - ], - { - "text": " in the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "panic/_dont.md", - "nodes": [ - { - "text": "Stream", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " type.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-37", - "type": "listing" - }, - "file": "panic/_dont.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "panic", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "panic/src/interface/backed/main.go#example" - }, - "lang": "go", - "nodes": [ - { - "content": "func main() {\n\n\t// initialize a stream\n\t// with STDOUT as the writer\n\ts := Stream{\n\t\tWriter: os.Stdout,\n\t}\n\n\tfmt.Fprintf(s, \"Hello Gophers!\")\n}", - "file": "panic/src/interface/backed/main.go", - "lang": "go", - "name": "example", - "start": 13, - "end": 25, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "atom": "hr", - "file": "panic", - "type": "*hype.Element" - }, - [ - { - "args": [ - "go", - "run", - "." - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go run .", - "run": ".", - "src": "panic/src/interface/backed" - }, - "expected_exit": 0, - "file": "panic", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\nHello Gophers!", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/interface/backed", - "stdout": "SGVsbG8gR29waGVycyE=", - "duration": 3591777917, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\nHello Gophers!", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/interface/backed", - "stdout": "SGVsbG8gR29waGVycyE=", - "duration": 3591777917, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "panic", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.37:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Properly assigning an implementation of an embedded ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "io#Writer", - "href": "https://pkg.go.dev/io#Writer", - "target": "_blank" - }, - "file": "panic", - "nodes": [ - [ - { - "atom": "code", - "file": "panic", - "nodes": [ - { - "text": "io.Writer", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/io#Writer" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 37, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "panic/_dont.md", - "level": 2, - "nodes": [ - { - "text": "Functions", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "panic/_dont.md", - "nodes": [ - { - "text": "A function's zero value is ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "panic/_dont.md", - "nodes": [ - { - "text": "nil", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ". As such, a function needs to be assigned before using it. In ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-38" - }, - "file": "panic/_dont.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-38" - }, - "nodes": [ - { - "text": "Listing 1.38", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-38" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", we have created a function variable, ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "panic/_dont.md", - "nodes": [ - { - "text": "fn", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ", that is not backed by an actual function. This causes a panic when we try to call the function.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-38", - "type": "listing" - }, - "file": "panic/_dont.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "panic", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "panic/src/func/broken/main.go#example" - }, - "lang": "go", - "nodes": [ - { - "content": "func main() {\n\n\t// create a new function\n\t// type variable\n\tvar fn func() string\n\n\t// print the results\n\t// of the function\n\tfmt.Println(fn())\n}", - "file": "panic/src/func/broken/main.go", - "lang": "go", - "name": "example", - "start": 7, - "end": 19, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "atom": "hr", - "file": "panic", - "type": "*hype.Element" - }, - [ - { - "args": [ - "go", - "run", - "." - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go run .", - "exit": "-1", - "run": ".", - "src": "panic/src/func/broken" - }, - "expected_exit": -1, - "file": "panic", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\npanic: runtime error: invalid memory address or nil pointer dereference\n[signal SIGSEGV: segmentation violation code=0x2 addr=0x0 pc=0x1007e6bbc]\n\ngoroutine 1 [running]:\nmain.main()\n\t./main.go:16 +0x1c\nexit status 2", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/func/broken", - "err": { - "Stderr": null - }, - "exit": 1, - "stderr": "cGFuaWM6IHJ1bnRpbWUgZXJyb3I6IGludmFsaWQgbWVtb3J5IGFkZHJlc3Mgb3IgbmlsIHBvaW50ZXIgZGVyZWZlcmVuY2UKW3NpZ25hbCBTSUdTRUdWOiBzZWdtZW50YXRpb24gdmlvbGF0aW9uIGNvZGU9MHgyIGFkZHI9MHgwIHBjPTB4MTAwN2U2YmJjXQoKZ29yb3V0aW5lIDEgW3J1bm5pbmddOgptYWluLm1haW4oKQoJL1VzZXJzL21hcmtiYXRlcy9MaWJyYXJ5L0Nsb3VkU3RvcmFnZS9Ecm9wYm94L2Rldi9ndWlkZXMvY29udGVudC9ib29rL2NoYXB0ZXJzLzA5LWVycm9ycy9wYW5pYy9zcmMvZnVuYy9icm9rZW4vbWFpbi5nbzoxNiArMHgxYwpleGl0IHN0YXR1cyAy", - "duration": 2737692417, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\npanic: runtime error: invalid memory address or nil pointer dereference\n[signal SIGSEGV: segmentation violation code=0x2 addr=0x0 pc=0x1007e6bbc]\n\ngoroutine 1 [running]:\nmain.main()\n\t./main.go:16 +0x1c\nexit status 2", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/func/broken", - "err": { - "Stderr": null - }, - "exit": 1, - "stderr": "cGFuaWM6IHJ1bnRpbWUgZXJyb3I6IGludmFsaWQgbWVtb3J5IGFkZHJlc3Mgb3IgbmlsIHBvaW50ZXIgZGVyZWZlcmVuY2UKW3NpZ25hbCBTSUdTRUdWOiBzZWdtZW50YXRpb24gdmlvbGF0aW9uIGNvZGU9MHgyIGFkZHI9MHgwIHBjPTB4MTAwN2U2YmJjXQoKZ29yb3V0aW5lIDEgW3J1bm5pbmddOgptYWluLm1haW4oKQoJL1VzZXJzL21hcmtiYXRlcy9MaWJyYXJ5L0Nsb3VkU3RvcmFnZS9Ecm9wYm94L2Rldi9ndWlkZXMvY29udGVudC9ib29rL2NoYXB0ZXJzLzA5LWVycm9ycy9wYW5pYy9zcmMvZnVuYy9icm9rZW4vbWFpbi5nbzoxNiArMHgxYwpleGl0IHN0YXR1cyAy", - "duration": 2737692417, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "panic", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.38:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Using an uninitialized function variable.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 38, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "panic/_dont.md", - "nodes": [ - { - "text": "In ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-39" - }, - "file": "panic/_dont.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-39" - }, - "nodes": [ - { - "text": "Listing 1.39", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-39" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", we have assigned a function to the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "panic/_dont.md", - "nodes": [ - { - "text": "fn", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " variable and the application runs successfully.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-39", - "type": "listing" - }, - "file": "panic/_dont.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "panic", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "panic/src/func/fixed/main.go#example" - }, - "lang": "go", - "nodes": [ - { - "content": "func main() {\n\n\t// create a new function\n\t// type variable\n\tvar fn func() string\n\n\t// back the fn variable\n\t// with a function\n\tfn = func() string {\n\t\treturn \"Hello, World!\"\n\t}\n\n\t// print the results\n\t// of the function\n\tfmt.Println(fn())\n}", - "file": "panic/src/func/fixed/main.go", - "lang": "go", - "name": "example", - "start": 7, - "end": 25, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "atom": "hr", - "file": "panic", - "type": "*hype.Element" - }, - [ - { - "args": [ - "go", - "run", - "." - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go run .", - "run": ".", - "src": "panic/src/func/fixed" - }, - "expected_exit": 0, - "file": "panic", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\nHello, World!", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/func/fixed", - "stdout": "SGVsbG8sIFdvcmxkIQ==", - "duration": 4059711417, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\nHello, World!", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/func/fixed", - "stdout": "SGVsbG8sIFdvcmxkIQ==", - "duration": 4059711417, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "panic", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.39:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Assigning a function definition to the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "panic", - "nodes": [ - { - "text": "fn", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " variable.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 39, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "panic/_dont.md", - "level": 2, - "nodes": [ - { - "text": "Type Assertions", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "panic/_dont.md", - "nodes": [ - { - "text": "When type asserting in Go, if the interface being asserted against fails, Go will panic as a result.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-40", - "type": "listing" - }, - "file": "panic/_dont.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "panic", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "panic/src/assert/broken/main.go#write" - }, - "lang": "go", - "nodes": [ - { - "content": "func WriteToFile(w io.Writer, data []byte) error {\n\n\t// assert that w is a file\n\tf := w.(*os.File)\n\n\t// defer closing the file\n\tdefer f.Close()\n\n\t// log the file name\n\tfmt.Printf(\"writing to file %s\\n\", f.Name())\n\n\t// write the data\n\t_, err := f.Write(data)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}", - "file": "panic/src/assert/broken/main.go", - "lang": "go", - "name": "write", - "start": 34, - "end": 55, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "panic", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.40:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Panic caused by a failed type assertion.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 40, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "panic/_dont.md", - "nodes": [ - { - "text": "Consider the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "panic/_dont.md", - "nodes": [ - { - "text": "WriteToFile(io.Writer, []byte)", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function defined in ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-40" - }, - "file": "panic/_dont.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-40" - }, - "nodes": [ - { - "text": "Listing 1.40", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-40" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ". This function takes an ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "io#Writer", - "href": "https://pkg.go.dev/io#Writer", - "target": "_blank" - }, - "file": "panic/_dont.md", - "nodes": [ - { - "atom": "code", - "file": "panic/_dont.md", - "nodes": [ - { - "text": "io.Writer", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/io#Writer" - } - ], - { - "text": " as an argument, along with a ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "panic/_dont.md", - "nodes": [ - { - "text": "[]byte", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " slice of data to write. Inside of the function, the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "io#Writer", - "href": "https://pkg.go.dev/io#Writer", - "target": "_blank" - }, - "file": "panic/_dont.md", - "nodes": [ - { - "atom": "code", - "file": "panic/_dont.md", - "nodes": [ - { - "text": "io.Writer", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/io#Writer" - } - ], - { - "text": " argument, ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "panic/_dont.md", - "nodes": [ - { - "text": "w", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ", is being type asserted to the concrete type ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "os#File", - "href": "https://pkg.go.dev/os#File", - "target": "_blank" - }, - "file": "panic/_dont.md", - "nodes": [ - { - "atom": "code", - "file": "panic/_dont.md", - "nodes": [ - { - "text": "os.File", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/os#File" - } - ], - { - "text": ". In ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-41" - }, - "file": "panic/_dont.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-41" - }, - "nodes": [ - { - "text": "Listing 1.41", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-41" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", we are calling this function with a ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "bytes#Buffer", - "href": "https://pkg.go.dev/bytes#Buffer", - "target": "_blank" - }, - "file": "panic/_dont.md", - "nodes": [ - { - "atom": "code", - "file": "panic/_dont.md", - "nodes": [ - { - "text": "bytes.Buffer", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/bytes#Buffer" - } - ], - { - "text": " as the first argument, which is not an instance of ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "os#File", - "href": "https://pkg.go.dev/os#File", - "target": "_blank" - }, - "file": "panic/_dont.md", - "nodes": [ - { - "atom": "code", - "file": "panic/_dont.md", - "nodes": [ - { - "text": "os.File", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/os#File" - } - ], - { - "text": ". This causes a panic.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-41", - "type": "listing" - }, - "file": "panic/_dont.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "panic", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "panic/src/assert/broken/main.go#example" - }, - "lang": "go", - "nodes": [ - { - "content": "func main() {\n\n\t// create a buffer\n\t// to write to\n\tbb := \u0026bytes.Buffer{}\n\n\t// data to be written\n\tdata := []byte(\"Hello, world!\")\n\n\t// call WriteToFile\n\t// passing the buffer\n\t// and the data\n\terr := WriteToFile(bb, data)\n\n\t// check for errors\n\tif err != nil {\n\t\tfmt.Println(err)\n\t\tos.Exit(1)\n\t}\n}", - "file": "panic/src/assert/broken/main.go", - "lang": "go", - "name": "example", - "start": 10, - "end": 32, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "atom": "hr", - "file": "panic", - "type": "*hype.Element" - }, - [ - { - "args": [ - "go", - "run", - "." - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go run .", - "exit": "-1", - "run": ".", - "src": "panic/src/assert/broken" - }, - "expected_exit": -1, - "file": "panic", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\npanic: interface conversion: io.Writer is *bytes.Buffer, not *os.File\n\ngoroutine 1 [running]:\nmain.WriteToFile({0x104a7f008?, 0x140000acf00?}, {0x140000acee3?, 0x1049ea548?, 0x140000a6000?})\n\t./main.go:38 +0x150\nmain.main()\n\t./main.go:23 +0x68\nexit status 2", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/assert/broken", - "err": { - "Stderr": null - }, - "exit": 1, - "stderr": "cGFuaWM6IGludGVyZmFjZSBjb252ZXJzaW9uOiBpby5Xcml0ZXIgaXMgKmJ5dGVzLkJ1ZmZlciwgbm90ICpvcy5GaWxlCgpnb3JvdXRpbmUgMSBbcnVubmluZ106Cm1haW4uV3JpdGVUb0ZpbGUoezB4MTA0YTdmMDA4PywgMHgxNDAwMDBhY2YwMD99LCB7MHgxNDAwMDBhY2VlMz8sIDB4MTA0OWVhNTQ4PywgMHgxNDAwMDBhNjAwMD99KQoJL1VzZXJzL21hcmtiYXRlcy9MaWJyYXJ5L0Nsb3VkU3RvcmFnZS9Ecm9wYm94L2Rldi9ndWlkZXMvY29udGVudC9ib29rL2NoYXB0ZXJzLzA5LWVycm9ycy9wYW5pYy9zcmMvYXNzZXJ0L2Jyb2tlbi9tYWluLmdvOjM4ICsweDE1MAptYWluLm1haW4oKQoJL1VzZXJzL21hcmtiYXRlcy9MaWJyYXJ5L0Nsb3VkU3RvcmFnZS9Ecm9wYm94L2Rldi9ndWlkZXMvY29udGVudC9ib29rL2NoYXB0ZXJzLzA5LWVycm9ycy9wYW5pYy9zcmMvYXNzZXJ0L2Jyb2tlbi9tYWluLmdvOjIzICsweDY4CmV4aXQgc3RhdHVzIDI=", - "duration": 2931108667, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\npanic: interface conversion: io.Writer is *bytes.Buffer, not *os.File\n\ngoroutine 1 [running]:\nmain.WriteToFile({0x104a7f008?, 0x140000acf00?}, {0x140000acee3?, 0x1049ea548?, 0x140000a6000?})\n\t./main.go:38 +0x150\nmain.main()\n\t./main.go:23 +0x68\nexit status 2", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/assert/broken", - "err": { - "Stderr": null - }, - "exit": 1, - "stderr": "cGFuaWM6IGludGVyZmFjZSBjb252ZXJzaW9uOiBpby5Xcml0ZXIgaXMgKmJ5dGVzLkJ1ZmZlciwgbm90ICpvcy5GaWxlCgpnb3JvdXRpbmUgMSBbcnVubmluZ106Cm1haW4uV3JpdGVUb0ZpbGUoezB4MTA0YTdmMDA4PywgMHgxNDAwMDBhY2YwMD99LCB7MHgxNDAwMDBhY2VlMz8sIDB4MTA0OWVhNTQ4PywgMHgxNDAwMDBhNjAwMD99KQoJL1VzZXJzL21hcmtiYXRlcy9MaWJyYXJ5L0Nsb3VkU3RvcmFnZS9Ecm9wYm94L2Rldi9ndWlkZXMvY29udGVudC9ib29rL2NoYXB0ZXJzLzA5LWVycm9ycy9wYW5pYy9zcmMvYXNzZXJ0L2Jyb2tlbi9tYWluLmdvOjM4ICsweDE1MAptYWluLm1haW4oKQoJL1VzZXJzL21hcmtiYXRlcy9MaWJyYXJ5L0Nsb3VkU3RvcmFnZS9Ecm9wYm94L2Rldi9ndWlkZXMvY29udGVudC9ib29rL2NoYXB0ZXJzLzA5LWVycm9ycy9wYW5pYy9zcmMvYXNzZXJ0L2Jyb2tlbi9tYWluLmdvOjIzICsweDY4CmV4aXQgc3RhdHVzIDI=", - "duration": 2931108667, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "panic", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.41:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Panic caused by a failed type assertion.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 41, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "panic/_dont.md", - "nodes": [ - { - "text": "If asked, Go, will return a second argument, a boolean, during the assertion. That boolean will be ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "panic/_dont.md", - "nodes": [ - { - "text": "true", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " if the assertion was successful and ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "panic/_dont.md", - "nodes": [ - { - "text": "false", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " if it wasn't. Checking this second argument will prevent panics on type assertion failures and keep your application up and running.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-42", - "type": "listing" - }, - "file": "panic/_dont.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "panic", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "panic/src/assert/fixed/main.go#write" - }, - "lang": "go", - "nodes": [ - { - "content": "func WriteToFile(w io.Writer, data []byte) error {\n\n\t// assert that w is a file\n\tf, ok := w.(*os.File)\n\n\t// check the assertion was successful\n\tif !ok {\n\t\treturn fmt.Errorf(\"expected *os.File, got %T\", w)\n\t}\n\n\t// defer closing the file\n\tdefer f.Close()\n\n\t// log the file name\n\tfmt.Printf(\"writing to file %s\\n\", f.Name())\n\n\t// write the data\n\t_, err := f.Write(data)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}", - "file": "panic/src/assert/fixed/main.go", - "lang": "go", - "name": "write", - "start": 34, - "end": 60, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "atom": "hr", - "file": "panic", - "type": "*hype.Element" - }, - [ - { - "args": [ - "go", - "run", - "." - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go run .", - "exit": "-1", - "run": ".", - "src": "panic/src/assert/fixed" - }, - "expected_exit": -1, - "file": "panic", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\nexpected *os.File, got *bytes.Buffer\n\nexit status 1", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/assert/fixed", - "err": { - "Stderr": null - }, - "exit": 1, - "stderr": "ZXhpdCBzdGF0dXMgMQ==", - "stdout": "ZXhwZWN0ZWQgKm9zLkZpbGUsIGdvdCAqYnl0ZXMuQnVmZmVy", - "duration": 2997711750, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\nexpected *os.File, got *bytes.Buffer\n\nexit status 1", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/assert/fixed", - "err": { - "Stderr": null - }, - "exit": 1, - "stderr": "ZXhpdCBzdGF0dXMgMQ==", - "stdout": "ZXhwZWN0ZWQgKm9zLkZpbGUsIGdvdCAqYnl0ZXMuQnVmZmVy", - "duration": 2997711750, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "panic", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.42:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Proper type assertion checking prevents panics.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 42, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - { - "atom": "blockquote", - "file": "panic/_dont.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "panic/_dont.md", - "nodes": [ - { - "text": "Note: It is very important that a type check is not avoided. In virtually all cases, avoiding a type check will lead to a future bug in your code.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "panic/_dont.md", - "level": 2, - "nodes": [ - { - "text": "Array/Slice Indexes", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "panic/_dont.md", - "nodes": [ - { - "text": "When accessing indexes on slices and arrays if the index is greater than the length of the slice/array Go will panic.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-43", - "type": "listing" - }, - "file": "panic/_dont.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "panic", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "panic/src/slices/broken/main.go#find" - }, - "lang": "go", - "nodes": [ - { - "content": "func find(names []string, index int) (string, error) {\n\n\t// find the name at the index\n\ts := names[index]\n\n\t// return an error if the value is empty\n\tif len(s) == 0 {\n\t\treturn s, fmt.Errorf(\"index %d empty\", index)\n\t}\n\n\t// return the name\n\treturn s, nil\n}", - "file": "panic/src/slices/broken/main.go", - "lang": "go", - "name": "find", - "start": 29, - "end": 44, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "panic", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.43:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "A function for retrieving the index of a slice.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 43, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "panic/_dont.md", - "nodes": [ - { - "text": "Consider the function defined in ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-43" - }, - "file": "panic/_dont.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-43" - }, - "nodes": [ - { - "text": "Listing 1.43", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-43" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ". This function attempts to access the given index of the given slice. If the index is greater than the length of the slice, Go will panic, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-44" - }, - "file": "panic/_dont.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-44" - }, - "nodes": [ - { - "text": "Listing 1.44", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-44" - } - ], - "type": "*hype.Ref" - } - ] - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-44", - "type": "listing" - }, - "file": "panic/_dont.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "panic", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "panic/src/slices/broken/main.go#example" - }, - "lang": "go", - "nodes": [ - { - "content": "func main() {\n\n\t// create a slice\n\tnames := []string{\"Kurt\", \"Janis\", \"Jimi\", \"Amy\"}\n\n\t// find index 42\n\ts, err := find(names, 42)\n\n\t// check for errors\n\tif err != nil {\n\t\tfmt.Println(err)\n\t\tos.Exit(1)\n\t}\n\n\t// print the result\n\tfmt.Println(\"found: \", s)\n}", - "file": "panic/src/slices/broken/main.go", - "lang": "go", - "name": "example", - "start": 8, - "end": 27, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "atom": "hr", - "file": "panic", - "type": "*hype.Element" - }, - [ - { - "args": [ - "go", - "run", - "." - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go run .", - "exit": "-1", - "run": ".", - "src": "panic/src/slices/broken" - }, - "expected_exit": -1, - "file": "panic", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\npanic: runtime error: index out of range [42] with length 4\n\ngoroutine 1 [running]:\nmain.find({0x14000104ee8?, 0x102297d6c?, 0x14000104ec8?}, 0x102298734?)\n\t./main.go:33 +0xb0\nmain.main()\n\t./main.go:15 +0x88\nexit status 2", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/slices/broken", - "err": { - "Stderr": null - }, - "exit": 1, - "stderr": "cGFuaWM6IHJ1bnRpbWUgZXJyb3I6IGluZGV4IG91dCBvZiByYW5nZSBbNDJdIHdpdGggbGVuZ3RoIDQKCmdvcm91dGluZSAxIFtydW5uaW5nXToKbWFpbi5maW5kKHsweDE0MDAwMTA0ZWU4PywgMHgxMDIyOTdkNmM/LCAweDE0MDAwMTA0ZWM4P30sIDB4MTAyMjk4NzM0PykKCS9Vc2Vycy9tYXJrYmF0ZXMvTGlicmFyeS9DbG91ZFN0b3JhZ2UvRHJvcGJveC9kZXYvZ3VpZGVzL2NvbnRlbnQvYm9vay9jaGFwdGVycy8wOS1lcnJvcnMvcGFuaWMvc3JjL3NsaWNlcy9icm9rZW4vbWFpbi5nbzozMyArMHhiMAptYWluLm1haW4oKQoJL1VzZXJzL21hcmtiYXRlcy9MaWJyYXJ5L0Nsb3VkU3RvcmFnZS9Ecm9wYm94L2Rldi9ndWlkZXMvY29udGVudC9ib29rL2NoYXB0ZXJzLzA5LWVycm9ycy9wYW5pYy9zcmMvc2xpY2VzL2Jyb2tlbi9tYWluLmdvOjE1ICsweDg4CmV4aXQgc3RhdHVzIDI=", - "duration": 2861713666, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\npanic: runtime error: index out of range [42] with length 4\n\ngoroutine 1 [running]:\nmain.find({0x14000104ee8?, 0x102297d6c?, 0x14000104ec8?}, 0x102298734?)\n\t./main.go:33 +0xb0\nmain.main()\n\t./main.go:15 +0x88\nexit status 2", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/slices/broken", - "err": { - "Stderr": null - }, - "exit": 1, - "stderr": "cGFuaWM6IHJ1bnRpbWUgZXJyb3I6IGluZGV4IG91dCBvZiByYW5nZSBbNDJdIHdpdGggbGVuZ3RoIDQKCmdvcm91dGluZSAxIFtydW5uaW5nXToKbWFpbi5maW5kKHsweDE0MDAwMTA0ZWU4PywgMHgxMDIyOTdkNmM/LCAweDE0MDAwMTA0ZWM4P30sIDB4MTAyMjk4NzM0PykKCS9Vc2Vycy9tYXJrYmF0ZXMvTGlicmFyeS9DbG91ZFN0b3JhZ2UvRHJvcGJveC9kZXYvZ3VpZGVzL2NvbnRlbnQvYm9vay9jaGFwdGVycy8wOS1lcnJvcnMvcGFuaWMvc3JjL3NsaWNlcy9icm9rZW4vbWFpbi5nbzozMyArMHhiMAptYWluLm1haW4oKQoJL1VzZXJzL21hcmtiYXRlcy9MaWJyYXJ5L0Nsb3VkU3RvcmFnZS9Ecm9wYm94L2Rldi9ndWlkZXMvY29udGVudC9ib29rL2NoYXB0ZXJzLzA5LWVycm9ycy9wYW5pYy9zcmMvc2xpY2VzL2Jyb2tlbi9tYWluLmdvOjE1ICsweDg4CmV4aXQgc3RhdHVzIDI=", - "duration": 2861713666, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "panic", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.44:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "An out of bounds panic.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 44, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "panic/_dont.md", - "nodes": [ - { - "text": "To avoid this panic, check the length of slice/array to ensure the requested index can safely be retrieved. In ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-45" - }, - "file": "panic/_dont.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-45" - }, - "nodes": [ - { - "text": "Listing 1.45", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-45" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", the index is checked against the length of the slice/array before being accessed. If the index is greater than the length of the slice/array, the function will return an ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "builtin#error", - "href": "https://pkg.go.dev/builtin#error", - "target": "_blank" - }, - "file": "panic/_dont.md", - "nodes": [ - { - "atom": "code", - "file": "panic/_dont.md", - "nodes": [ - { - "text": "error", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/builtin#error" - } - ], - { - "text": " instead of panicking.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-45", - "type": "listing" - }, - "file": "panic/_dont.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "panic", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "panic/src/slices/fixed/main.go#find" - }, - "lang": "go", - "nodes": [ - { - "content": "func find(names []string, index int) (string, error) {\n\n\t// check for out of bounds index\n\tif index \u003e= len(names) {\n\t\treturn \"\", fmt.Errorf(\"out of bounds index %d [%d]\", index, len(names))\n\t}\n\n\t// find the name at the index\n\ts := names[index]\n\n\t// return an error if the value is empty\n\tif len(s) == 0 {\n\t\treturn s, fmt.Errorf(\"index %d empty\", index)\n\t}\n\n\t// return the name\n\treturn s, nil\n}", - "file": "panic/src/slices/fixed/main.go", - "lang": "go", - "name": "find", - "start": 29, - "end": 49, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "atom": "hr", - "file": "panic", - "type": "*hype.Element" - }, - [ - { - "args": [ - "go", - "run", - "." - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go run .", - "exit": "-1", - "run": ".", - "src": "panic/src/slices/fixed" - }, - "expected_exit": -1, - "file": "panic", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\nout of bounds index 42 [4]\n\nexit status 1", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/slices/fixed", - "err": { - "Stderr": null - }, - "exit": 1, - "stderr": "ZXhpdCBzdGF0dXMgMQ==", - "stdout": "b3V0IG9mIGJvdW5kcyBpbmRleCA0MiBbNF0=", - "duration": 3722740334, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\nout of bounds index 42 [4]\n\nexit status 1", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/panic/src/slices/fixed", - "err": { - "Stderr": null - }, - "exit": 1, - "stderr": "ZXhpdCBzdGF0dXMgMQ==", - "stdout": "b3V0IG9mIGJvdW5kcyBpbmRleCA0MiBbNF0=", - "duration": 3722740334, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "panic", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.45:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Proper type assertion checking prevents panics.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 45, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "title": "Don't Panic", - "type": "*hype.Page" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "type": "*hype.Include" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "type": "*hype.Include" - } - ], - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "include", - "attributes": { - "src": "errors/custom.md" - }, - "dir": "errors", - "file": "module.md", - "nodes": [ - [ - { - "atom": "page", - "file": "errors/custom.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "h1", - "file": "errors/custom.md", - "level": 1, - "nodes": [ - { - "text": "Custom Errors", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "errors/custom.md", - "nodes": [ - { - "text": "As we have seen, errors in Go are implemented via the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "builtin#error", - "href": "https://pkg.go.dev/builtin#error", - "target": "_blank" - }, - "file": "errors/custom.md", - "nodes": [ - { - "atom": "code", - "file": "errors/custom.md", - "nodes": [ - { - "text": "error", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/builtin#error" - } - ], - { - "text": " interface, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-46" - }, - "file": "errors/custom.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-46" - }, - "nodes": [ - { - "text": "Listing 1.46", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-46" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ". This means we can create our own custom error implementations. Custom errors allow us to manage workflow and provide detailed information about an error beyond the scope of the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "builtin#error", - "href": "https://pkg.go.dev/builtin#error", - "target": "_blank" - }, - "file": "errors/custom.md", - "nodes": [ - { - "atom": "code", - "file": "errors/custom.md", - "nodes": [ - { - "text": "error", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/builtin#error" - } - ], - { - "text": " interface.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-46", - "type": "listing" - }, - "file": "errors/custom.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "doc", - "builtin.error" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "doc": "builtin.error", - "exec": "go doc builtin.error" - }, - "expected_exit": 0, - "file": "errors", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc builtin.error\n\npackage builtin // import \u0026#34;builtin\u0026#34;\n\ntype error interface {\n\tError() string\n}\n The error built-in interface type is the conventional interface for\n representing an error condition, with the nil value representing no error.", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "builtin.error" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBidWlsdGluIC8vIGltcG9ydCAiYnVpbHRpbiIKCnR5cGUgZXJyb3IgaW50ZXJmYWNlIHsKCUVycm9yKCkgc3RyaW5nCn0KICAgIFRoZSBlcnJvciBidWlsdC1pbiBpbnRlcmZhY2UgdHlwZSBpcyB0aGUgY29udmVudGlvbmFsIGludGVyZmFjZSBmb3IKICAgIHJlcHJlc2VudGluZyBhbiBlcnJvciBjb25kaXRpb24sIHdpdGggdGhlIG5pbCB2YWx1ZSByZXByZXNlbnRpbmcgbm8gZXJyb3Iu", - "duration": 2629797875, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc builtin.error\n\npackage builtin // import \u0026#34;builtin\u0026#34;\n\ntype error interface {\n\tError() string\n}\n The error built-in interface type is the conventional interface for\n representing an error condition, with the nil value representing no error.", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "builtin.error" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBidWlsdGluIC8vIGltcG9ydCAiYnVpbHRpbiIKCnR5cGUgZXJyb3IgaW50ZXJmYWNlIHsKCUVycm9yKCkgc3RyaW5nCn0KICAgIFRoZSBlcnJvciBidWlsdC1pbiBpbnRlcmZhY2UgdHlwZSBpcyB0aGUgY29udmVudGlvbmFsIGludGVyZmFjZSBmb3IKICAgIHJlcHJlc2VudGluZyBhbiBlcnJvciBjb25kaXRpb24sIHdpdGggdGhlIG5pbCB2YWx1ZSByZXByZXNlbnRpbmcgbm8gZXJyb3Iu", - "duration": 2629797875, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "errors", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.46:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "builtin#error", - "href": "https://pkg.go.dev/builtin#error", - "target": "_blank" - }, - "file": "errors", - "nodes": [ - [ - { - "atom": "code", - "file": "errors", - "nodes": [ - { - "text": "error", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/builtin#error" - } - ], - { - "text": " interface.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 46, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "errors/custom.md", - "level": 2, - "nodes": [ - { - "text": "Standard Errors", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "errors/custom.md", - "nodes": [ - { - "text": "Let's consider ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-47" - }, - "file": "errors/custom.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-47" - }, - "nodes": [ - { - "text": "Listing 1.47", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-47" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ". A couple of types are being defined. The first, ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "errors/custom.md", - "nodes": [ - { - "text": "Model", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ", is based on ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "errors/custom.md", - "nodes": [ - { - "text": "map[string]any", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ". For example, ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "errors/custom.md", - "nodes": [ - { - "text": "{\"age\": 27, \"name\": \"jimi\"}", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ". Next, a ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "errors/custom.md", - "nodes": [ - { - "text": "Store", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " struct type is defined with a ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "errors/custom.md", - "nodes": [ - { - "text": "data", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " field of type ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "errors/custom.md", - "nodes": [ - { - "text": "map[string][]Model", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ". This ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "errors/custom.md", - "nodes": [ - { - "text": "data", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " field is a map of table names to their models.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-47", - "type": "listing" - }, - "file": "errors/custom.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "errors", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "errors/src/custom/store.go#store" - }, - "lang": "go", - "nodes": [ - { - "content": "// Model is a key/value pair representing a model in the store.\n// e.g. {\"id\": 1, \"name\": \"bob\"}\ntype Model map[string]any\n\n// Store is a table based key/value store.\ntype Store struct {\n\tdata map[string][]Model\n}", - "file": "errors/src/custom/store.go", - "lang": "go", - "name": "store", - "start": 5, - "end": 16, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "errors", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.47:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Type definitions.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 47, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "errors/custom.md", - "nodes": [ - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "errors/custom.md", - "nodes": [ - { - "text": "Store", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " has a method, ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "errors/custom.md", - "nodes": [ - { - "text": "All(string)", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ", that will return all of the models in the store for the given table. If the table doesn't exist an error will be returned. This error is created using the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "fmt#Errorf", - "href": "https://pkg.go.dev/fmt#Errorf", - "target": "_blank" - }, - "file": "errors/custom.md", - "nodes": [ - { - "atom": "code", - "file": "errors/custom.md", - "nodes": [ - { - "text": "fmt.Errorf", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/fmt#Errorf" - } - ], - { - "text": " function.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-48", - "type": "listing" - }, - "file": "errors/custom.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "errors", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "errors/src/custom/store.go#all" - }, - "lang": "go", - "nodes": [ - { - "content": "// All returns all models in the store for the given table name.\n// If no models exist, an error is returned.\nfunc (s *Store) All(tn string) ([]Model, error) {\n\tdb := s.data\n\n\t// if the underlying data is nil, return an error\n\tif db == nil {\n\t\treturn nil, fmt.Errorf(\"no data\")\n\t}\n\n\t// check to make sure table exists\n\tmods, ok := db[tn]\n\n\t// if table doesn't exist, return an error\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"table %s not found\", tn)\n\t}\n\n\t// return the slice of models\n\treturn mods, nil\n}", - "file": "errors/src/custom/store.go", - "lang": "go", - "name": "all", - "start": 18, - "end": 41, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "errors", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.48:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "errors", - "nodes": [ - { - "text": "Store.All", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " method.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 48, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "errors/custom.md", - "nodes": [ - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-49" - }, - "file": "errors/custom.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-49" - }, - "nodes": [ - { - "text": "Listing 1.49", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-49" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": " is a test that asserts that if a given table doesn't exist in the store. This test, however, is lacking. Yes it asserts that an error was returned, but we don't know which error was returned. Did the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "errors/custom.md", - "nodes": [ - { - "text": "All", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " method return an error because the table didn't exist or because the underlying ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "errors/custom.md", - "nodes": [ - { - "text": "data", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " map was ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "errors/custom.md", - "nodes": [ - { - "text": "nil", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": "?", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-49", - "type": "listing" - }, - "file": "errors/custom.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "errors", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "errors/src/custom/store_test.go#test" - }, - "lang": "go", - "nodes": [ - { - "content": "func Test_Store_All_NoTable(t *testing.T) {\n\tt.Parallel()\n\n\ts := \u0026Store{\n\t\tdata: map[string][]Model{},\n\t}\n\n\t_, err := s.All(\"users\")\n\tif err == nil {\n\t\tt.Fatal(\"expected error, got nil\")\n\t}\n\n\texp := \"table users not found\"\n\tact := err.Error()\n\tif act != exp {\n\t\tt.Fatalf(\"expected %q, got %q\", exp, act)\n\t}\n}", - "file": "errors/src/custom/store_test.go", - "lang": "go", - "name": "test", - "start": 5, - "end": 27, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "atom": "hr", - "file": "errors", - "type": "*hype.Element" - }, - [ - { - "args": [ - "go", - "test", - "-v" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go test -v", - "src": "errors/src/custom", - "test": "-v" - }, - "expected_exit": 0, - "file": "errors", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go test -v\n\n=== RUN Test_Store_All_NoTable\n=== PAUSE Test_Store_All_NoTable\n=== CONT Test_Store_All_NoTable\n--- PASS: Test_Store_All_NoTable (0.00s)\nPASS\nok \tdemo\t1.919s", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "test", - "-v" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/errors/src/custom", - "stdout": "PT09IFJVTiAgIFRlc3RfU3RvcmVfQWxsX05vVGFibGUKPT09IFBBVVNFIFRlc3RfU3RvcmVfQWxsX05vVGFibGUKPT09IENPTlQgIFRlc3RfU3RvcmVfQWxsX05vVGFibGUKLS0tIFBBU1M6IFRlc3RfU3RvcmVfQWxsX05vVGFibGUgKDAuMDBzKQpQQVNTCm9rICAJZGVtbwkxLjkxOXM=", - "duration": 4775293208, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go test -v\n\n=== RUN Test_Store_All_NoTable\n=== PAUSE Test_Store_All_NoTable\n=== CONT Test_Store_All_NoTable\n--- PASS: Test_Store_All_NoTable (0.00s)\nPASS\nok \tdemo\t1.919s", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "test", - "-v" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/errors/src/custom", - "stdout": "PT09IFJVTiAgIFRlc3RfU3RvcmVfQWxsX05vVGFibGUKPT09IFBBVVNFIFRlc3RfU3RvcmVfQWxsX05vVGFibGUKPT09IENPTlQgIFRlc3RfU3RvcmVfQWxsX05vVGFibGUKLS0tIFBBU1M6IFRlc3RfU3RvcmVfQWxsX05vVGFibGUgKDAuMDBzKQpQQVNTCm9rICAJZGVtbwkxLjkxOXM=", - "duration": 4775293208, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "errors", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.49:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "A test for the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "errors", - "nodes": [ - { - "text": "Store.All", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " method.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 49, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "errors/custom.md", - "nodes": [ - { - "text": "Like in, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-49" - }, - "file": "errors/custom.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-49" - }, - "nodes": [ - { - "text": "Listing 1.49", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-49" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", it might be tempting to assert against an error's message, but that is considered non-idiomatic and should never be used. The reason for this is simple; error messages change. If the error message changes the following test will fail. We consider this to be a \"brittle\" test.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "errors/custom.md", - "level": 2, - "nodes": [ - { - "text": "Defining Custom Errors", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "errors/custom.md", - "nodes": [ - { - "text": "We can define custom errors that can help distinguish one error from another, as well as, add more context around the error.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "errors/custom.md", - "nodes": [ - { - "text": "In ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-50" - }, - "file": "errors/custom.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-50" - }, - "nodes": [ - { - "text": "Listing 1.50", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-50" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": " we define a new ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "errors/custom.md", - "nodes": [ - { - "text": "struct", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " type, ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "errors/custom.md", - "nodes": [ - { - "text": "ErrTableNotFound", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ", that will implement the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "builtin#error", - "href": "https://pkg.go.dev/builtin#error", - "target": "_blank" - }, - "file": "errors/custom.md", - "nodes": [ - { - "atom": "code", - "file": "errors/custom.md", - "nodes": [ - { - "text": "error", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/builtin#error" - } - ], - { - "text": " interface. This type will contain information such as what table was missing and what time the error occurred.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-50", - "type": "listing" - }, - "file": "errors/custom.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "errors", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "errors/src/custom-table-err/errors.go#err-table-not-found" - }, - "lang": "go", - "nodes": [ - { - "content": "type ErrTableNotFound struct {\n\tTable string\n\tOccurredAt time.Time\n}\n\nfunc (e ErrTableNotFound) Error() string {\n\treturn fmt.Sprintf(\"[%s] table not found %s\", e.OccurredAt, e.Table)\n}", - "file": "errors/src/custom-table-err/errors.go", - "lang": "go", - "name": "err-table-not-found", - "start": 8, - "end": 18, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "errors", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.50:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "errors", - "nodes": [ - { - "text": "ErrTableNotFound", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " struct.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 50, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "errors/custom.md", - "nodes": [ - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-51" - }, - "file": "errors/custom.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-51" - }, - "nodes": [ - { - "text": "Listing 1.51", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-51" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": " updates the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "errors/custom.md", - "nodes": [ - { - "text": "Store.All(string)", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ", method to now return an ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "errors/custom.md", - "nodes": [ - { - "text": "ErrTableNotFound", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " error if the table doesn't exist. We also set the table name and the time the error occurred.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-51", - "type": "listing" - }, - "file": "errors/custom.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "errors", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "errors/src/custom-table-err/store.go#all" - }, - "lang": "go", - "nodes": [ - { - "content": "// All returns all models in the store for the given table name.\n// If no models exist, an error is returned.\nfunc (s *Store) All(tn string) ([]Model, error) {\n\tdb := s.data\n\n\t// if the underlying data is nil, return an error\n\tif db == nil {\n\t\treturn nil, fmt.Errorf(\"no data\")\n\t}\n\n\t// check to make sure table exists\n\tmods, ok := db[tn]\n\n\t// if table doesn't exist, return an error\n\tif !ok {\n\t\treturn nil, ErrTableNotFound{\n\t\t\tTable: tn,\n\t\t\tOccurredAt: time.Now(),\n\t\t}\n\t}\n\n\t// return the slice of models\n\treturn mods, nil\n}", - "file": "errors/src/custom-table-err/store.go", - "lang": "go", - "name": "all", - "start": 21, - "end": 47, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "errors", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.51:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "errors", - "nodes": [ - { - "text": "Store.All", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " method with custom errors.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 51, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "errors/custom.md", - "nodes": [ - { - "text": "The test can now be updated, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-52" - }, - "file": "errors/custom.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-52" - }, - "nodes": [ - { - "text": "Listing 1.52", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-52" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", to assert that the error is an ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "errors/custom.md", - "nodes": [ - { - "text": "ErrTableNotFound", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " error. The test passes and we can see the table name and the time the error occurred.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-52", - "type": "listing" - }, - "file": "errors/custom.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "errors", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "errors/src/custom-table-err/store_test.go#test" - }, - "lang": "go", - "nodes": [ - { - "content": "func Test_Store_All_NoTable(t *testing.T) {\n\tt.Parallel()\n\n\ts := \u0026Store{\n\t\tdata: map[string][]Model{},\n\t}\n\n\t_, err := s.All(\"users\")\n\tif err == nil {\n\t\tt.Fatal(\"expected error, got nil\")\n\t}\n\n\texp := \"users\"\n\te, ok := err.(ErrTableNotFound)\n\tif !ok {\n\t\tt.Fatalf(\"expected ErrTableNotFound, got %T\", err)\n\t}\n\n\tact := e.Table\n\tif act != exp {\n\t\tt.Fatalf(\"expected %q, got %q\", exp, act)\n\t}\n\n\tif e.OccurredAt.IsZero() {\n\t\tt.Fatal(\"expected non-zero time\")\n\t}\n}", - "file": "errors/src/custom-table-err/store_test.go", - "lang": "go", - "name": "test", - "start": 5, - "end": 36, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "atom": "hr", - "file": "errors", - "type": "*hype.Element" - }, - [ - { - "args": [ - "go", - "test", - "-v" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go test -v", - "src": "errors/src/custom-table-err", - "test": "-v" - }, - "expected_exit": 0, - "file": "errors", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go test -v\n\n=== RUN Test_Store_All_NoTable\n=== PAUSE Test_Store_All_NoTable\n=== CONT Test_Store_All_NoTable\n--- PASS: Test_Store_All_NoTable (0.00s)\nPASS\nok \tdemo\t2.353s", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "test", - "-v" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/errors/src/custom-table-err", - "stdout": "PT09IFJVTiAgIFRlc3RfU3RvcmVfQWxsX05vVGFibGUKPT09IFBBVVNFIFRlc3RfU3RvcmVfQWxsX05vVGFibGUKPT09IENPTlQgIFRlc3RfU3RvcmVfQWxsX05vVGFibGUKLS0tIFBBU1M6IFRlc3RfU3RvcmVfQWxsX05vVGFibGUgKDAuMDBzKQpQQVNTCm9rICAJZGVtbwkyLjM1M3M=", - "duration": 5251222625, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go test -v\n\n=== RUN Test_Store_All_NoTable\n=== PAUSE Test_Store_All_NoTable\n=== CONT Test_Store_All_NoTable\n--- PASS: Test_Store_All_NoTable (0.00s)\nPASS\nok \tdemo\t2.353s", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "test", - "-v" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/errors/src/custom-table-err", - "stdout": "PT09IFJVTiAgIFRlc3RfU3RvcmVfQWxsX05vVGFibGUKPT09IFBBVVNFIFRlc3RfU3RvcmVfQWxsX05vVGFibGUKPT09IENPTlQgIFRlc3RfU3RvcmVfQWxsX05vVGFibGUKLS0tIFBBU1M6IFRlc3RfU3RvcmVfQWxsX05vVGFibGUgKDAuMDBzKQpQQVNTCm9rICAJZGVtbwkyLjM1M3M=", - "duration": 5251222625, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "errors", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.52:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "A test for the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "errors", - "nodes": [ - { - "text": "Store.All", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " method with custom errors.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 52, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "title": "Custom Errors", - "type": "*hype.Page" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "type": "*hype.Include" - } - ], - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "include", - "attributes": { - "src": "errors/wrapping.md" - }, - "dir": "errors", - "file": "module.md", - "nodes": [ - [ - { - "atom": "page", - "file": "errors/wrapping.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "h1", - "file": "errors/wrapping.md", - "level": 1, - "nodes": [ - { - "text": "Wrapping and Unwrapping Errors", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "errors/wrapping.md", - "nodes": [ - { - "text": "Consider the method defined in ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-53" - }, - "file": "errors/wrapping.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-53" - }, - "nodes": [ - { - "text": "Listing 1.53", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-53" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ". If an error occurs a custom ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "builtin#error", - "href": "https://pkg.go.dev/builtin#error", - "target": "_blank" - }, - "file": "errors/wrapping.md", - "nodes": [ - { - "atom": "code", - "file": "errors/wrapping.md", - "nodes": [ - { - "text": "error", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/builtin#error" - } - ], - { - "text": " implementation, ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "errors/wrapping.md", - "nodes": [ - { - "text": "ErrTableNotFound", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ", is initialized with the appropriate information. Before being returned, however, error is then wrapped with ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "fmt#Errorf", - "href": "https://pkg.go.dev/fmt#Errorf", - "target": "_blank" - }, - "file": "errors/wrapping.md", - "nodes": [ - { - "atom": "code", - "file": "errors/wrapping.md", - "nodes": [ - { - "text": "fmt.Errorf", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/fmt#Errorf" - } - ], - { - "text": " to a message that includes the type and method that caused the error. To wrap an error using ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "fmt#Errorf", - "href": "https://pkg.go.dev/fmt#Errorf", - "target": "_blank" - }, - "file": "errors/wrapping.md", - "nodes": [ - { - "atom": "code", - "file": "errors/wrapping.md", - "nodes": [ - { - "text": "fmt.Errorf", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/fmt#Errorf" - } - ], - { - "text": ", we can use the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "errors/wrapping.md", - "nodes": [ - { - "text": "%w", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " formatting verb, meant for errors.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-53", - "type": "listing" - }, - "file": "errors/wrapping.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "errors", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "errors/src/wrapped-error/store.go#all" - }, - "lang": "go", - "nodes": [ - { - "content": "// All returns all models in the store for the given table name.\n// If no models exist, an error is returned.\nfunc (s *Store) All(tn string) ([]Model, error) {\n\tdb := s.data\n\n\t// if the underlying data is nil, return an error\n\tif db == nil {\n\t\treturn nil, fmt.Errorf(\"no data\")\n\t}\n\n\t// check to make sure table exists\n\tmods, ok := db[tn]\n\n\t// if table doesn't exist, return an error\n\tif !ok {\n\t\terr := ErrTableNotFound{\n\t\t\tTable: tn,\n\t\t\tOccurredAt: time.Now(),\n\t\t}\n\t\treturn nil, fmt.Errorf(\"[Store.All] %w\", err)\n\t}\n\n\t// return the slice of models\n\treturn mods, nil\n}", - "file": "errors/src/wrapped-error/store.go", - "lang": "go", - "name": "all", - "start": 21, - "end": 48, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "errors", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.53:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "errors", - "nodes": [ - { - "text": "Store.All", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " method.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 53, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "errors/wrapping.md", - "nodes": [ - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-54" - }, - "file": "errors/wrapping.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-54" - }, - "nodes": [ - { - "text": "Listing 1.54", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-54" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": " shows a test for the method in ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-53" - }, - "file": "errors/wrapping.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-53" - }, - "nodes": [ - { - "text": "Listing 1.53", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-53" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ". This test tries to assert the returned error is of type ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "errors/wrapping.md", - "nodes": [ - { - "text": "ErrTableNotFound", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ". When an error is wrapped with ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "fmt#Errorf", - "href": "https://pkg.go.dev/fmt#Errorf", - "target": "_blank" - }, - "file": "errors/wrapping.md", - "nodes": [ - { - "atom": "code", - "file": "errors/wrapping.md", - "nodes": [ - { - "text": "fmt.Errorf", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/fmt#Errorf" - } - ], - { - "text": ", the resulting type is that of the general ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "builtin#error", - "href": "https://pkg.go.dev/builtin#error", - "target": "_blank" - }, - "file": "errors/wrapping.md", - "nodes": [ - { - "atom": "code", - "file": "errors/wrapping.md", - "nodes": [ - { - "text": "error", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/builtin#error" - } - ], - { - "text": " interface. As such, by wrapping the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "errors/wrapping.md", - "nodes": [ - { - "text": "ErrTableNotFound", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " error with ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "fmt#Errorf", - "href": "https://pkg.go.dev/fmt#Errorf", - "target": "_blank" - }, - "file": "errors/wrapping.md", - "nodes": [ - { - "atom": "code", - "file": "errors/wrapping.md", - "nodes": [ - { - "text": "fmt.Errorf", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/fmt#Errorf" - } - ], - { - "text": " we have changed the resulting type of the error. This also results in the tests failing as the error is no longer an ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "errors/wrapping.md", - "nodes": [ - { - "text": "ErrTableNotFound", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ", but a different type.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-54", - "type": "listing" - }, - "file": "errors/wrapping.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "errors", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "errors/src/wrapped-error/store_test.go#test" - }, - "lang": "go", - "nodes": [ - { - "content": "func Test_Store_All_NoTable(t *testing.T) {\n\tt.Parallel()\n\n\ts := \u0026Store{\n\t\tdata: map[string][]Model{},\n\t}\n\n\t_, err := s.All(\"users\")\n\tif err == nil {\n\t\tt.Fatal(\"expected error, got nil\")\n\t}\n\n\texp := \"users\"\n\te, ok := err.(ErrTableNotFound)\n\tif !ok {\n\t\tt.Fatalf(\"expected ErrTableNotFound, got %T\", err)\n\t}\n\n\tact := e.Table\n\tif act != exp {\n\t\tt.Fatalf(\"expected %q, got %q\", exp, act)\n\t}\n\n\tif e.OccurredAt.IsZero() {\n\t\tt.Fatal(\"expected non-zero time\")\n\t}\n}", - "file": "errors/src/wrapped-error/store_test.go", - "lang": "go", - "name": "test", - "start": 5, - "end": 34, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "test", - "-v" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go test -v", - "exit": "-1", - "src": "errors/src/wrapped-error", - "test": "-v" - }, - "expected_exit": -1, - "file": "errors", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go test -v\n\n=== RUN Test_Store_All_NoTable\n=== PAUSE Test_Store_All_NoTable\n=== CONT Test_Store_All_NoTable\n store_test.go:21: expected ErrTableNotFound, got *fmt.wrapError\n--- FAIL: Test_Store_All_NoTable (0.00s)\nFAIL\nexit status 1\nFAIL\tdemo\t1.606s", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "test", - "-v" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/errors/src/wrapped-error", - "err": { - "Stderr": null - }, - "exit": 1, - "stdout": "PT09IFJVTiAgIFRlc3RfU3RvcmVfQWxsX05vVGFibGUKPT09IFBBVVNFIFRlc3RfU3RvcmVfQWxsX05vVGFibGUKPT09IENPTlQgIFRlc3RfU3RvcmVfQWxsX05vVGFibGUKICAgIHN0b3JlX3Rlc3QuZ286MjE6IGV4cGVjdGVkIEVyclRhYmxlTm90Rm91bmQsIGdvdCAqZm10LndyYXBFcnJvcgotLS0gRkFJTDogVGVzdF9TdG9yZV9BbGxfTm9UYWJsZSAoMC4wMHMpCkZBSUwKZXhpdCBzdGF0dXMgMQpGQUlMCWRlbW8JMS42MDZz", - "duration": 4406563000, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go test -v\n\n=== RUN Test_Store_All_NoTable\n=== PAUSE Test_Store_All_NoTable\n=== CONT Test_Store_All_NoTable\n store_test.go:21: expected ErrTableNotFound, got *fmt.wrapError\n--- FAIL: Test_Store_All_NoTable (0.00s)\nFAIL\nexit status 1\nFAIL\tdemo\t1.606s", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "test", - "-v" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/errors/src/wrapped-error", - "err": { - "Stderr": null - }, - "exit": 1, - "stdout": "PT09IFJVTiAgIFRlc3RfU3RvcmVfQWxsX05vVGFibGUKPT09IFBBVVNFIFRlc3RfU3RvcmVfQWxsX05vVGFibGUKPT09IENPTlQgIFRlc3RfU3RvcmVfQWxsX05vVGFibGUKICAgIHN0b3JlX3Rlc3QuZ286MjE6IGV4cGVjdGVkIEVyclRhYmxlTm90Rm91bmQsIGdvdCAqZm10LndyYXBFcnJvcgotLS0gRkFJTDogVGVzdF9TdG9yZV9BbGxfTm9UYWJsZSAoMC4wMHMpCkZBSUwKZXhpdCBzdGF0dXMgMQpGQUlMCWRlbW8JMS42MDZz", - "duration": 4406563000, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "errors", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.54:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "A wrapped error can no longer be asserted against correctly.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 54, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "errors/wrapping.md", - "level": 2, - "nodes": [ - { - "text": "Wrapping Errors", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "errors/wrapping.md", - "nodes": [ - { - "text": "In order to get to the original error we need to unwrap the errors until we reach the original error. This is similar to peeling an onion, where each error is a layer of wrapping.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "errors/wrapping.md", - "nodes": [ - { - "text": "Let's take a simplified look at how wrapping and unwrapping errors works in Go. Consider the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "builtin#error", - "href": "https://pkg.go.dev/builtin#error", - "target": "_blank" - }, - "file": "errors/wrapping.md", - "nodes": [ - { - "atom": "code", - "file": "errors/wrapping.md", - "nodes": [ - { - "text": "error", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/builtin#error" - } - ], - { - "text": " types defined in ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-55" - }, - "file": "errors/wrapping.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-55" - }, - "nodes": [ - { - "text": "Listing 1.55", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-55" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ". Each one contains a ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "errors/wrapping.md", - "nodes": [ - { - "text": "err", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " field that holds the error that is wrapping.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-55", - "type": "listing" - }, - "file": "errors/wrapping.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "errors", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "errors/src/wrapping-error/errors.go#errors" - }, - "lang": "go", - "nodes": [ - { - "content": "type ErrorA struct {\n\terr error\n}\n\nfunc (e ErrorA) Error() string {\n\treturn fmt.Sprintf(\"[ErrorA] %s\", e.err)\n}\n\ntype ErrorB struct {\n\terr error\n}\n\nfunc (e ErrorB) Error() string {\n\treturn fmt.Sprintf(\"[ErrorB] %s\", e.err)\n}\n\ntype ErrorC struct {\n\terr error\n}\n\nfunc (e ErrorC) Error() string {\n\treturn fmt.Sprintf(\"[ErrorC] %s\", e.err)\n}", - "file": "errors/src/wrapping-error/errors.go", - "lang": "go", - "name": "errors", - "start": 5, - "end": 30, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "errors", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.55:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The three error types.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 55, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "errors/wrapping.md", - "nodes": [ - { - "text": "In ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-56" - }, - "file": "errors/wrapping.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-56" - }, - "nodes": [ - { - "text": "Listing 1.56", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-56" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "errors/wrapping.md", - "nodes": [ - { - "text": "Wrapper", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function takes an error and the proceeds to wrap it in each of the three error types.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-56", - "type": "listing" - }, - "file": "errors/wrapping.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "errors", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "errors/src/wrapping-error/errors.go#wrapper-short" - }, - "lang": "go", - "nodes": [ - { - "content": "// Wrapper wraps an error with a bunch of\n// other errors.\n// ex. Wrapper(original) #=\u003e ErrorC -\u003e ErrorB -\u003e ErrorA -\u003e original\nfunc Wrapper(original error) error {\n\toriginal = ErrorA{original}\n\toriginal = ErrorB{original}\n\toriginal = ErrorC{original}\n\treturn original\n}", - "file": "errors/src/wrapping-error/errors.go", - "lang": "go", - "name": "wrapper-short", - "start": 32, - "end": 43, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "errors", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.56:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "errors", - "nodes": [ - { - "text": "Wrapper", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 56, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "errors/wrapping.md", - "nodes": [ - { - "text": "Another way to do this same wrapping is to use multiline initialization and fill each error type with the next error type, as seen in ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-57" - }, - "file": "errors/wrapping.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-57" - }, - "nodes": [ - { - "text": "Listing 1.57", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-57" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ". Both of these are valid implementations of the same wrapping.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-57", - "type": "listing" - }, - "file": "errors/wrapping.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "errors", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "errors/src/wrapping-error/errors.go#wrapper-long" - }, - "lang": "go", - "nodes": [ - { - "content": "// WrapperLong wraps an error with a bunch of\n// other errors.\n// ex. WrapperLong(original) #=\u003e ErrorC -\u003e ErrorB -\u003e ErrorA -\u003e original\nfunc WrapperLong(original error) error {\n\treturn ErrorC{\n\t\terr: ErrorB{\n\t\t\terr: ErrorA{\n\t\t\t\terr: original,\n\t\t\t},\n\t\t},\n\t}\n}", - "file": "errors/src/wrapping-error/errors.go", - "lang": "go", - "name": "wrapper-long", - "start": 45, - "end": 59, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "errors", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.57:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "errors", - "nodes": [ - { - "text": "Wrapper", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 57, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "errors/wrapping.md", - "level": 2, - "nodes": [ - { - "text": "Unwrapping Errors", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "errors/wrapping.md", - "nodes": [ - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "errors#Unwrap", - "href": "https://pkg.go.dev/errors#Unwrap", - "target": "_blank" - }, - "file": "errors/wrapping.md", - "nodes": [ - { - "atom": "code", - "file": "errors/wrapping.md", - "nodes": [ - { - "text": "errors.Unwrap", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/errors#Unwrap" - } - ], - { - "text": " function, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-58" - }, - "file": "errors/wrapping.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-58" - }, - "nodes": [ - { - "text": "Listing 1.58", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-58" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", can be used to unwrap an error until it reaches the original error. This will continue to peel the wrapped layers until it, hopefully, reaches the original error.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-58", - "type": "listing" - }, - "file": "errors/wrapping.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "doc", - "errors.Unwrap" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "doc": "errors.Unwrap", - "exec": "go doc errors.Unwrap" - }, - "expected_exit": 0, - "file": "errors", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc errors.Unwrap\n\npackage errors // import \u0026#34;errors\u0026#34;\n\nfunc Unwrap(err error) error\n Unwrap returns the result of calling the Unwrap method on err, if err\u0026#39;s type\n contains an Unwrap method returning error. Otherwise, Unwrap returns nil.\n\n Unwrap only calls a method of the form \u0026#34;Unwrap() error\u0026#34;. In particular\n Unwrap does not unwrap errors returned by Join.", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "errors.Unwrap" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBlcnJvcnMgLy8gaW1wb3J0ICJlcnJvcnMiCgpmdW5jIFVud3JhcChlcnIgZXJyb3IpIGVycm9yCiAgICBVbndyYXAgcmV0dXJucyB0aGUgcmVzdWx0IG9mIGNhbGxpbmcgdGhlIFVud3JhcCBtZXRob2Qgb24gZXJyLCBpZiBlcnIncyB0eXBlCiAgICBjb250YWlucyBhbiBVbndyYXAgbWV0aG9kIHJldHVybmluZyBlcnJvci4gT3RoZXJ3aXNlLCBVbndyYXAgcmV0dXJucyBuaWwuCgogICAgVW53cmFwIG9ubHkgY2FsbHMgYSBtZXRob2Qgb2YgdGhlIGZvcm0gIlVud3JhcCgpIGVycm9yIi4gSW4gcGFydGljdWxhcgogICAgVW53cmFwIGRvZXMgbm90IHVud3JhcCBlcnJvcnMgcmV0dXJuZWQgYnkgSm9pbi4=", - "duration": 2083229667, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc errors.Unwrap\n\npackage errors // import \u0026#34;errors\u0026#34;\n\nfunc Unwrap(err error) error\n Unwrap returns the result of calling the Unwrap method on err, if err\u0026#39;s type\n contains an Unwrap method returning error. Otherwise, Unwrap returns nil.\n\n Unwrap only calls a method of the form \u0026#34;Unwrap() error\u0026#34;. In particular\n Unwrap does not unwrap errors returned by Join.", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "errors.Unwrap" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBlcnJvcnMgLy8gaW1wb3J0ICJlcnJvcnMiCgpmdW5jIFVud3JhcChlcnIgZXJyb3IpIGVycm9yCiAgICBVbndyYXAgcmV0dXJucyB0aGUgcmVzdWx0IG9mIGNhbGxpbmcgdGhlIFVud3JhcCBtZXRob2Qgb24gZXJyLCBpZiBlcnIncyB0eXBlCiAgICBjb250YWlucyBhbiBVbndyYXAgbWV0aG9kIHJldHVybmluZyBlcnJvci4gT3RoZXJ3aXNlLCBVbndyYXAgcmV0dXJucyBuaWwuCgogICAgVW53cmFwIG9ubHkgY2FsbHMgYSBtZXRob2Qgb2YgdGhlIGZvcm0gIlVud3JhcCgpIGVycm9yIi4gSW4gcGFydGljdWxhcgogICAgVW53cmFwIGRvZXMgbm90IHVud3JhcCBlcnJvcnMgcmV0dXJuZWQgYnkgSm9pbi4=", - "duration": 2083229667, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "errors", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.58:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "errors#Unwrap", - "href": "https://pkg.go.dev/errors#Unwrap", - "target": "_blank" - }, - "file": "errors", - "nodes": [ - [ - { - "atom": "code", - "file": "errors", - "nodes": [ - { - "text": "errors.Unwrap", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/errors#Unwrap" - } - ], - { - "text": " function.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 58, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "errors/wrapping.md", - "nodes": [ - { - "text": "In ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-59" - }, - "file": "errors/wrapping.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-59" - }, - "nodes": [ - { - "text": "Listing 1.59", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-59" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": " the test has been updated to use the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "errors#Unwrap", - "href": "https://pkg.go.dev/errors#Unwrap", - "target": "_blank" - }, - "file": "errors/wrapping.md", - "nodes": [ - { - "atom": "code", - "file": "errors/wrapping.md", - "nodes": [ - { - "text": "errors.Unwrap", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/errors#Unwrap" - } - ], - { - "text": " function to unwrap the error until it reaches the original error. Unfortunately, however, the test will fail because the result of ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "errors/wrapping.md", - "nodes": [ - { - "text": "errors.Unwrap", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " is ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "errors/wrapping.md", - "nodes": [ - { - "text": "nil", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-59", - "type": "listing" - }, - "file": "errors/wrapping.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "errors", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "errors/src/wrapping-error/errors_test.go#test-unwrap" - }, - "lang": "go", - "nodes": [ - { - "content": "func Test_Unwrap(t *testing.T) {\n\tt.Parallel()\n\n\toriginal := errors.New(\"original error\")\n\twrapped := Wrapper(original)\n\n\tunwrapped := errors.Unwrap(wrapped)\n\tif unwrapped != original {\n\t\tt.Fatalf(\"expected %v, got %v\", original, unwrapped)\n\t}\n\n}", - "file": "errors/src/wrapping-error/errors_test.go", - "lang": "go", - "name": "test-unwrap", - "start": 23, - "end": 37, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "atom": "hr", - "file": "errors", - "type": "*hype.Element" - }, - [ - { - "args": [ - "go", - "test", - "-v" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go test -v", - "exit": "-1", - "src": "errors/src/wrapping-error", - "test": "-v" - }, - "expected_exit": -1, - "file": "errors", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go test -v\n\n=== RUN Test_Wrapper\n=== PAUSE Test_Wrapper\n=== RUN Test_Unwrap\n=== PAUSE Test_Unwrap\n=== CONT Test_Wrapper\n--- PASS: Test_Wrapper (0.00s)\n=== CONT Test_Unwrap\n errors_test.go:32: expected original error, got \u0026lt;nil\u0026gt;\n--- FAIL: Test_Unwrap (0.00s)\nFAIL\nexit status 1\nFAIL\tdemo\t2.278s", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "test", - "-v" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/errors/src/wrapping-error", - "err": { - "Stderr": null - }, - "exit": 1, - "stdout": "PT09IFJVTiAgIFRlc3RfV3JhcHBlcgo9PT0gUEFVU0UgVGVzdF9XcmFwcGVyCj09PSBSVU4gICBUZXN0X1Vud3JhcAo9PT0gUEFVU0UgVGVzdF9VbndyYXAKPT09IENPTlQgIFRlc3RfV3JhcHBlcgotLS0gUEFTUzogVGVzdF9XcmFwcGVyICgwLjAwcykKPT09IENPTlQgIFRlc3RfVW53cmFwCiAgICBlcnJvcnNfdGVzdC5nbzozMjogZXhwZWN0ZWQgb3JpZ2luYWwgZXJyb3IsIGdvdCA8bmlsPgotLS0gRkFJTDogVGVzdF9VbndyYXAgKDAuMDBzKQpGQUlMCmV4aXQgc3RhdHVzIDEKRkFJTAlkZW1vCTIuMjc4cw==", - "duration": 5174826458, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go test -v\n\n=== RUN Test_Wrapper\n=== PAUSE Test_Wrapper\n=== RUN Test_Unwrap\n=== PAUSE Test_Unwrap\n=== CONT Test_Wrapper\n--- PASS: Test_Wrapper (0.00s)\n=== CONT Test_Unwrap\n errors_test.go:32: expected original error, got \u0026lt;nil\u0026gt;\n--- FAIL: Test_Unwrap (0.00s)\nFAIL\nexit status 1\nFAIL\tdemo\t2.278s", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "test", - "-v" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/errors/src/wrapping-error", - "err": { - "Stderr": null - }, - "exit": 1, - "stdout": "PT09IFJVTiAgIFRlc3RfV3JhcHBlcgo9PT0gUEFVU0UgVGVzdF9XcmFwcGVyCj09PSBSVU4gICBUZXN0X1Vud3JhcAo9PT0gUEFVU0UgVGVzdF9VbndyYXAKPT09IENPTlQgIFRlc3RfV3JhcHBlcgotLS0gUEFTUzogVGVzdF9XcmFwcGVyICgwLjAwcykKPT09IENPTlQgIFRlc3RfVW53cmFwCiAgICBlcnJvcnNfdGVzdC5nbzozMjogZXhwZWN0ZWQgb3JpZ2luYWwgZXJyb3IsIGdvdCA8bmlsPgotLS0gRkFJTDogVGVzdF9VbndyYXAgKDAuMDBzKQpGQUlMCmV4aXQgc3RhdHVzIDEKRkFJTAlkZW1vCTIuMjc4cw==", - "duration": 5174826458, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "errors", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.59:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Using ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "errors#Unwrap", - "href": "https://pkg.go.dev/errors#Unwrap", - "target": "_blank" - }, - "file": "errors", - "nodes": [ - [ - { - "atom": "code", - "file": "errors", - "nodes": [ - { - "text": "errors.Unwrap", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/errors#Unwrap" - } - ], - { - "text": " to get the original error.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 59, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "errors/wrapping.md", - "level": 2, - "nodes": [ - { - "text": "Unwrapping Custom Errors", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "errors/wrapping.md", - "nodes": [ - { - "text": "As the documentation states, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-58" - }, - "file": "errors/wrapping.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-58" - }, - "nodes": [ - { - "text": "Listing 1.58", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-58" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "errors#Unwrap", - "href": "https://pkg.go.dev/errors#Unwrap", - "target": "_blank" - }, - "file": "errors/wrapping.md", - "nodes": [ - { - "atom": "code", - "file": "errors/wrapping.md", - "nodes": [ - { - "text": "errors.Unwrap", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/errors#Unwrap" - } - ], - { - "text": " returns the result of calling the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "errors/wrapping.md", - "nodes": [ - { - "text": "Unwrap", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " method on an error, if the error's type contains an ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "errors/wrapping.md", - "nodes": [ - { - "text": "Unwrap", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " method returning ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "errors/wrapping.md", - "nodes": [ - { - "text": "error", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ". Otherwise, ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "errors#Unwrap", - "href": "https://pkg.go.dev/errors#Unwrap", - "target": "_blank" - }, - "file": "errors/wrapping.md", - "nodes": [ - { - "atom": "code", - "file": "errors/wrapping.md", - "nodes": [ - { - "text": "errors.Unwrap", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/errors#Unwrap" - } - ], - { - "text": " returns ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "errors/wrapping.md", - "nodes": [ - { - "text": "nil", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "errors/wrapping.md", - "nodes": [ - { - "text": "What the documentation is trying to say is that our custom error types need to implement the interface shown in ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-60" - }, - "file": "errors/wrapping.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-60" - }, - "nodes": [ - { - "text": "Listing 1.60", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-60" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ". Unfortunately, the Go standard library does not define this interface for you, outside of the documentation.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-60", - "type": "listing" - }, - "file": "errors/wrapping.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "errors", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "errors/src/wrapped-broken/errors.go#interface" - }, - "lang": "go", - "nodes": [ - { - "content": "type Unwrapper interface {\n\tUnwrap() error\n}", - "file": "errors/src/wrapped-broken/errors.go", - "lang": "go", - "name": "interface", - "start": 8, - "end": 13, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "errors", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.60:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The missing ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "errors", - "nodes": [ - { - "text": "Unwrapper", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " interface.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 60, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "errors/wrapping.md", - "nodes": [ - { - "text": "Let's update the error types defined in ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-55" - }, - "file": "errors/wrapping.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-55" - }, - "nodes": [ - { - "text": "Listing 1.55", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-55" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": " to implement the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "errors/wrapping.md", - "nodes": [ - { - "text": "Unwrapper", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " interface. While ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-61" - }, - "file": "errors/wrapping.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-61" - }, - "nodes": [ - { - "text": "Listing 1.61", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-61" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": " only shows one implementation, all of our types will need to be made to implement the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "errors/wrapping.md", - "nodes": [ - { - "text": "Unwrapper", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " interface. The implementation of this interface needs to make sure to call ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "errors#Unwrap", - "href": "https://pkg.go.dev/errors#Unwrap", - "target": "_blank" - }, - "file": "errors/wrapping.md", - "nodes": [ - { - "atom": "code", - "file": "errors/wrapping.md", - "nodes": [ - { - "text": "errors.Unwrap", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/errors#Unwrap" - } - ], - { - "text": " on the error it is wrapping.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-61", - "type": "listing" - }, - "file": "errors/wrapping.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "errors", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "errors/src/wrapped-broken/errors.go#unwrap" - }, - "lang": "go", - "nodes": [ - { - "content": "func (e ErrorA) Unwrap() error {\n\treturn errors.Unwrap(e.err)\n}", - "file": "errors/src/wrapped-broken/errors.go", - "lang": "go", - "name": "unwrap", - "start": 24, - "end": 29, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "atom": "hr", - "file": "errors", - "type": "*hype.Element" - }, - [ - { - "args": [ - "go", - "test", - "-v" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go test -v", - "exit": "-1", - "src": "errors/src/wrapped-broken", - "test": "-v" - }, - "expected_exit": -1, - "file": "errors", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go test -v\n\n=== RUN Test_Wrapper\n=== PAUSE Test_Wrapper\n=== RUN Test_Unwrap\n=== PAUSE Test_Unwrap\n=== CONT Test_Wrapper\n--- PASS: Test_Wrapper (0.00s)\n=== CONT Test_Unwrap\n errors_test.go:32: expected original error, got \u0026lt;nil\u0026gt;\n--- FAIL: Test_Unwrap (0.00s)\nFAIL\nexit status 1\nFAIL\tdemo\t2.148s", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "test", - "-v" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/errors/src/wrapped-broken", - "err": { - "Stderr": null - }, - "exit": 1, - "stdout": "PT09IFJVTiAgIFRlc3RfV3JhcHBlcgo9PT0gUEFVU0UgVGVzdF9XcmFwcGVyCj09PSBSVU4gICBUZXN0X1Vud3JhcAo9PT0gUEFVU0UgVGVzdF9VbndyYXAKPT09IENPTlQgIFRlc3RfV3JhcHBlcgotLS0gUEFTUzogVGVzdF9XcmFwcGVyICgwLjAwcykKPT09IENPTlQgIFRlc3RfVW53cmFwCiAgICBlcnJvcnNfdGVzdC5nbzozMjogZXhwZWN0ZWQgb3JpZ2luYWwgZXJyb3IsIGdvdCA8bmlsPgotLS0gRkFJTDogVGVzdF9VbndyYXAgKDAuMDBzKQpGQUlMCmV4aXQgc3RhdHVzIDEKRkFJTAlkZW1vCTIuMTQ4cw==", - "duration": 5014927334, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go test -v\n\n=== RUN Test_Wrapper\n=== PAUSE Test_Wrapper\n=== RUN Test_Unwrap\n=== PAUSE Test_Unwrap\n=== CONT Test_Wrapper\n--- PASS: Test_Wrapper (0.00s)\n=== CONT Test_Unwrap\n errors_test.go:32: expected original error, got \u0026lt;nil\u0026gt;\n--- FAIL: Test_Unwrap (0.00s)\nFAIL\nexit status 1\nFAIL\tdemo\t2.148s", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "test", - "-v" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/errors/src/wrapped-broken", - "err": { - "Stderr": null - }, - "exit": 1, - "stdout": "PT09IFJVTiAgIFRlc3RfV3JhcHBlcgo9PT0gUEFVU0UgVGVzdF9XcmFwcGVyCj09PSBSVU4gICBUZXN0X1Vud3JhcAo9PT0gUEFVU0UgVGVzdF9VbndyYXAKPT09IENPTlQgIFRlc3RfV3JhcHBlcgotLS0gUEFTUzogVGVzdF9XcmFwcGVyICgwLjAwcykKPT09IENPTlQgIFRlc3RfVW53cmFwCiAgICBlcnJvcnNfdGVzdC5nbzozMjogZXhwZWN0ZWQgb3JpZ2luYWwgZXJyb3IsIGdvdCA8bmlsPgotLS0gRkFJTDogVGVzdF9VbndyYXAgKDAuMDBzKQpGQUlMCmV4aXQgc3RhdHVzIDEKRkFJTAlkZW1vCTIuMTQ4cw==", - "duration": 5014927334, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "errors", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.61:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Implementing the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "errors", - "nodes": [ - { - "text": "Unwrapper", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " interface.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 61, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "errors/wrapping.md", - "nodes": [ - { - "text": "The tests in ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-61" - }, - "file": "errors/wrapping.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-61" - }, - "nodes": [ - { - "text": "Listing 1.61", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-61" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", however, are still failing. If the error we are wrapping does not contain an ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "errors/wrapping.md", - "nodes": [ - { - "text": "Unwrap", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " method, the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "errors#Unwrap", - "href": "https://pkg.go.dev/errors#Unwrap", - "target": "_blank" - }, - "file": "errors/wrapping.md", - "nodes": [ - { - "atom": "code", - "file": "errors/wrapping.md", - "nodes": [ - { - "text": "errors.Unwrap", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/errors#Unwrap" - } - ], - { - "text": " function will return ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "errors/wrapping.md", - "nodes": [ - { - "text": "nil", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " and we won't be able to get access to the original error.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "errors/wrapping.md", - "nodes": [ - { - "text": "To fix this we need to check the error we are wrapping for the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "errors/wrapping.md", - "nodes": [ - { - "text": "Unwrapper", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " interface. If it does, we can call ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "errors#Unwrap", - "href": "https://pkg.go.dev/errors#Unwrap", - "target": "_blank" - }, - "file": "errors/wrapping.md", - "nodes": [ - { - "atom": "code", - "file": "errors/wrapping.md", - "nodes": [ - { - "text": "errors.Unwrap", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/errors#Unwrap" - } - ], - { - "text": " with the error. If it does not exist, we can return the error as is.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-62", - "type": "listing" - }, - "file": "errors/wrapping.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "errors", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "errors/src/wrapped/errors.go#unwrap" - }, - "lang": "go", - "nodes": [ - { - "content": "func (e ErrorA) Unwrap() error {\n\tif _, ok := e.err.(Unwrapper); ok {\n\t\treturn errors.Unwrap(e.err)\n\t}\n\n\treturn e.err\n}", - "file": "errors/src/wrapped/errors.go", - "lang": "go", - "name": "unwrap", - "start": 24, - "end": 33, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "test", - "-v" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go test -v", - "src": "errors/src/wrapped", - "test": "-v" - }, - "expected_exit": 0, - "file": "errors", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go test -v\n\n=== RUN Test_Wrapper\n=== PAUSE Test_Wrapper\n=== RUN Test_Unwrap\n=== PAUSE Test_Unwrap\n=== CONT Test_Wrapper\n=== CONT Test_Unwrap\n--- PASS: Test_Wrapper (0.00s)\n--- PASS: Test_Unwrap (0.00s)\nPASS\nok \tdemo\t2.072s", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "test", - "-v" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/errors/src/wrapped", - "stdout": "PT09IFJVTiAgIFRlc3RfV3JhcHBlcgo9PT0gUEFVU0UgVGVzdF9XcmFwcGVyCj09PSBSVU4gICBUZXN0X1Vud3JhcAo9PT0gUEFVU0UgVGVzdF9VbndyYXAKPT09IENPTlQgIFRlc3RfV3JhcHBlcgo9PT0gQ09OVCAgVGVzdF9VbndyYXAKLS0tIFBBU1M6IFRlc3RfV3JhcHBlciAoMC4wMHMpCi0tLSBQQVNTOiBUZXN0X1Vud3JhcCAoMC4wMHMpClBBU1MKb2sgIAlkZW1vCTIuMDcycw==", - "duration": 4937172917, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go test -v\n\n=== RUN Test_Wrapper\n=== PAUSE Test_Wrapper\n=== RUN Test_Unwrap\n=== PAUSE Test_Unwrap\n=== CONT Test_Wrapper\n=== CONT Test_Unwrap\n--- PASS: Test_Wrapper (0.00s)\n--- PASS: Test_Unwrap (0.00s)\nPASS\nok \tdemo\t2.072s", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "test", - "-v" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/errors/src/wrapped", - "stdout": "PT09IFJVTiAgIFRlc3RfV3JhcHBlcgo9PT0gUEFVU0UgVGVzdF9XcmFwcGVyCj09PSBSVU4gICBUZXN0X1Vud3JhcAo9PT0gUEFVU0UgVGVzdF9VbndyYXAKPT09IENPTlQgIFRlc3RfV3JhcHBlcgo9PT0gQ09OVCAgVGVzdF9VbndyYXAKLS0tIFBBU1M6IFRlc3RfV3JhcHBlciAoMC4wMHMpCi0tLSBQQVNTOiBUZXN0X1Vud3JhcCAoMC4wMHMpClBBU1MKb2sgIAlkZW1vCTIuMDcycw==", - "duration": 4937172917, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "errors", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.62:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Properly implementing the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "errors", - "nodes": [ - { - "text": "Unwrap", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " method.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 62, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "errors/wrapping.md", - "nodes": [ - { - "text": "Now that we understand ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "errors#Unwrap", - "href": "https://pkg.go.dev/errors#Unwrap", - "target": "_blank" - }, - "file": "errors/wrapping.md", - "nodes": [ - { - "atom": "code", - "file": "errors/wrapping.md", - "nodes": [ - { - "text": "errors.Unwrap", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/errors#Unwrap" - } - ], - { - "text": ", we can fix the test in ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-54" - }, - "file": "errors/wrapping.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-54" - }, - "nodes": [ - { - "text": "Listing 1.54", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-54" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": " to get the original error.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-63", - "type": "listing" - }, - "file": "errors/wrapping.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "errors", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "errors/src/wrapped-fixed/store_test.go#test" - }, - "lang": "go", - "nodes": [ - { - "content": "func Test_Store_All_NoTable(t *testing.T) {\n\tt.Parallel()\n\n\ts := \u0026Store{\n\t\tdata: map[string][]Model{},\n\t}\n\n\t_, err := s.All(\"users\")\n\tif err == nil {\n\t\tt.Fatal(\"expected error, got nil\")\n\t}\n\n\t// unwrap the error\n\terr = errors.Unwrap(err)\n\n\texp := \"users\"\n\te, ok := err.(ErrTableNotFound)\n\tif !ok {\n\t\tt.Fatalf(\"expected ErrTableNotFound, got %T\", err)\n\t}\n\n\tact := e.Table\n\tif act != exp {\n\t\tt.Fatalf(\"expected %q, got %q\", exp, act)\n\t}\n\n\tif e.OccurredAt.IsZero() {\n\t\tt.Fatal(\"expected non-zero time\")\n\t}\n}", - "file": "errors/src/wrapped-fixed/store_test.go", - "lang": "go", - "name": "test", - "start": 8, - "end": 40, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "atom": "hr", - "file": "errors", - "type": "*hype.Element" - }, - [ - { - "args": [ - "go", - "test", - "-v" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go test -v", - "src": "errors/src/wrapped-fixed", - "test": "-v" - }, - "expected_exit": 0, - "file": "errors", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go test -v\n\n=== RUN Test_Store_All_NoTable\n=== PAUSE Test_Store_All_NoTable\n=== CONT Test_Store_All_NoTable\n--- PASS: Test_Store_All_NoTable (0.00s)\nPASS\nok \tdemo\t1.993s", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "test", - "-v" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/errors/src/wrapped-fixed", - "stdout": "PT09IFJVTiAgIFRlc3RfU3RvcmVfQWxsX05vVGFibGUKPT09IFBBVVNFIFRlc3RfU3RvcmVfQWxsX05vVGFibGUKPT09IENPTlQgIFRlc3RfU3RvcmVfQWxsX05vVGFibGUKLS0tIFBBU1M6IFRlc3RfU3RvcmVfQWxsX05vVGFibGUgKDAuMDBzKQpQQVNTCm9rICAJZGVtbwkxLjk5M3M=", - "duration": 4855782250, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go test -v\n\n=== RUN Test_Store_All_NoTable\n=== PAUSE Test_Store_All_NoTable\n=== CONT Test_Store_All_NoTable\n--- PASS: Test_Store_All_NoTable (0.00s)\nPASS\nok \tdemo\t1.993s", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "test", - "-v" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/errors/src/wrapped-fixed", - "stdout": "PT09IFJVTiAgIFRlc3RfU3RvcmVfQWxsX05vVGFibGUKPT09IFBBVVNFIFRlc3RfU3RvcmVfQWxsX05vVGFibGUKPT09IENPTlQgIFRlc3RfU3RvcmVfQWxsX05vVGFibGUKLS0tIFBBU1M6IFRlc3RfU3RvcmVfQWxsX05vVGFibGUgKDAuMDBzKQpQQVNTCm9rICAJZGVtbwkxLjk5M3M=", - "duration": 4855782250, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "errors", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.63:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "errors", - "nodes": [ - { - "text": "WrappedError", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " type.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 63, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "errors/wrapping.md", - "level": 2, - "nodes": [ - { - "text": "To Wrap Or Not to Wrap", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "errors/wrapping.md", - "nodes": [ - { - "text": "We saw that you can use the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "fmt#Errorf", - "href": "https://pkg.go.dev/fmt#Errorf", - "target": "_blank" - }, - "file": "errors/wrapping.md", - "nodes": [ - { - "atom": "code", - "file": "errors/wrapping.md", - "nodes": [ - { - "text": "fmt.Errorf", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/fmt#Errorf" - } - ], - { - "text": " with the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "errors/wrapping.md", - "nodes": [ - { - "text": "%w", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " verb to wrap an error. This will allow for the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "errors/wrapping.md", - "nodes": [ - { - "text": "unwrapping", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " of an error later, either from the caller of your function/method or in a test.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "errors/wrapping.md", - "nodes": [ - { - "text": "While the normal rule is to always wrap the errors with the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "errors/wrapping.md", - "nodes": [ - { - "text": "%w", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ", there are exceptions. If you don't want some internal information or package specific information to not be wrapped, then it is ok to use the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "errors/wrapping.md", - "nodes": [ - { - "text": "%s", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " verb to hide any implementation details. Keep in mind, this is normally the exception and not the rule.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "errors/wrapping.md", - "nodes": [ - { - "text": "If in doubt, it is usually safer to wrap the error so that other code that calls your package can check for specific errors later.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "title": "Wrapping and Unwrapping Errors", - "type": "*hype.Page" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "type": "*hype.Include" - } - ], - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "include", - "attributes": { - "src": "errors/as_is.md" - }, - "dir": "errors", - "file": "module.md", - "nodes": [ - [ - { - "atom": "page", - "file": "errors/as_is.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "h1", - "file": "errors/as_is.md", - "level": 1, - "nodes": [ - { - "text": "Errors As/Is", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "errors/as_is.md", - "nodes": [ - { - "text": "While unwrapping an error allows us to get to the original, underlying error, it does not allow us to get access to any of the other errors that it might have been wrapped with. Consider ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-64" - }, - "file": "errors/as_is.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-64" - }, - "nodes": [ - { - "text": "Listing 1.64", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-64" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ". When we unwrap the error returned from the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "errors/as_is.md", - "nodes": [ - { - "text": "Wrapper", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function we can get access to the original error passed in, but how do we check if the wrapped error has ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "errors/as_is.md", - "nodes": [ - { - "text": "ErrorB", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " in its stack and how do we get access to the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "errors/as_is.md", - "nodes": [ - { - "text": "ErrorA", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " error? The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "errors", - "href": "https://pkg.go.dev/errors", - "target": "_blank" - }, - "file": "errors/as_is.md", - "nodes": [ - { - "atom": "code", - "file": "errors/as_is.md", - "nodes": [ - { - "text": "errors", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/errors" - } - ], - { - "text": " package provides two functions, ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "errors#Is", - "href": "https://pkg.go.dev/errors#Is", - "target": "_blank" - }, - "file": "errors/as_is.md", - "nodes": [ - { - "atom": "code", - "file": "errors/as_is.md", - "nodes": [ - { - "text": "errors.Is", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/errors#Is" - } - ], - { - "text": " and ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "errors#As", - "href": "https://pkg.go.dev/errors#As", - "target": "_blank" - }, - "file": "errors/as_is.md", - "nodes": [ - { - "atom": "code", - "file": "errors/as_is.md", - "nodes": [ - { - "text": "errors.As", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/errors#As" - } - ], - { - "text": ", that will help us with these questions.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-64", - "type": "listing" - }, - "file": "errors/as_is.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "errors", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "errors/src/wrapping-error/errors.go#wrapper-short" - }, - "lang": "go", - "nodes": [ - { - "content": "// Wrapper wraps an error with a bunch of\n// other errors.\n// ex. Wrapper(original) #=\u003e ErrorC -\u003e ErrorB -\u003e ErrorA -\u003e original\nfunc Wrapper(original error) error {\n\toriginal = ErrorA{original}\n\toriginal = ErrorB{original}\n\toriginal = ErrorC{original}\n\treturn original\n}", - "file": "errors/src/wrapping-error/errors.go", - "lang": "go", - "name": "wrapper-short", - "start": 32, - "end": 43, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "errors", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.64:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "A function that nests one error in many errors.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 64, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "errors/as_is.md", - "level": 2, - "nodes": [ - { - "text": "As", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "errors/as_is.md", - "nodes": [ - { - "text": "When working with errors, we often don't care about the underlying error, there are times, however, when we do care about the underlying error and we want to get access to it. The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "errors#As", - "href": "https://pkg.go.dev/errors#As", - "target": "_blank" - }, - "file": "errors/as_is.md", - "nodes": [ - { - "atom": "code", - "file": "errors/as_is.md", - "nodes": [ - { - "text": "errors.As", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/errors#As" - } - ], - { - "text": ", ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-65" - }, - "file": "errors/as_is.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-65" - }, - "nodes": [ - { - "text": "Listing 1.65", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-65" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", function is designed to do this. It takes an ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "builtin#error", - "href": "https://pkg.go.dev/builtin#error", - "target": "_blank" - }, - "file": "errors/as_is.md", - "nodes": [ - { - "atom": "code", - "file": "errors/as_is.md", - "nodes": [ - { - "text": "error", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/builtin#error" - } - ], - { - "text": " and a type to match against. If the error matches the type, it will return the underlying error. If the error does not match the type, it will return ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "errors/as_is.md", - "nodes": [ - { - "text": "nil", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-65", - "type": "listing" - }, - "file": "errors/as_is.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "doc", - "errors.As" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "doc": "errors.As", - "exec": "go doc errors.As" - }, - "expected_exit": 0, - "file": "errors", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc errors.As\n\npackage errors // import \u0026#34;errors\u0026#34;\n\nfunc As(err error, target any) bool\n As finds the first error in err\u0026#39;s tree that matches target, and if one\n is found, sets target to that error value and returns true. Otherwise,\n it returns false.\n\n The tree consists of err itself, followed by the errors obtained by\n repeatedly calling Unwrap. When err wraps multiple errors, As examines err\n followed by a depth-first traversal of its children.\n\n An error matches target if the error\u0026#39;s concrete value is assignable to the\n value pointed to by target, or if the error has a method As(interface{})\n bool such that As(target) returns true. In the latter case, the As method is\n responsible for setting target.\n\n An error type might provide an As method so it can be treated as if it were\n a different error type.\n\n As panics if target is not a non-nil pointer to either a type that\n implements error, or to any interface type.", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "errors.As" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBlcnJvcnMgLy8gaW1wb3J0ICJlcnJvcnMiCgpmdW5jIEFzKGVyciBlcnJvciwgdGFyZ2V0IGFueSkgYm9vbAogICAgQXMgZmluZHMgdGhlIGZpcnN0IGVycm9yIGluIGVycidzIHRyZWUgdGhhdCBtYXRjaGVzIHRhcmdldCwgYW5kIGlmIG9uZQogICAgaXMgZm91bmQsIHNldHMgdGFyZ2V0IHRvIHRoYXQgZXJyb3IgdmFsdWUgYW5kIHJldHVybnMgdHJ1ZS4gT3RoZXJ3aXNlLAogICAgaXQgcmV0dXJucyBmYWxzZS4KCiAgICBUaGUgdHJlZSBjb25zaXN0cyBvZiBlcnIgaXRzZWxmLCBmb2xsb3dlZCBieSB0aGUgZXJyb3JzIG9idGFpbmVkIGJ5CiAgICByZXBlYXRlZGx5IGNhbGxpbmcgVW53cmFwLiBXaGVuIGVyciB3cmFwcyBtdWx0aXBsZSBlcnJvcnMsIEFzIGV4YW1pbmVzIGVycgogICAgZm9sbG93ZWQgYnkgYSBkZXB0aC1maXJzdCB0cmF2ZXJzYWwgb2YgaXRzIGNoaWxkcmVuLgoKICAgIEFuIGVycm9yIG1hdGNoZXMgdGFyZ2V0IGlmIHRoZSBlcnJvcidzIGNvbmNyZXRlIHZhbHVlIGlzIGFzc2lnbmFibGUgdG8gdGhlCiAgICB2YWx1ZSBwb2ludGVkIHRvIGJ5IHRhcmdldCwgb3IgaWYgdGhlIGVycm9yIGhhcyBhIG1ldGhvZCBBcyhpbnRlcmZhY2V7fSkKICAgIGJvb2wgc3VjaCB0aGF0IEFzKHRhcmdldCkgcmV0dXJucyB0cnVlLiBJbiB0aGUgbGF0dGVyIGNhc2UsIHRoZSBBcyBtZXRob2QgaXMKICAgIHJlc3BvbnNpYmxlIGZvciBzZXR0aW5nIHRhcmdldC4KCiAgICBBbiBlcnJvciB0eXBlIG1pZ2h0IHByb3ZpZGUgYW4gQXMgbWV0aG9kIHNvIGl0IGNhbiBiZSB0cmVhdGVkIGFzIGlmIGl0IHdlcmUKICAgIGEgZGlmZmVyZW50IGVycm9yIHR5cGUuCgogICAgQXMgcGFuaWNzIGlmIHRhcmdldCBpcyBub3QgYSBub24tbmlsIHBvaW50ZXIgdG8gZWl0aGVyIGEgdHlwZSB0aGF0CiAgICBpbXBsZW1lbnRzIGVycm9yLCBvciB0byBhbnkgaW50ZXJmYWNlIHR5cGUu", - "duration": 2732899041, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc errors.As\n\npackage errors // import \u0026#34;errors\u0026#34;\n\nfunc As(err error, target any) bool\n As finds the first error in err\u0026#39;s tree that matches target, and if one\n is found, sets target to that error value and returns true. Otherwise,\n it returns false.\n\n The tree consists of err itself, followed by the errors obtained by\n repeatedly calling Unwrap. When err wraps multiple errors, As examines err\n followed by a depth-first traversal of its children.\n\n An error matches target if the error\u0026#39;s concrete value is assignable to the\n value pointed to by target, or if the error has a method As(interface{})\n bool such that As(target) returns true. In the latter case, the As method is\n responsible for setting target.\n\n An error type might provide an As method so it can be treated as if it were\n a different error type.\n\n As panics if target is not a non-nil pointer to either a type that\n implements error, or to any interface type.", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "errors.As" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBlcnJvcnMgLy8gaW1wb3J0ICJlcnJvcnMiCgpmdW5jIEFzKGVyciBlcnJvciwgdGFyZ2V0IGFueSkgYm9vbAogICAgQXMgZmluZHMgdGhlIGZpcnN0IGVycm9yIGluIGVycidzIHRyZWUgdGhhdCBtYXRjaGVzIHRhcmdldCwgYW5kIGlmIG9uZQogICAgaXMgZm91bmQsIHNldHMgdGFyZ2V0IHRvIHRoYXQgZXJyb3IgdmFsdWUgYW5kIHJldHVybnMgdHJ1ZS4gT3RoZXJ3aXNlLAogICAgaXQgcmV0dXJucyBmYWxzZS4KCiAgICBUaGUgdHJlZSBjb25zaXN0cyBvZiBlcnIgaXRzZWxmLCBmb2xsb3dlZCBieSB0aGUgZXJyb3JzIG9idGFpbmVkIGJ5CiAgICByZXBlYXRlZGx5IGNhbGxpbmcgVW53cmFwLiBXaGVuIGVyciB3cmFwcyBtdWx0aXBsZSBlcnJvcnMsIEFzIGV4YW1pbmVzIGVycgogICAgZm9sbG93ZWQgYnkgYSBkZXB0aC1maXJzdCB0cmF2ZXJzYWwgb2YgaXRzIGNoaWxkcmVuLgoKICAgIEFuIGVycm9yIG1hdGNoZXMgdGFyZ2V0IGlmIHRoZSBlcnJvcidzIGNvbmNyZXRlIHZhbHVlIGlzIGFzc2lnbmFibGUgdG8gdGhlCiAgICB2YWx1ZSBwb2ludGVkIHRvIGJ5IHRhcmdldCwgb3IgaWYgdGhlIGVycm9yIGhhcyBhIG1ldGhvZCBBcyhpbnRlcmZhY2V7fSkKICAgIGJvb2wgc3VjaCB0aGF0IEFzKHRhcmdldCkgcmV0dXJucyB0cnVlLiBJbiB0aGUgbGF0dGVyIGNhc2UsIHRoZSBBcyBtZXRob2QgaXMKICAgIHJlc3BvbnNpYmxlIGZvciBzZXR0aW5nIHRhcmdldC4KCiAgICBBbiBlcnJvciB0eXBlIG1pZ2h0IHByb3ZpZGUgYW4gQXMgbWV0aG9kIHNvIGl0IGNhbiBiZSB0cmVhdGVkIGFzIGlmIGl0IHdlcmUKICAgIGEgZGlmZmVyZW50IGVycm9yIHR5cGUuCgogICAgQXMgcGFuaWNzIGlmIHRhcmdldCBpcyBub3QgYSBub24tbmlsIHBvaW50ZXIgdG8gZWl0aGVyIGEgdHlwZSB0aGF0CiAgICBpbXBsZW1lbnRzIGVycm9yLCBvciB0byBhbnkgaW50ZXJmYWNlIHR5cGUu", - "duration": 2732899041, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "errors", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.65:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "errors#As", - "href": "https://pkg.go.dev/errors#As", - "target": "_blank" - }, - "file": "errors", - "nodes": [ - [ - { - "atom": "code", - "file": "errors", - "nodes": [ - { - "text": "errors.As", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/errors#As" - } - ], - { - "text": " function.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 65, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "errors/as_is.md", - "nodes": [ - { - "text": "Like the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "errors#Unwrap", - "href": "https://pkg.go.dev/errors#Unwrap", - "target": "_blank" - }, - "file": "errors/as_is.md", - "nodes": [ - { - "atom": "code", - "file": "errors/as_is.md", - "nodes": [ - { - "text": "errors.Unwrap", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/errors#Unwrap" - } - ], - { - "text": " function, ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "errors#As", - "href": "https://pkg.go.dev/errors#As", - "target": "_blank" - }, - "file": "errors/as_is.md", - "nodes": [ - { - "atom": "code", - "file": "errors/as_is.md", - "nodes": [ - { - "text": "errors.As", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/errors#As" - } - ], - { - "text": " ", - "type": "hype.Text" - }, - { - "atom": "strong", - "file": "errors/as_is.md", - "nodes": [ - { - "text": "also", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " has a documented, but unpublished, interface, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-66" - }, - "file": "errors/as_is.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-66" - }, - "nodes": [ - { - "text": "Listing 1.66", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-66" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", that can be implemented on custom errors.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-66", - "type": "listing" - }, - "file": "errors/as_is.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "errors", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "errors/src/as/errors.go#as-interface" - }, - "lang": "go", - "nodes": [ - { - "content": "type AsError interface {\n\tAs(target any) bool\n}", - "file": "errors/src/as/errors.go", - "lang": "go", - "name": "as-interface", - "start": 15, - "end": 20, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "errors", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.66:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "errors", - "nodes": [ - { - "text": "AsError", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " interface.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 66, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "errors/as_is.md", - "nodes": [ - { - "text": "In order for the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "errors#As", - "href": "https://pkg.go.dev/errors#As", - "target": "_blank" - }, - "file": "errors/as_is.md", - "nodes": [ - { - "atom": "code", - "file": "errors/as_is.md", - "nodes": [ - { - "text": "errors.As", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/errors#As" - } - ], - { - "text": " function to work properly, we need to implement an ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "errors/as_is.md", - "nodes": [ - { - "text": "As", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " method on our error types. This method will be called when ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "errors#As", - "href": "https://pkg.go.dev/errors#As", - "target": "_blank" - }, - "file": "errors/as_is.md", - "nodes": [ - { - "atom": "code", - "file": "errors/as_is.md", - "nodes": [ - { - "text": "errors.As", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/errors#As" - } - ], - { - "text": " is called on our error. The ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "errors/as_is.md", - "nodes": [ - { - "text": "As", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " method should return ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "errors/as_is.md", - "nodes": [ - { - "text": "true", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " if the error matches the target, and ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "errors/as_is.md", - "nodes": [ - { - "text": "false", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " otherwise. If ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "errors/as_is.md", - "nodes": [ - { - "text": "false", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ", we need to call ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "errors#As", - "href": "https://pkg.go.dev/errors#As", - "target": "_blank" - }, - "file": "errors/as_is.md", - "nodes": [ - { - "atom": "code", - "file": "errors/as_is.md", - "nodes": [ - { - "text": "errors.As", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/errors#As" - } - ], - { - "text": " on our error's underlying error. If ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "errors/as_is.md", - "nodes": [ - { - "text": "true", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ", we can return ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "errors/as_is.md", - "nodes": [ - { - "text": "true", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " and set the target to the current error.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-67", - "type": "listing" - }, - "file": "errors/as_is.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "errors", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "errors/src/as/errors.go#as" - }, - "lang": "go", - "nodes": [ - { - "content": "func (e ErrorA) As(target any) bool {\n\tex, ok := target.(*ErrorA)\n\tif !ok {\n\t\t// if the target is not an ErrorA,\n\t\t// pass the underlying error up the chain\n\t\t// by calling errors.As with the underlying error\n\t\t// and the target error\n\t\treturn errors.As(e.err, target)\n\t}\n\n\t// set the target to the current error\n\t(*ex) = e\n\treturn true\n}", - "file": "errors/src/as/errors.go", - "lang": "go", - "name": "as", - "start": 64, - "end": 80, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "errors", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.67:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Implementing the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "errors", - "nodes": [ - { - "text": "AsError", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " interface.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 67, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "errors/as_is.md", - "nodes": [ - { - "text": "It is important to note that in order to set the target to the current error, we must first dereference the target pointer. This is because the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "errors/as_is.md", - "nodes": [ - { - "text": "As", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " method is responsible for setting the target to the current error. If we don't dereference the target pointer, any changes we make would be lost when the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "errors/as_is.md", - "nodes": [ - { - "text": "As", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " method returns.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "errors/as_is.md", - "nodes": [ - { - "text": "As we can see from the test we are able to take the wrapped error and extract the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "errors/as_is.md", - "nodes": [ - { - "text": "ErrorA", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " type from the error stack. The ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "errors/as_is.md", - "nodes": [ - { - "text": "As", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " method sets the value of ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "errors/as_is.md", - "nodes": [ - { - "text": "act", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " to the error in the stack and we are able to then access the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "errors/as_is.md", - "nodes": [ - { - "text": "ErrorA", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " type directly.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-68", - "type": "listing" - }, - "file": "errors/as_is.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "errors", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "errors/src/as/errors_test.go#test-as" - }, - "lang": "go", - "nodes": [ - { - "content": "func Test_As(t *testing.T) {\n\tt.Parallel()\n\n\toriginal := errors.New(\"original error\")\n\twrapped := Wrapper(original)\n\n\tact := ErrorA{}\n\n\tok := errors.As(wrapped, \u0026act)\n\tif !ok {\n\t\tt.Fatalf(\"expected %v to act as %v\", wrapped, act)\n\t}\n\n\tif act.err == nil {\n\t\tt.Fatalf(\"expected non-nil, got nil\")\n\t}\n\n}", - "file": "errors/src/as/errors_test.go", - "lang": "go", - "name": "test-as", - "start": 8, - "end": 28, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "atom": "hr", - "file": "errors", - "type": "*hype.Element" - }, - [ - { - "args": [ - "go", - "test", - "-v" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go test -v", - "src": "errors/src/as", - "test": "-v" - }, - "expected_exit": 0, - "file": "errors", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go test -v\n\n=== RUN Test_As\n=== PAUSE Test_As\n=== CONT Test_As\n--- PASS: Test_As (0.00s)\nPASS\nok \tdemo\t1.786s", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "test", - "-v" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/errors/src/as", - "stdout": "PT09IFJVTiAgIFRlc3RfQXMKPT09IFBBVVNFIFRlc3RfQXMKPT09IENPTlQgIFRlc3RfQXMKLS0tIFBBU1M6IFRlc3RfQXMgKDAuMDBzKQpQQVNTCm9rICAJZGVtbwkxLjc4NnM=", - "duration": 4617526791, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go test -v\n\n=== RUN Test_As\n=== PAUSE Test_As\n=== CONT Test_As\n--- PASS: Test_As (0.00s)\nPASS\nok \tdemo\t1.786s", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "test", - "-v" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/errors/src/as", - "stdout": "PT09IFJVTiAgIFRlc3RfQXMKPT09IFBBVVNFIFRlc3RfQXMKPT09IENPTlQgIFRlc3RfQXMKLS0tIFBBU1M6IFRlc3RfQXMgKDAuMDBzKQpQQVNTCm9rICAJZGVtbwkxLjc4NnM=", - "duration": 4617526791, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "errors", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.68:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Testing the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "errors", - "nodes": [ - { - "text": "AsError", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " implementation.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 68, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "errors/as_is.md", - "level": 2, - "nodes": [ - { - "text": "Is", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "errors/as_is.md", - "nodes": [ - { - "text": "While the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "errors#As", - "href": "https://pkg.go.dev/errors#As", - "target": "_blank" - }, - "file": "errors/as_is.md", - "nodes": [ - { - "atom": "code", - "file": "errors/as_is.md", - "nodes": [ - { - "text": "errors.As", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/errors#As" - } - ], - { - "text": " function, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-65" - }, - "file": "errors/as_is.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-65" - }, - "nodes": [ - { - "text": "Listing 1.65", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-65" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", is used to check for the type of an error, the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "errors#Is", - "href": "https://pkg.go.dev/errors#Is", - "target": "_blank" - }, - "file": "errors/as_is.md", - "nodes": [ - { - "atom": "code", - "file": "errors/as_is.md", - "nodes": [ - { - "text": "errors.Is", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/errors#Is" - } - ], - { - "text": " function, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-69" - }, - "file": "errors/as_is.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-69" - }, - "nodes": [ - { - "text": "Listing 1.69", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-69" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", is used to check if an error in the error chain matches a specific error type. This provides a quick ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "errors/as_is.md", - "nodes": [ - { - "text": "true/false", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " check for an error type.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-69", - "type": "listing" - }, - "file": "errors/as_is.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "doc", - "errors.Is" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "doc": "errors.Is", - "exec": "go doc errors.Is" - }, - "expected_exit": 0, - "file": "errors", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc errors.Is\n\npackage errors // import \u0026#34;errors\u0026#34;\n\nfunc Is(err, target error) bool\n Is reports whether any error in err\u0026#39;s tree matches target.\n\n The tree consists of err itself, followed by the errors obtained by\n repeatedly calling Unwrap. When err wraps multiple errors, Is examines err\n followed by a depth-first traversal of its children.\n\n An error is considered to match a target if it is equal to that target or if\n it implements a method Is(error) bool such that Is(target) returns true.\n\n An error type might provide an Is method so it can be treated as equivalent\n to an existing error. For example, if MyError defines\n\n func (m MyError) Is(target error) bool { return target == fs.ErrExist }\n\n then Is(MyError{}, fs.ErrExist) returns true. See syscall.Errno.Is for an\n example in the standard library. An Is method should only shallowly compare\n err and the target and not call Unwrap on either.", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "errors.Is" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBlcnJvcnMgLy8gaW1wb3J0ICJlcnJvcnMiCgpmdW5jIElzKGVyciwgdGFyZ2V0IGVycm9yKSBib29sCiAgICBJcyByZXBvcnRzIHdoZXRoZXIgYW55IGVycm9yIGluIGVycidzIHRyZWUgbWF0Y2hlcyB0YXJnZXQuCgogICAgVGhlIHRyZWUgY29uc2lzdHMgb2YgZXJyIGl0c2VsZiwgZm9sbG93ZWQgYnkgdGhlIGVycm9ycyBvYnRhaW5lZCBieQogICAgcmVwZWF0ZWRseSBjYWxsaW5nIFVud3JhcC4gV2hlbiBlcnIgd3JhcHMgbXVsdGlwbGUgZXJyb3JzLCBJcyBleGFtaW5lcyBlcnIKICAgIGZvbGxvd2VkIGJ5IGEgZGVwdGgtZmlyc3QgdHJhdmVyc2FsIG9mIGl0cyBjaGlsZHJlbi4KCiAgICBBbiBlcnJvciBpcyBjb25zaWRlcmVkIHRvIG1hdGNoIGEgdGFyZ2V0IGlmIGl0IGlzIGVxdWFsIHRvIHRoYXQgdGFyZ2V0IG9yIGlmCiAgICBpdCBpbXBsZW1lbnRzIGEgbWV0aG9kIElzKGVycm9yKSBib29sIHN1Y2ggdGhhdCBJcyh0YXJnZXQpIHJldHVybnMgdHJ1ZS4KCiAgICBBbiBlcnJvciB0eXBlIG1pZ2h0IHByb3ZpZGUgYW4gSXMgbWV0aG9kIHNvIGl0IGNhbiBiZSB0cmVhdGVkIGFzIGVxdWl2YWxlbnQKICAgIHRvIGFuIGV4aXN0aW5nIGVycm9yLiBGb3IgZXhhbXBsZSwgaWYgTXlFcnJvciBkZWZpbmVzCgogICAgICAgIGZ1bmMgKG0gTXlFcnJvcikgSXModGFyZ2V0IGVycm9yKSBib29sIHsgcmV0dXJuIHRhcmdldCA9PSBmcy5FcnJFeGlzdCB9CgogICAgdGhlbiBJcyhNeUVycm9ye30sIGZzLkVyckV4aXN0KSByZXR1cm5zIHRydWUuIFNlZSBzeXNjYWxsLkVycm5vLklzIGZvciBhbgogICAgZXhhbXBsZSBpbiB0aGUgc3RhbmRhcmQgbGlicmFyeS4gQW4gSXMgbWV0aG9kIHNob3VsZCBvbmx5IHNoYWxsb3dseSBjb21wYXJlCiAgICBlcnIgYW5kIHRoZSB0YXJnZXQgYW5kIG5vdCBjYWxsIFVud3JhcCBvbiBlaXRoZXIu", - "duration": 2613946209, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc errors.Is\n\npackage errors // import \u0026#34;errors\u0026#34;\n\nfunc Is(err, target error) bool\n Is reports whether any error in err\u0026#39;s tree matches target.\n\n The tree consists of err itself, followed by the errors obtained by\n repeatedly calling Unwrap. When err wraps multiple errors, Is examines err\n followed by a depth-first traversal of its children.\n\n An error is considered to match a target if it is equal to that target or if\n it implements a method Is(error) bool such that Is(target) returns true.\n\n An error type might provide an Is method so it can be treated as equivalent\n to an existing error. For example, if MyError defines\n\n func (m MyError) Is(target error) bool { return target == fs.ErrExist }\n\n then Is(MyError{}, fs.ErrExist) returns true. See syscall.Errno.Is for an\n example in the standard library. An Is method should only shallowly compare\n err and the target and not call Unwrap on either.", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "errors.Is" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBlcnJvcnMgLy8gaW1wb3J0ICJlcnJvcnMiCgpmdW5jIElzKGVyciwgdGFyZ2V0IGVycm9yKSBib29sCiAgICBJcyByZXBvcnRzIHdoZXRoZXIgYW55IGVycm9yIGluIGVycidzIHRyZWUgbWF0Y2hlcyB0YXJnZXQuCgogICAgVGhlIHRyZWUgY29uc2lzdHMgb2YgZXJyIGl0c2VsZiwgZm9sbG93ZWQgYnkgdGhlIGVycm9ycyBvYnRhaW5lZCBieQogICAgcmVwZWF0ZWRseSBjYWxsaW5nIFVud3JhcC4gV2hlbiBlcnIgd3JhcHMgbXVsdGlwbGUgZXJyb3JzLCBJcyBleGFtaW5lcyBlcnIKICAgIGZvbGxvd2VkIGJ5IGEgZGVwdGgtZmlyc3QgdHJhdmVyc2FsIG9mIGl0cyBjaGlsZHJlbi4KCiAgICBBbiBlcnJvciBpcyBjb25zaWRlcmVkIHRvIG1hdGNoIGEgdGFyZ2V0IGlmIGl0IGlzIGVxdWFsIHRvIHRoYXQgdGFyZ2V0IG9yIGlmCiAgICBpdCBpbXBsZW1lbnRzIGEgbWV0aG9kIElzKGVycm9yKSBib29sIHN1Y2ggdGhhdCBJcyh0YXJnZXQpIHJldHVybnMgdHJ1ZS4KCiAgICBBbiBlcnJvciB0eXBlIG1pZ2h0IHByb3ZpZGUgYW4gSXMgbWV0aG9kIHNvIGl0IGNhbiBiZSB0cmVhdGVkIGFzIGVxdWl2YWxlbnQKICAgIHRvIGFuIGV4aXN0aW5nIGVycm9yLiBGb3IgZXhhbXBsZSwgaWYgTXlFcnJvciBkZWZpbmVzCgogICAgICAgIGZ1bmMgKG0gTXlFcnJvcikgSXModGFyZ2V0IGVycm9yKSBib29sIHsgcmV0dXJuIHRhcmdldCA9PSBmcy5FcnJFeGlzdCB9CgogICAgdGhlbiBJcyhNeUVycm9ye30sIGZzLkVyckV4aXN0KSByZXR1cm5zIHRydWUuIFNlZSBzeXNjYWxsLkVycm5vLklzIGZvciBhbgogICAgZXhhbXBsZSBpbiB0aGUgc3RhbmRhcmQgbGlicmFyeS4gQW4gSXMgbWV0aG9kIHNob3VsZCBvbmx5IHNoYWxsb3dseSBjb21wYXJlCiAgICBlcnIgYW5kIHRoZSB0YXJnZXQgYW5kIG5vdCBjYWxsIFVud3JhcCBvbiBlaXRoZXIu", - "duration": 2613946209, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "errors", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.69:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "errors#Is", - "href": "https://pkg.go.dev/errors#Is", - "target": "_blank" - }, - "file": "errors", - "nodes": [ - [ - { - "atom": "code", - "file": "errors", - "nodes": [ - { - "text": "errors.Is", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/errors#Is" - } - ], - { - "text": " function.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 69, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "errors/as_is.md", - "nodes": [ - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "errors#Is", - "href": "https://pkg.go.dev/errors#Is", - "target": "_blank" - }, - "file": "errors/as_is.md", - "nodes": [ - { - "atom": "code", - "file": "errors/as_is.md", - "nodes": [ - { - "text": "errors.Is", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/errors#Is" - } - ], - { - "text": " documentation, like ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "errors#As", - "href": "https://pkg.go.dev/errors#As", - "target": "_blank" - }, - "file": "errors/as_is.md", - "nodes": [ - { - "atom": "code", - "file": "errors/as_is.md", - "nodes": [ - { - "text": "errors.As", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/errors#As" - } - ], - { - "text": " and ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "errors#Unwrap", - "href": "https://pkg.go.dev/errors#Unwrap", - "target": "_blank" - }, - "file": "errors/as_is.md", - "nodes": [ - { - "atom": "code", - "file": "errors/as_is.md", - "nodes": [ - { - "text": "errors.Unwrap", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/errors#Unwrap" - } - ], - { - "text": ", has a documented, but unpublished, interface. This interface is defined in ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-70" - }, - "file": "errors/as_is.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-70" - }, - "nodes": [ - { - "text": "Listing 1.70", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-70" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-70", - "type": "listing" - }, - "file": "errors/as_is.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "errors", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "errors/src/is/errors.go#is-interface" - }, - "lang": "go", - "nodes": [ - { - "content": "type IsError interface {\n\tIs(target error) bool\n}", - "file": "errors/src/is/errors.go", - "lang": "go", - "name": "is-interface", - "start": 22, - "end": 27, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "errors", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.70:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "errors", - "nodes": [ - { - "text": "IsError", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " interface.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 70, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "errors/as_is.md", - "nodes": [ - { - "text": "Like with ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "errors#As", - "href": "https://pkg.go.dev/errors#As", - "target": "_blank" - }, - "file": "errors/as_is.md", - "nodes": [ - { - "atom": "code", - "file": "errors/as_is.md", - "nodes": [ - { - "text": "errors.As", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/errors#As" - } - ], - { - "text": " we have to implement the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "errors/as_is.md", - "nodes": [ - { - "text": "Is", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " method for our custom error types, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-71" - }, - "file": "errors/as_is.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-71" - }, - "nodes": [ - { - "text": "Listing 1.71", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-71" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ". If our error types is the same type as the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "errors/as_is.md", - "nodes": [ - { - "text": "target", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " error then we can return ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "errors/as_is.md", - "nodes": [ - { - "text": "true", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ". If the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "errors/as_is.md", - "nodes": [ - { - "text": "target", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " error is not a much we then need to call ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "errors#Is", - "href": "https://pkg.go.dev/errors#Is", - "target": "_blank" - }, - "file": "errors/as_is.md", - "nodes": [ - { - "atom": "code", - "file": "errors/as_is.md", - "nodes": [ - { - "text": "errors.Is", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/errors#Is" - } - ], - { - "text": " with our underlying error and the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "errors/as_is.md", - "nodes": [ - { - "text": "target", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " error so that error can be checked as well.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-71", - "type": "listing" - }, - "file": "errors/as_is.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "errors", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "errors/src/is/errors.go#is" - }, - "lang": "go", - "nodes": [ - { - "content": "func (e ErrorA) Is(target error) bool {\n\tif _, ok := target.(ErrorA); ok {\n\t\t// return true if target is ErrorA\n\t\treturn true\n\t}\n\n\t// if not, pass the underlying error up the chain\n\t// by calling errors.Is with the underlying error\n\t// and the target error\n\treturn errors.Is(e.err, target)\n}", - "file": "errors/src/is/errors.go", - "lang": "go", - "name": "is", - "start": 49, - "end": 62, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "errors", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.71:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Implementing the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "errors", - "nodes": [ - { - "text": "IsError", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " interface.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 71, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "errors/as_is.md", - "nodes": [ - { - "text": "Finally, in ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-72" - }, - "file": "errors/as_is.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-72" - }, - "nodes": [ - { - "text": "Listing 1.72", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-72" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", we can write a test to assert that our ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "errors/as_is.md", - "nodes": [ - { - "text": "Is", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " method works as expected.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-72", - "type": "listing" - }, - "file": "errors/as_is.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "errors", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "errors/src/is/errors_test.go#test-is" - }, - "lang": "go", - "nodes": [ - { - "content": "func Test_Is(t *testing.T) {\n\tt.Parallel()\n\n\toriginal := errors.New(\"original error\")\n\twrapped := Wrapper(original)\n\n\texp := ErrorB{}\n\n\tok := errors.Is(wrapped, exp)\n\tif !ok {\n\t\tt.Fatalf(\"expected %v to be %v\", wrapped, exp)\n\t}\n\n}", - "file": "errors/src/is/errors_test.go", - "lang": "go", - "name": "test-is", - "start": 8, - "end": 24, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "test", - "-v" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go test -v", - "src": "errors/src/is", - "test": "-v" - }, - "expected_exit": 0, - "file": "errors", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go test -v\n\n=== RUN Test_Is\n=== PAUSE Test_Is\n=== CONT Test_Is\n--- PASS: Test_Is (0.00s)\nPASS\nok \tdemo\t1.159s", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "test", - "-v" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/errors/src/is", - "stdout": "PT09IFJVTiAgIFRlc3RfSXMKPT09IFBBVVNFIFRlc3RfSXMKPT09IENPTlQgIFRlc3RfSXMKLS0tIFBBU1M6IFRlc3RfSXMgKDAuMDBzKQpQQVNTCm9rICAJZGVtbwkxLjE1OXM=", - "duration": 3870325792, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go test -v\n\n=== RUN Test_Is\n=== PAUSE Test_Is\n=== CONT Test_Is\n--- PASS: Test_Is (0.00s)\nPASS\nok \tdemo\t1.159s", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "test", - "-v" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/errors/src/is", - "stdout": "PT09IFJVTiAgIFRlc3RfSXMKPT09IFBBVVNFIFRlc3RfSXMKPT09IENPTlQgIFRlc3RfSXMKLS0tIFBBU1M6IFRlc3RfSXMgKDAuMDBzKQpQQVNTCm9rICAJZGVtbwkxLjE1OXM=", - "duration": 3870325792, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "errors", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.72:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Testing the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "errors", - "nodes": [ - { - "text": "IsError", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " implementation.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 72, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "title": "Errors As/Is", - "type": "*hype.Page" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "type": "*hype.Include" - } - ], - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "include", - "attributes": { - "src": "errors/summary.md" - }, - "dir": "errors", - "file": "module.md", - "nodes": [ - [ - { - "atom": "page", - "file": "errors/summary.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "h1", - "file": "errors/summary.md", - "level": 1, - "nodes": [ - { - "text": "Stack Traces", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "errors/summary.md", - "nodes": [ - { - "text": "Using a stack trace to debug your code can be very helpful at times. A stack trace shows where you are at in the code, and how you got there by printing a list of all calling functions.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "errors/summary.md", - "nodes": [ - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "runtime/debug", - "href": "https://pkg.go.dev/runtime/debug", - "target": "_blank" - }, - "file": "errors/summary.md", - "nodes": [ - { - "atom": "code", - "file": "errors/summary.md", - "nodes": [ - { - "text": "runtime/debug", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/runtime/debug" - } - ], - { - "text": " package provides a couple of functions that can be use to get, or print, a stack trace. The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "runtime/debug#Stack", - "href": "https://pkg.go.dev/runtime/debug#Stack", - "target": "_blank" - }, - "file": "errors/summary.md", - "nodes": [ - { - "atom": "code", - "file": "errors/summary.md", - "nodes": [ - { - "text": "debug.Stack", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/runtime/debug#Stack" - } - ], - { - "text": " function, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-73" - }, - "file": "errors/summary.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-73" - }, - "nodes": [ - { - "text": "Listing 1.73", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-73" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", will return a slice of bytes that represent the stack trace.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-73", - "type": "listing" - }, - "file": "errors/summary.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "doc", - "runtime/debug.Stack" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "doc": "runtime/debug.Stack", - "exec": "go doc runtime/debug.Stack" - }, - "expected_exit": 0, - "file": "errors", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc runtime/debug.Stack\n\npackage debug // import \u0026#34;runtime/debug\u0026#34;\n\nfunc Stack() []byte\n Stack returns a formatted stack trace of the goroutine that calls it. It\n calls runtime.Stack with a large enough buffer to capture the entire trace.", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "runtime/debug.Stack" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBkZWJ1ZyAvLyBpbXBvcnQgInJ1bnRpbWUvZGVidWciCgpmdW5jIFN0YWNrKCkgW11ieXRlCiAgICBTdGFjayByZXR1cm5zIGEgZm9ybWF0dGVkIHN0YWNrIHRyYWNlIG9mIHRoZSBnb3JvdXRpbmUgdGhhdCBjYWxscyBpdC4gSXQKICAgIGNhbGxzIHJ1bnRpbWUuU3RhY2sgd2l0aCBhIGxhcmdlIGVub3VnaCBidWZmZXIgdG8gY2FwdHVyZSB0aGUgZW50aXJlIHRyYWNlLg==", - "duration": 2731607000, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc runtime/debug.Stack\n\npackage debug // import \u0026#34;runtime/debug\u0026#34;\n\nfunc Stack() []byte\n Stack returns a formatted stack trace of the goroutine that calls it. It\n calls runtime.Stack with a large enough buffer to capture the entire trace.", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "runtime/debug.Stack" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBkZWJ1ZyAvLyBpbXBvcnQgInJ1bnRpbWUvZGVidWciCgpmdW5jIFN0YWNrKCkgW11ieXRlCiAgICBTdGFjayByZXR1cm5zIGEgZm9ybWF0dGVkIHN0YWNrIHRyYWNlIG9mIHRoZSBnb3JvdXRpbmUgdGhhdCBjYWxscyBpdC4gSXQKICAgIGNhbGxzIHJ1bnRpbWUuU3RhY2sgd2l0aCBhIGxhcmdlIGVub3VnaCBidWZmZXIgdG8gY2FwdHVyZSB0aGUgZW50aXJlIHRyYWNlLg==", - "duration": 2731607000, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "errors", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.73:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "runtime/debug#Stack", - "href": "https://pkg.go.dev/runtime/debug#Stack", - "target": "_blank" - }, - "file": "errors", - "nodes": [ - [ - { - "atom": "code", - "file": "errors", - "nodes": [ - { - "text": "debug.Stack", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/runtime/debug#Stack" - } - ], - { - "text": " function", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 73, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "errors/summary.md", - "nodes": [ - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "runtime/debug#PrintStack", - "href": "https://pkg.go.dev/runtime/debug#PrintStack", - "target": "_blank" - }, - "file": "errors/summary.md", - "nodes": [ - { - "atom": "code", - "file": "errors/summary.md", - "nodes": [ - { - "text": "debug.PrintStack", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/runtime/debug#PrintStack" - } - ], - { - "text": " function, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-74" - }, - "file": "errors/summary.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-74" - }, - "nodes": [ - { - "text": "Listing 1.74", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-74" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", will print the stack trace to the standard output.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-74", - "type": "listing" - }, - "file": "errors/summary.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "doc", - "runtime/debug.PrintStack" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "doc": "runtime/debug.PrintStack", - "exec": "go doc runtime/debug.PrintStack" - }, - "expected_exit": 0, - "file": "errors", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc runtime/debug.PrintStack\n\npackage debug // import \u0026#34;runtime/debug\u0026#34;\n\nfunc PrintStack()\n PrintStack prints to standard error the stack trace returned by\n runtime.Stack.", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "runtime/debug.PrintStack" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBkZWJ1ZyAvLyBpbXBvcnQgInJ1bnRpbWUvZGVidWciCgpmdW5jIFByaW50U3RhY2soKQogICAgUHJpbnRTdGFjayBwcmludHMgdG8gc3RhbmRhcmQgZXJyb3IgdGhlIHN0YWNrIHRyYWNlIHJldHVybmVkIGJ5CiAgICBydW50aW1lLlN0YWNrLg==", - "duration": 2489650000, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc runtime/debug.PrintStack\n\npackage debug // import \u0026#34;runtime/debug\u0026#34;\n\nfunc PrintStack()\n PrintStack prints to standard error the stack trace returned by\n runtime.Stack.", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "runtime/debug.PrintStack" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBkZWJ1ZyAvLyBpbXBvcnQgInJ1bnRpbWUvZGVidWciCgpmdW5jIFByaW50U3RhY2soKQogICAgUHJpbnRTdGFjayBwcmludHMgdG8gc3RhbmRhcmQgZXJyb3IgdGhlIHN0YWNrIHRyYWNlIHJldHVybmVkIGJ5CiAgICBydW50aW1lLlN0YWNrLg==", - "duration": 2489650000, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "errors", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.74:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "runtime/debug#PrintStack", - "href": "https://pkg.go.dev/runtime/debug#PrintStack", - "target": "_blank" - }, - "file": "errors", - "nodes": [ - [ - { - "atom": "code", - "file": "errors", - "nodes": [ - { - "text": "debug.PrintStack", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/runtime/debug#PrintStack" - } - ], - { - "text": " function", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 74, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "errors/summary.md", - "nodes": [ - { - "text": "In ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-75" - }, - "file": "errors/summary.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-75" - }, - "nodes": [ - { - "text": "Listing 1.75", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-75" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", we print the stack trace of a program to standard output, using ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "runtime/debug#PrintStack", - "href": "https://pkg.go.dev/runtime/debug#PrintStack", - "target": "_blank" - }, - "file": "errors/summary.md", - "nodes": [ - { - "atom": "code", - "file": "errors/summary.md", - "nodes": [ - { - "text": "debug.PrintStack", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/runtime/debug#PrintStack" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-75", - "type": "listing" - }, - "file": "errors/summary.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "errors", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "errors/src/stack/main.go" - }, - "lang": "go", - "nodes": [ - { - "text": "package main\n\nimport \u0026#34;runtime/debug\u0026#34;\n\nfunc main() {\n\tFirst()\n}\n\nfunc First() {\n\tSecond()\n}\n\nfunc Second() {\n\tThird()\n}\n\nfunc Third() {\n\tdebug.PrintStack()\n}\n", - "type": "hype.Text" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "atom": "hr", - "file": "errors", - "type": "*hype.Element" - }, - [ - { - "args": [ - "go", - "run", - "." - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go run .", - "run": ".", - "src": "errors/src/stack" - }, - "expected_exit": 0, - "file": "errors", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\ngoroutine 1 [running]:\nruntime/debug.Stack()\n\t/usr/local/go/src/runtime/debug/stack.go:24 +0x64\nruntime/debug.PrintStack()\n\t/usr/local/go/src/runtime/debug/stack.go:16 +0x1c\nmain.Third(...)\n\t./main.go:18\nmain.Second(...)\n\t./main.go:14\nmain.First(...)\n\t./main.go:10\nmain.main()\n\t./main.go:6 +0x28", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/errors/src/stack", - "stderr": "Z29yb3V0aW5lIDEgW3J1bm5pbmddOgpydW50aW1lL2RlYnVnLlN0YWNrKCkKCS91c3IvbG9jYWwvZ28vc3JjL3J1bnRpbWUvZGVidWcvc3RhY2suZ286MjQgKzB4NjQKcnVudGltZS9kZWJ1Zy5QcmludFN0YWNrKCkKCS91c3IvbG9jYWwvZ28vc3JjL3J1bnRpbWUvZGVidWcvc3RhY2suZ286MTYgKzB4MWMKbWFpbi5UaGlyZCguLi4pCgkvVXNlcnMvbWFya2JhdGVzL0xpYnJhcnkvQ2xvdWRTdG9yYWdlL0Ryb3Bib3gvZGV2L2d1aWRlcy9jb250ZW50L2Jvb2svY2hhcHRlcnMvMDktZXJyb3JzL2Vycm9ycy9zcmMvc3RhY2svbWFpbi5nbzoxOAptYWluLlNlY29uZCguLi4pCgkvVXNlcnMvbWFya2JhdGVzL0xpYnJhcnkvQ2xvdWRTdG9yYWdlL0Ryb3Bib3gvZGV2L2d1aWRlcy9jb250ZW50L2Jvb2svY2hhcHRlcnMvMDktZXJyb3JzL2Vycm9ycy9zcmMvc3RhY2svbWFpbi5nbzoxNAptYWluLkZpcnN0KC4uLikKCS9Vc2Vycy9tYXJrYmF0ZXMvTGlicmFyeS9DbG91ZFN0b3JhZ2UvRHJvcGJveC9kZXYvZ3VpZGVzL2NvbnRlbnQvYm9vay9jaGFwdGVycy8wOS1lcnJvcnMvZXJyb3JzL3NyYy9zdGFjay9tYWluLmdvOjEwCm1haW4ubWFpbigpCgkvVXNlcnMvbWFya2JhdGVzL0xpYnJhcnkvQ2xvdWRTdG9yYWdlL0Ryb3Bib3gvZGV2L2d1aWRlcy9jb250ZW50L2Jvb2svY2hhcHRlcnMvMDktZXJyb3JzL2Vycm9ycy9zcmMvc3RhY2svbWFpbi5nbzo2ICsweDI4", - "duration": 3129546334, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\ngoroutine 1 [running]:\nruntime/debug.Stack()\n\t/usr/local/go/src/runtime/debug/stack.go:24 +0x64\nruntime/debug.PrintStack()\n\t/usr/local/go/src/runtime/debug/stack.go:16 +0x1c\nmain.Third(...)\n\t./main.go:18\nmain.Second(...)\n\t./main.go:14\nmain.First(...)\n\t./main.go:10\nmain.main()\n\t./main.go:6 +0x28", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors/errors/src/stack", - "stderr": "Z29yb3V0aW5lIDEgW3J1bm5pbmddOgpydW50aW1lL2RlYnVnLlN0YWNrKCkKCS91c3IvbG9jYWwvZ28vc3JjL3J1bnRpbWUvZGVidWcvc3RhY2suZ286MjQgKzB4NjQKcnVudGltZS9kZWJ1Zy5QcmludFN0YWNrKCkKCS91c3IvbG9jYWwvZ28vc3JjL3J1bnRpbWUvZGVidWcvc3RhY2suZ286MTYgKzB4MWMKbWFpbi5UaGlyZCguLi4pCgkvVXNlcnMvbWFya2JhdGVzL0xpYnJhcnkvQ2xvdWRTdG9yYWdlL0Ryb3Bib3gvZGV2L2d1aWRlcy9jb250ZW50L2Jvb2svY2hhcHRlcnMvMDktZXJyb3JzL2Vycm9ycy9zcmMvc3RhY2svbWFpbi5nbzoxOAptYWluLlNlY29uZCguLi4pCgkvVXNlcnMvbWFya2JhdGVzL0xpYnJhcnkvQ2xvdWRTdG9yYWdlL0Ryb3Bib3gvZGV2L2d1aWRlcy9jb250ZW50L2Jvb2svY2hhcHRlcnMvMDktZXJyb3JzL2Vycm9ycy9zcmMvc3RhY2svbWFpbi5nbzoxNAptYWluLkZpcnN0KC4uLikKCS9Vc2Vycy9tYXJrYmF0ZXMvTGlicmFyeS9DbG91ZFN0b3JhZ2UvRHJvcGJveC9kZXYvZ3VpZGVzL2NvbnRlbnQvYm9vay9jaGFwdGVycy8wOS1lcnJvcnMvZXJyb3JzL3NyYy9zdGFjay9tYWluLmdvOjEwCm1haW4ubWFpbigpCgkvVXNlcnMvbWFya2JhdGVzL0xpYnJhcnkvQ2xvdWRTdG9yYWdlL0Ryb3Bib3gvZGV2L2d1aWRlcy9jb250ZW50L2Jvb2svY2hhcHRlcnMvMDktZXJyb3JzL2Vycm9ycy9zcmMvc3RhY2svbWFpbi5nbzo2ICsweDI4", - "duration": 3129546334, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "errors", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.75:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Printing a stack trace.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 75, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "title": "Stack Traces", - "type": "*hype.Page" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "type": "*hype.Include" - } - ], - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "page", - "file": "module.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "h1", - "file": "module.md", - "level": 1, - "nodes": [ - { - "text": "Summary", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "module.md", - "nodes": [ - { - "text": "In this ", - "type": "hype.Text" - }, - { - "atom": "binding", - "attributes": { - "part": "" - }, - "file": "module.md", - "type": "*hype.Element" - }, - { - "text": " we discussed Go's error handling in depth. We covered error handling, and creation, in our code. We learned how to create custom implementations of ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "builtin#error", - "href": "https://pkg.go.dev/builtin#error", - "target": "_blank" - }, - "file": "module.md", - "nodes": [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "error", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/builtin#error" - } - ], - { - "text": " interface. Next, we saw how a panic can crash an application, and we discussed various ways to recover from panics. We saw that we can use ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "errors#Unwrap", - "href": "https://pkg.go.dev/errors#Unwrap", - "target": "_blank" - }, - "file": "module.md", - "nodes": [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "errors.Unwrap", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/errors#Unwrap" - } - ], - { - "text": " to try and get the original error from a wrapped error. We also saw how to use ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "errors#As", - "href": "https://pkg.go.dev/errors#As", - "target": "_blank" - }, - "file": "module.md", - "nodes": [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "errors.As", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/errors#As" - } - ], - { - "text": " to try assert an error has a certain type in its chain, and if so, it binds the error to a variable to be used in the rest of the function. Finally, we saw how to use ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "errors#Is", - "href": "https://pkg.go.dev/errors#Is", - "target": "_blank" - }, - "file": "module.md", - "nodes": [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "errors.Is", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/errors#Is" - } - ], - { - "text": " to check if an error in the chain is of a certain type.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "title": "Summary", - "type": "*hype.Page" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "type": "*hype.Body" - } - ] - ], - "type": "*hype.Element" - } - ], - "type": "*hype.Element" - } - ], - "parser": { - "type": "*hype.Parser", - "root": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors", - "section": 1, - "snippets": {} - }, - "root": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/09-errors", - "section_id": 1, - "snippets": {}, - "title": "Errors", - "type": "*hype.Document", - "filename": "module.md" -} \ No newline at end of file diff --git a/src/testdata/errors/post_parse.json b/src/testdata/errors/post_parse.json new file mode 100644 index 0000000..2d1140d --- /dev/null +++ b/src/testdata/errors/post_parse.json @@ -0,0 +1,8 @@ +{ + "error": "error post parsing", + "filename": "module.md", + "orig_error": "original error", + "postparser": "\u003cnil\u003e", + "root": "testdata/whole/simple", + "type": "hype.PostParseError" +} \ No newline at end of file diff --git a/src/testdata/files.json b/src/testdata/files.json deleted file mode 100644 index 9a0398e..0000000 --- a/src/testdata/files.json +++ /dev/null @@ -1,26139 +0,0 @@ -{ - "nodes": [ - { - "file": "module.md", - "nodes": [ - { - "atom": "html", - "file": "module.md", - "nodes": [ - { - "atom": "head", - "file": "module.md", - "type": "*hype.Element" - }, - [ - { - "atom": "body", - "file": "module.md", - "nodes": [ - [ - { - "atom": "page", - "file": "module.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "h1", - "file": "module.md", - "level": 1, - "nodes": [ - { - "text": "Working With Files", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "module.md", - "nodes": [ - { - "text": "Working with files is a very common task in computer programming. We work with log files, HTML files, and a whole host of other file types in our programs. In this ", - "type": "hype.Text" - }, - { - "atom": "binding", - "attributes": { - "part": "" - }, - "file": "module.md", - "type": "*hype.Element" - }, - { - "text": " we will learn how to read and write files, walk directories, use the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "fs", - "href": "https://pkg.go.dev/fs", - "target": "_blank" - }, - "file": "module.md", - "nodes": [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "fs", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/fs" - } - ], - { - "text": " package, and finally, learn how we can embed files into our Go binaries creating a truly self-contained application.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "title": "Working With Files", - "type": "*hype.Page" - } - ], - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "include", - "attributes": { - "src": "dirs/dirs.md" - }, - "dir": "dirs", - "file": "module.md", - "nodes": [ - [ - { - "atom": "page", - "file": "dirs.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "h1", - "file": "dirs.md", - "level": 1, - "nodes": [ - { - "text": "Directory Entries and File Information", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "dirs.md", - "nodes": [ - { - "text": "Before we can begin using files for our programs, we need to, first, understand the basics of how files work in Go.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "dirs.md", - "nodes": [ - { - "text": "Consider the following file tree. We will be using this file tree to aid in our understanding of files in Go. This tree contains ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "dirs.md", - "nodes": [ - { - "text": ".txt", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " files, as well as, special directories, ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "dirs.md", - "nodes": [ - { - "text": "testdata", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ", ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "dirs.md", - "nodes": [ - { - "text": "_ignore", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ", and ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "dirs.md", - "nodes": [ - { - "text": ".hidden", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ". We will cover the importance of these files, and directories, as we progress.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-1", - "type": "listing" - }, - "file": "dirs.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "tree", - "-a" - ], - "atom": "cmd", - "attributes": { - "exec": "tree -a", - "src": "dirs/src/tree/data" - }, - "expected_exit": 0, - "file": "dirs", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ tree -a\n\n.\n├── .hidden\n│   └── d.txt\n├── a.txt\n├── b.txt\n├── e\n│   ├── f\n│   │   ├── _ignore\n│   │   │   └── i.txt\n│   │   ├── g.txt\n│   │   └── h.txt\n│   └── j.txt\n└── testdata\n └── c.txt\n\n6 directories, 8 files", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "tree", - "-a" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/14-files/dirs/src/tree/data", - "stdout": "LgrilJzilIDilIAgLmhpZGRlbgrilILCoMKgIOKUlOKUgOKUgCBkLnR4dArilJzilIDilIAgYS50eHQK4pSc4pSA4pSAIGIudHh0CuKUnOKUgOKUgCBlCuKUgsKgwqAg4pSc4pSA4pSAIGYK4pSCwqDCoCDilILCoMKgIOKUnOKUgOKUgCBfaWdub3JlCuKUgsKgwqAg4pSCwqDCoCDilILCoMKgIOKUlOKUgOKUgCBpLnR4dArilILCoMKgIOKUgsKgwqAg4pSc4pSA4pSAIGcudHh0CuKUgsKgwqAg4pSCwqDCoCDilJTilIDilIAgaC50eHQK4pSCwqDCoCDilJTilIDilIAgai50eHQK4pSU4pSA4pSAIHRlc3RkYXRhCiAgICDilJTilIDilIAgYy50eHQKCjYgZGlyZWN0b3JpZXMsIDggZmlsZXM=", - "duration": 583889042, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ tree -a\n\n.\n├── .hidden\n│   └── d.txt\n├── a.txt\n├── b.txt\n├── e\n│   ├── f\n│   │   ├── _ignore\n│   │   │   └── i.txt\n│   │   ├── g.txt\n│   │   └── h.txt\n│   └── j.txt\n└── testdata\n └── c.txt\n\n6 directories, 8 files", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "tree", - "-a" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/14-files/dirs/src/tree/data", - "stdout": "LgrilJzilIDilIAgLmhpZGRlbgrilILCoMKgIOKUlOKUgOKUgCBkLnR4dArilJzilIDilIAgYS50eHQK4pSc4pSA4pSAIGIudHh0CuKUnOKUgOKUgCBlCuKUgsKgwqAg4pSc4pSA4pSAIGYK4pSCwqDCoCDilILCoMKgIOKUnOKUgOKUgCBfaWdub3JlCuKUgsKgwqAg4pSCwqDCoCDilILCoMKgIOKUlOKUgOKUgCBpLnR4dArilILCoMKgIOKUgsKgwqAg4pSc4pSA4pSAIGcudHh0CuKUgsKgwqAg4pSCwqDCoCDilJTilIDilIAgaC50eHQK4pSCwqDCoCDilJTilIDilIAgai50eHQK4pSU4pSA4pSAIHRlc3RkYXRhCiAgICDilJTilIDilIAgYy50eHQKCjYgZGlyZWN0b3JpZXMsIDggZmlsZXM=", - "duration": 583889042, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "dirs", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.1:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "File tree containing special folders; ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "dirs", - "nodes": [ - { - "text": ".hidden", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ", ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "dirs", - "nodes": [ - { - "text": "_ignore", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ", and ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "dirs", - "nodes": [ - { - "text": "testdata", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 1, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "dirs.md", - "level": 2, - "nodes": [ - { - "text": "Reading a Directory", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "dirs.md", - "nodes": [ - { - "text": "In order to know which files we can work with, we need to know which files are in a directory. To do this we can use the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "os#ReadDir", - "href": "https://pkg.go.dev/os#ReadDir", - "target": "_blank" - }, - "file": "dirs.md", - "nodes": [ - { - "atom": "code", - "file": "dirs.md", - "nodes": [ - { - "text": "os.ReadDir", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/os#ReadDir" - } - ], - { - "text": " function, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-2" - }, - "file": "dirs.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-2" - }, - "nodes": [ - { - "text": "Listing 1.2", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-2" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-2", - "type": "listing" - }, - "file": "dirs.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "doc", - "os.ReadDir" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "doc": "os.ReadDir", - "exec": "go doc os.ReadDir" - }, - "expected_exit": 0, - "file": "dirs", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc os.ReadDir\n\npackage os // import \u0026#34;os\u0026#34;\n\nfunc ReadDir(name string) ([]DirEntry, error)\n ReadDir reads the named directory, returning all its directory entries\n sorted by filename. If an error occurs reading the directory, ReadDir\n returns the entries it was able to read before the error, along with the\n error.", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "os.ReadDir" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBvcyAvLyBpbXBvcnQgIm9zIgoKZnVuYyBSZWFkRGlyKG5hbWUgc3RyaW5nKSAoW11EaXJFbnRyeSwgZXJyb3IpCiAgICBSZWFkRGlyIHJlYWRzIHRoZSBuYW1lZCBkaXJlY3RvcnksIHJldHVybmluZyBhbGwgaXRzIGRpcmVjdG9yeSBlbnRyaWVzCiAgICBzb3J0ZWQgYnkgZmlsZW5hbWUuIElmIGFuIGVycm9yIG9jY3VycyByZWFkaW5nIHRoZSBkaXJlY3RvcnksIFJlYWREaXIKICAgIHJldHVybnMgdGhlIGVudHJpZXMgaXQgd2FzIGFibGUgdG8gcmVhZCBiZWZvcmUgdGhlIGVycm9yLCBhbG9uZyB3aXRoIHRoZQogICAgZXJyb3Iu", - "duration": 979215916, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc os.ReadDir\n\npackage os // import \u0026#34;os\u0026#34;\n\nfunc ReadDir(name string) ([]DirEntry, error)\n ReadDir reads the named directory, returning all its directory entries\n sorted by filename. If an error occurs reading the directory, ReadDir\n returns the entries it was able to read before the error, along with the\n error.", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "os.ReadDir" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBvcyAvLyBpbXBvcnQgIm9zIgoKZnVuYyBSZWFkRGlyKG5hbWUgc3RyaW5nKSAoW11EaXJFbnRyeSwgZXJyb3IpCiAgICBSZWFkRGlyIHJlYWRzIHRoZSBuYW1lZCBkaXJlY3RvcnksIHJldHVybmluZyBhbGwgaXRzIGRpcmVjdG9yeSBlbnRyaWVzCiAgICBzb3J0ZWQgYnkgZmlsZW5hbWUuIElmIGFuIGVycm9yIG9jY3VycyByZWFkaW5nIHRoZSBkaXJlY3RvcnksIFJlYWREaXIKICAgIHJldHVybnMgdGhlIGVudHJpZXMgaXQgd2FzIGFibGUgdG8gcmVhZCBiZWZvcmUgdGhlIGVycm9yLCBhbG9uZyB3aXRoIHRoZQogICAgZXJyb3Iu", - "duration": 979215916, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "dirs", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.2:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "os#ReadDir", - "href": "https://pkg.go.dev/os#ReadDir", - "target": "_blank" - }, - "file": "dirs", - "nodes": [ - [ - { - "atom": "code", - "file": "dirs", - "nodes": [ - { - "text": "os.ReadDir", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/os#ReadDir" - } - ], - { - "text": " function.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 2, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "dirs.md", - "nodes": [ - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "os#ReadDir", - "href": "https://pkg.go.dev/os#ReadDir", - "target": "_blank" - }, - "file": "dirs.md", - "nodes": [ - { - "atom": "code", - "file": "dirs.md", - "nodes": [ - { - "text": "os.ReadDir", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/os#ReadDir" - } - ], - { - "text": " function takes a path as a parameter, and returns a slice of ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "os#DirEntry", - "href": "https://pkg.go.dev/os#DirEntry", - "target": "_blank" - }, - "file": "dirs.md", - "nodes": [ - { - "atom": "code", - "file": "dirs.md", - "nodes": [ - { - "text": "os.DirEntry", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/os#DirEntry" - } - ], - { - "text": " values, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-3" - }, - "file": "dirs.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-3" - }, - "nodes": [ - { - "text": "Listing 1.3", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-3" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ". Each ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "os#DirEntry", - "href": "https://pkg.go.dev/os#DirEntry", - "target": "_blank" - }, - "file": "dirs.md", - "nodes": [ - { - "atom": "code", - "file": "dirs.md", - "nodes": [ - { - "text": "os.DirEntry", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/os#DirEntry" - } - ], - { - "text": " value represents a file or directory in the directory, and contains information about the file or directory.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-3", - "type": "listing" - }, - "file": "dirs.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "doc", - "os.DirEntry" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "doc": "os.DirEntry", - "exec": "go doc os.DirEntry" - }, - "expected_exit": 0, - "file": "dirs", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc os.DirEntry\n\npackage os // import \u0026#34;os\u0026#34;\n\ntype DirEntry = fs.DirEntry\n A DirEntry is an entry read from a directory (using the ReadDir function or\n a File\u0026#39;s ReadDir method).\n\nfunc ReadDir(name string) ([]DirEntry, error)", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "os.DirEntry" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBvcyAvLyBpbXBvcnQgIm9zIgoKdHlwZSBEaXJFbnRyeSA9IGZzLkRpckVudHJ5CiAgICBBIERpckVudHJ5IGlzIGFuIGVudHJ5IHJlYWQgZnJvbSBhIGRpcmVjdG9yeSAodXNpbmcgdGhlIFJlYWREaXIgZnVuY3Rpb24gb3IKICAgIGEgRmlsZSdzIFJlYWREaXIgbWV0aG9kKS4KCmZ1bmMgUmVhZERpcihuYW1lIHN0cmluZykgKFtdRGlyRW50cnksIGVycm9yKQ==", - "duration": 80765375, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc os.DirEntry\n\npackage os // import \u0026#34;os\u0026#34;\n\ntype DirEntry = fs.DirEntry\n A DirEntry is an entry read from a directory (using the ReadDir function or\n a File\u0026#39;s ReadDir method).\n\nfunc ReadDir(name string) ([]DirEntry, error)", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "os.DirEntry" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBvcyAvLyBpbXBvcnQgIm9zIgoKdHlwZSBEaXJFbnRyeSA9IGZzLkRpckVudHJ5CiAgICBBIERpckVudHJ5IGlzIGFuIGVudHJ5IHJlYWQgZnJvbSBhIGRpcmVjdG9yeSAodXNpbmcgdGhlIFJlYWREaXIgZnVuY3Rpb24gb3IKICAgIGEgRmlsZSdzIFJlYWREaXIgbWV0aG9kKS4KCmZ1bmMgUmVhZERpcihuYW1lIHN0cmluZykgKFtdRGlyRW50cnksIGVycm9yKQ==", - "duration": 80765375, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "dirs", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.3:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "os#DirEntry", - "href": "https://pkg.go.dev/os#DirEntry", - "target": "_blank" - }, - "file": "dirs", - "nodes": [ - [ - { - "atom": "code", - "file": "dirs", - "nodes": [ - { - "text": "os.DirEntry", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/os#DirEntry" - } - ], - { - "text": " type.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 3, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "dirs.md", - "nodes": [ - { - "text": "In ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "href": "https://go.dev/doc/go1.16", - "target": "_blank" - }, - "file": "dirs.md", - "nodes": [ - [ - { - "atom": "code", - "file": "dirs.md", - "nodes": [ - { - "text": "go1.16", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://go.dev/doc/go1.16" - } - ], - { - "text": " the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "fs", - "href": "https://pkg.go.dev/fs", - "target": "_blank" - }, - "file": "dirs.md", - "nodes": [ - { - "atom": "code", - "file": "dirs.md", - "nodes": [ - { - "text": "fs", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/fs" - } - ], - { - "text": " package was added, which provides interface around the file system. The result of this was that many types were aliased to the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "fs", - "href": "https://pkg.go.dev/fs", - "target": "_blank" - }, - "file": "dirs.md", - "nodes": [ - { - "atom": "code", - "file": "dirs.md", - "nodes": [ - { - "text": "fs", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/fs" - } - ], - { - "text": " package. This means that you may need to hunt a little further to find the deeper documentation.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "dirs.md", - "nodes": [ - { - "text": "For example, ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "os#DirEntry", - "href": "https://pkg.go.dev/os#DirEntry", - "target": "_blank" - }, - "file": "dirs.md", - "nodes": [ - { - "atom": "code", - "file": "dirs.md", - "nodes": [ - { - "text": "os.DirEntry", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/os#DirEntry" - } - ], - { - "text": " was aliased to ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "io/fs#DirEntry", - "href": "https://pkg.go.dev/io/fs#DirEntry", - "target": "_blank" - }, - "file": "dirs.md", - "nodes": [ - { - "atom": "code", - "file": "dirs.md", - "nodes": [ - { - "text": "fs.DirEntry", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/io/fs#DirEntry" - } - ], - { - "text": " in ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "dirs.md", - "nodes": [ - { - "text": "go1.16", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ", ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-4" - }, - "file": "dirs.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-4" - }, - "nodes": [ - { - "text": "Listing 1.4", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-4" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-4", - "type": "listing" - }, - "file": "dirs.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "doc", - "fs.DirEntry" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "doc": "fs.DirEntry", - "exec": "go doc fs.DirEntry" - }, - "expected_exit": 0, - "file": "dirs", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc fs.DirEntry\n\npackage fs // import \u0026#34;io/fs\u0026#34;\n\ntype DirEntry interface {\n\t// Name returns the name of the file (or subdirectory) described by the entry.\n\t// This name is only the final element of the path (the base name), not the entire path.\n\t// For example, Name would return \u0026#34;hello.go\u0026#34; not \u0026#34;home/gopher/hello.go\u0026#34;.\n\tName() string\n\n\t// IsDir reports whether the entry describes a directory.\n\tIsDir() bool\n\n\t// Type returns the type bits for the entry.\n\t// The type bits are a subset of the usual FileMode bits, those returned by the FileMode.Type method.\n\tType() FileMode\n\n\t// Info returns the FileInfo for the file or subdirectory described by the entry.\n\t// The returned FileInfo may be from the time of the original directory read\n\t// or from the time of the call to Info. If the file has been removed or renamed\n\t// since the directory read, Info may return an error satisfying errors.Is(err, ErrNotExist).\n\t// If the entry denotes a symbolic link, Info reports the information about the link itself,\n\t// not the link\u0026#39;s target.\n\tInfo() (FileInfo, error)\n}\n A DirEntry is an entry read from a directory (using the ReadDir function or\n a ReadDirFile\u0026#39;s ReadDir method).\n\nfunc FileInfoToDirEntry(info FileInfo) DirEntry\nfunc ReadDir(fsys FS, name string) ([]DirEntry, error)", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "fs.DirEntry" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBmcyAvLyBpbXBvcnQgImlvL2ZzIgoKdHlwZSBEaXJFbnRyeSBpbnRlcmZhY2UgewoJLy8gTmFtZSByZXR1cm5zIHRoZSBuYW1lIG9mIHRoZSBmaWxlIChvciBzdWJkaXJlY3RvcnkpIGRlc2NyaWJlZCBieSB0aGUgZW50cnkuCgkvLyBUaGlzIG5hbWUgaXMgb25seSB0aGUgZmluYWwgZWxlbWVudCBvZiB0aGUgcGF0aCAodGhlIGJhc2UgbmFtZSksIG5vdCB0aGUgZW50aXJlIHBhdGguCgkvLyBGb3IgZXhhbXBsZSwgTmFtZSB3b3VsZCByZXR1cm4gImhlbGxvLmdvIiBub3QgImhvbWUvZ29waGVyL2hlbGxvLmdvIi4KCU5hbWUoKSBzdHJpbmcKCgkvLyBJc0RpciByZXBvcnRzIHdoZXRoZXIgdGhlIGVudHJ5IGRlc2NyaWJlcyBhIGRpcmVjdG9yeS4KCUlzRGlyKCkgYm9vbAoKCS8vIFR5cGUgcmV0dXJucyB0aGUgdHlwZSBiaXRzIGZvciB0aGUgZW50cnkuCgkvLyBUaGUgdHlwZSBiaXRzIGFyZSBhIHN1YnNldCBvZiB0aGUgdXN1YWwgRmlsZU1vZGUgYml0cywgdGhvc2UgcmV0dXJuZWQgYnkgdGhlIEZpbGVNb2RlLlR5cGUgbWV0aG9kLgoJVHlwZSgpIEZpbGVNb2RlCgoJLy8gSW5mbyByZXR1cm5zIHRoZSBGaWxlSW5mbyBmb3IgdGhlIGZpbGUgb3Igc3ViZGlyZWN0b3J5IGRlc2NyaWJlZCBieSB0aGUgZW50cnkuCgkvLyBUaGUgcmV0dXJuZWQgRmlsZUluZm8gbWF5IGJlIGZyb20gdGhlIHRpbWUgb2YgdGhlIG9yaWdpbmFsIGRpcmVjdG9yeSByZWFkCgkvLyBvciBmcm9tIHRoZSB0aW1lIG9mIHRoZSBjYWxsIHRvIEluZm8uIElmIHRoZSBmaWxlIGhhcyBiZWVuIHJlbW92ZWQgb3IgcmVuYW1lZAoJLy8gc2luY2UgdGhlIGRpcmVjdG9yeSByZWFkLCBJbmZvIG1heSByZXR1cm4gYW4gZXJyb3Igc2F0aXNmeWluZyBlcnJvcnMuSXMoZXJyLCBFcnJOb3RFeGlzdCkuCgkvLyBJZiB0aGUgZW50cnkgZGVub3RlcyBhIHN5bWJvbGljIGxpbmssIEluZm8gcmVwb3J0cyB0aGUgaW5mb3JtYXRpb24gYWJvdXQgdGhlIGxpbmsgaXRzZWxmLAoJLy8gbm90IHRoZSBsaW5rJ3MgdGFyZ2V0LgoJSW5mbygpIChGaWxlSW5mbywgZXJyb3IpCn0KICAgIEEgRGlyRW50cnkgaXMgYW4gZW50cnkgcmVhZCBmcm9tIGEgZGlyZWN0b3J5ICh1c2luZyB0aGUgUmVhZERpciBmdW5jdGlvbiBvcgogICAgYSBSZWFkRGlyRmlsZSdzIFJlYWREaXIgbWV0aG9kKS4KCmZ1bmMgRmlsZUluZm9Ub0RpckVudHJ5KGluZm8gRmlsZUluZm8pIERpckVudHJ5CmZ1bmMgUmVhZERpcihmc3lzIEZTLCBuYW1lIHN0cmluZykgKFtdRGlyRW50cnksIGVycm9yKQ==", - "duration": 630553167, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc fs.DirEntry\n\npackage fs // import \u0026#34;io/fs\u0026#34;\n\ntype DirEntry interface {\n\t// Name returns the name of the file (or subdirectory) described by the entry.\n\t// This name is only the final element of the path (the base name), not the entire path.\n\t// For example, Name would return \u0026#34;hello.go\u0026#34; not \u0026#34;home/gopher/hello.go\u0026#34;.\n\tName() string\n\n\t// IsDir reports whether the entry describes a directory.\n\tIsDir() bool\n\n\t// Type returns the type bits for the entry.\n\t// The type bits are a subset of the usual FileMode bits, those returned by the FileMode.Type method.\n\tType() FileMode\n\n\t// Info returns the FileInfo for the file or subdirectory described by the entry.\n\t// The returned FileInfo may be from the time of the original directory read\n\t// or from the time of the call to Info. If the file has been removed or renamed\n\t// since the directory read, Info may return an error satisfying errors.Is(err, ErrNotExist).\n\t// If the entry denotes a symbolic link, Info reports the information about the link itself,\n\t// not the link\u0026#39;s target.\n\tInfo() (FileInfo, error)\n}\n A DirEntry is an entry read from a directory (using the ReadDir function or\n a ReadDirFile\u0026#39;s ReadDir method).\n\nfunc FileInfoToDirEntry(info FileInfo) DirEntry\nfunc ReadDir(fsys FS, name string) ([]DirEntry, error)", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "fs.DirEntry" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBmcyAvLyBpbXBvcnQgImlvL2ZzIgoKdHlwZSBEaXJFbnRyeSBpbnRlcmZhY2UgewoJLy8gTmFtZSByZXR1cm5zIHRoZSBuYW1lIG9mIHRoZSBmaWxlIChvciBzdWJkaXJlY3RvcnkpIGRlc2NyaWJlZCBieSB0aGUgZW50cnkuCgkvLyBUaGlzIG5hbWUgaXMgb25seSB0aGUgZmluYWwgZWxlbWVudCBvZiB0aGUgcGF0aCAodGhlIGJhc2UgbmFtZSksIG5vdCB0aGUgZW50aXJlIHBhdGguCgkvLyBGb3IgZXhhbXBsZSwgTmFtZSB3b3VsZCByZXR1cm4gImhlbGxvLmdvIiBub3QgImhvbWUvZ29waGVyL2hlbGxvLmdvIi4KCU5hbWUoKSBzdHJpbmcKCgkvLyBJc0RpciByZXBvcnRzIHdoZXRoZXIgdGhlIGVudHJ5IGRlc2NyaWJlcyBhIGRpcmVjdG9yeS4KCUlzRGlyKCkgYm9vbAoKCS8vIFR5cGUgcmV0dXJucyB0aGUgdHlwZSBiaXRzIGZvciB0aGUgZW50cnkuCgkvLyBUaGUgdHlwZSBiaXRzIGFyZSBhIHN1YnNldCBvZiB0aGUgdXN1YWwgRmlsZU1vZGUgYml0cywgdGhvc2UgcmV0dXJuZWQgYnkgdGhlIEZpbGVNb2RlLlR5cGUgbWV0aG9kLgoJVHlwZSgpIEZpbGVNb2RlCgoJLy8gSW5mbyByZXR1cm5zIHRoZSBGaWxlSW5mbyBmb3IgdGhlIGZpbGUgb3Igc3ViZGlyZWN0b3J5IGRlc2NyaWJlZCBieSB0aGUgZW50cnkuCgkvLyBUaGUgcmV0dXJuZWQgRmlsZUluZm8gbWF5IGJlIGZyb20gdGhlIHRpbWUgb2YgdGhlIG9yaWdpbmFsIGRpcmVjdG9yeSByZWFkCgkvLyBvciBmcm9tIHRoZSB0aW1lIG9mIHRoZSBjYWxsIHRvIEluZm8uIElmIHRoZSBmaWxlIGhhcyBiZWVuIHJlbW92ZWQgb3IgcmVuYW1lZAoJLy8gc2luY2UgdGhlIGRpcmVjdG9yeSByZWFkLCBJbmZvIG1heSByZXR1cm4gYW4gZXJyb3Igc2F0aXNmeWluZyBlcnJvcnMuSXMoZXJyLCBFcnJOb3RFeGlzdCkuCgkvLyBJZiB0aGUgZW50cnkgZGVub3RlcyBhIHN5bWJvbGljIGxpbmssIEluZm8gcmVwb3J0cyB0aGUgaW5mb3JtYXRpb24gYWJvdXQgdGhlIGxpbmsgaXRzZWxmLAoJLy8gbm90IHRoZSBsaW5rJ3MgdGFyZ2V0LgoJSW5mbygpIChGaWxlSW5mbywgZXJyb3IpCn0KICAgIEEgRGlyRW50cnkgaXMgYW4gZW50cnkgcmVhZCBmcm9tIGEgZGlyZWN0b3J5ICh1c2luZyB0aGUgUmVhZERpciBmdW5jdGlvbiBvcgogICAgYSBSZWFkRGlyRmlsZSdzIFJlYWREaXIgbWV0aG9kKS4KCmZ1bmMgRmlsZUluZm9Ub0RpckVudHJ5KGluZm8gRmlsZUluZm8pIERpckVudHJ5CmZ1bmMgUmVhZERpcihmc3lzIEZTLCBuYW1lIHN0cmluZykgKFtdRGlyRW50cnksIGVycm9yKQ==", - "duration": 630553167, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "dirs", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.4:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "io/fs#DirEntry", - "href": "https://pkg.go.dev/io/fs#DirEntry", - "target": "_blank" - }, - "file": "dirs", - "nodes": [ - [ - { - "atom": "code", - "file": "dirs", - "nodes": [ - { - "text": "fs.DirEntry", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/io/fs#DirEntry" - } - ], - { - "text": " type.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 4, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "dirs.md", - "nodes": [ - { - "text": "We can use the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "os#ReadDir", - "href": "https://pkg.go.dev/os#ReadDir", - "target": "_blank" - }, - "file": "dirs.md", - "nodes": [ - { - "atom": "code", - "file": "dirs.md", - "nodes": [ - { - "text": "os.ReadDir", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/os#ReadDir" - } - ], - { - "text": " function to read the contents of the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "dirs.md", - "nodes": [ - { - "text": "data", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " directory. We then print the names to the console. If the file is a directory, we prepend it with a ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "dirs.md", - "nodes": [ - { - "text": "-\u003e", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-5", - "type": "listing" - }, - "file": "dirs.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "dirs", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "dirs/src/tree/main.go#main" - }, - "lang": "go", - "nodes": [ - { - "content": "func main() {\n\tfiles, err := os.ReadDir(\"data\")\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\n\tfor _, file := range files {\n\t\tif file.IsDir() {\n\t\t\tfmt.Println(\"-\u003e\", file.Name())\n\t\t\tcontinue\n\t\t}\n\t\tfmt.Println(file.Name())\n\t}\n}", - "file": "dirs/src/tree/main.go", - "lang": "go", - "name": "main", - "start": 9, - "end": 25, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "dirs", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.5:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Using ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "os#ReadDir", - "href": "https://pkg.go.dev/os#ReadDir", - "target": "_blank" - }, - "file": "dirs", - "nodes": [ - [ - { - "atom": "code", - "file": "dirs", - "nodes": [ - { - "text": "os.ReadDir", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/os#ReadDir" - } - ], - { - "text": " to read the contents of a directory.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 5, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "dirs.md", - "nodes": [ - { - "text": "As we can see from the output of the program, only the files in the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "dirs.md", - "nodes": [ - { - "text": "data", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " directory are listed. The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "os#ReadDir", - "href": "https://pkg.go.dev/os#ReadDir", - "target": "_blank" - }, - "file": "dirs.md", - "nodes": [ - { - "atom": "code", - "file": "dirs.md", - "nodes": [ - { - "text": "os.ReadDir", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/os#ReadDir" - } - ], - { - "text": " function will only read the contents of the directory, and not the contents of any subdirectories. To get a full list of files, including the contents of subdirectories, we will need to walk the directories ourselves. We will discuss this more later.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-6", - "type": "listing" - }, - "file": "dirs.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "run", - "." - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go run .", - "run": ".", - "src": "dirs/src/tree" - }, - "expected_exit": 0, - "file": "dirs", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\n-\u0026gt; .hidden\na.txt\nb.txt\n-\u0026gt; e\n-\u0026gt; testdata", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/14-files/dirs/src/tree", - "stdout": "LT4gLmhpZGRlbgphLnR4dApiLnR4dAotPiBlCi0+IHRlc3RkYXRh", - "duration": 1748284792, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\n-\u0026gt; .hidden\na.txt\nb.txt\n-\u0026gt; e\n-\u0026gt; testdata", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/14-files/dirs/src/tree", - "stdout": "LT4gLmhpZGRlbgphLnR4dApiLnR4dAotPiBlCi0+IHRlc3RkYXRh", - "duration": 1748284792, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "dirs", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.6:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Output of ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-5" - }, - "file": "dirs", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-5" - }, - "nodes": [ - { - "text": "Listing 1.5", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-5" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 6, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "dirs.md", - "level": 2, - "nodes": [ - { - "text": "The FileInfo Interface", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "dirs.md", - "nodes": [ - { - "text": "The main source for metadata about files is the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "io/fs#FileInfo", - "href": "https://pkg.go.dev/io/fs#FileInfo", - "target": "_blank" - }, - "file": "dirs.md", - "nodes": [ - { - "atom": "code", - "file": "dirs.md", - "nodes": [ - { - "text": "fs.FileInfo", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/io/fs#FileInfo" - } - ], - { - "text": " interface, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-7" - }, - "file": "dirs.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-7" - }, - "nodes": [ - { - "text": "Listing 1.7", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-7" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ". In ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "dirs.md", - "nodes": [ - { - "text": "go1.16", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "os#FileInfo", - "href": "https://pkg.go.dev/os#FileInfo", - "target": "_blank" - }, - "file": "dirs.md", - "nodes": [ - { - "atom": "code", - "file": "dirs.md", - "nodes": [ - { - "text": "os.FileInfo", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/os#FileInfo" - } - ], - { - "text": " type was aliased to ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "io/fs#FileInfo", - "href": "https://pkg.go.dev/io/fs#FileInfo", - "target": "_blank" - }, - "file": "dirs.md", - "nodes": [ - { - "atom": "code", - "file": "dirs.md", - "nodes": [ - { - "text": "fs.FileInfo", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/io/fs#FileInfo" - } - ], - { - "text": ". From this interface we can get the name of the file, the size of the file, the time the file was last modified, and the mode, or permissions, of the file. We can also tell if the file is a directory, or a regular file.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-7", - "type": "listing" - }, - "file": "dirs.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "doc", - "fs.FileInfo" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "doc": "fs.FileInfo", - "exec": "go doc fs.FileInfo" - }, - "expected_exit": 0, - "file": "dirs", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc fs.FileInfo\n\npackage fs // import \u0026#34;io/fs\u0026#34;\n\ntype FileInfo interface {\n\tName() string // base name of the file\n\tSize() int64 // length in bytes for regular files; system-dependent for others\n\tMode() FileMode // file mode bits\n\tModTime() time.Time // modification time\n\tIsDir() bool // abbreviation for Mode().IsDir()\n\tSys() any // underlying data source (can return nil)\n}\n A FileInfo describes a file and is returned by Stat.\n\nfunc Stat(fsys FS, name string) (FileInfo, error)", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "fs.FileInfo" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBmcyAvLyBpbXBvcnQgImlvL2ZzIgoKdHlwZSBGaWxlSW5mbyBpbnRlcmZhY2UgewoJTmFtZSgpIHN0cmluZyAgICAgICAvLyBiYXNlIG5hbWUgb2YgdGhlIGZpbGUKCVNpemUoKSBpbnQ2NCAgICAgICAgLy8gbGVuZ3RoIGluIGJ5dGVzIGZvciByZWd1bGFyIGZpbGVzOyBzeXN0ZW0tZGVwZW5kZW50IGZvciBvdGhlcnMKCU1vZGUoKSBGaWxlTW9kZSAgICAgLy8gZmlsZSBtb2RlIGJpdHMKCU1vZFRpbWUoKSB0aW1lLlRpbWUgLy8gbW9kaWZpY2F0aW9uIHRpbWUKCUlzRGlyKCkgYm9vbCAgICAgICAgLy8gYWJicmV2aWF0aW9uIGZvciBNb2RlKCkuSXNEaXIoKQoJU3lzKCkgYW55ICAgICAgICAgICAvLyB1bmRlcmx5aW5nIGRhdGEgc291cmNlIChjYW4gcmV0dXJuIG5pbCkKfQogICAgQSBGaWxlSW5mbyBkZXNjcmliZXMgYSBmaWxlIGFuZCBpcyByZXR1cm5lZCBieSBTdGF0LgoKZnVuYyBTdGF0KGZzeXMgRlMsIG5hbWUgc3RyaW5nKSAoRmlsZUluZm8sIGVycm9yKQ==", - "duration": 910388042, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc fs.FileInfo\n\npackage fs // import \u0026#34;io/fs\u0026#34;\n\ntype FileInfo interface {\n\tName() string // base name of the file\n\tSize() int64 // length in bytes for regular files; system-dependent for others\n\tMode() FileMode // file mode bits\n\tModTime() time.Time // modification time\n\tIsDir() bool // abbreviation for Mode().IsDir()\n\tSys() any // underlying data source (can return nil)\n}\n A FileInfo describes a file and is returned by Stat.\n\nfunc Stat(fsys FS, name string) (FileInfo, error)", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "fs.FileInfo" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBmcyAvLyBpbXBvcnQgImlvL2ZzIgoKdHlwZSBGaWxlSW5mbyBpbnRlcmZhY2UgewoJTmFtZSgpIHN0cmluZyAgICAgICAvLyBiYXNlIG5hbWUgb2YgdGhlIGZpbGUKCVNpemUoKSBpbnQ2NCAgICAgICAgLy8gbGVuZ3RoIGluIGJ5dGVzIGZvciByZWd1bGFyIGZpbGVzOyBzeXN0ZW0tZGVwZW5kZW50IGZvciBvdGhlcnMKCU1vZGUoKSBGaWxlTW9kZSAgICAgLy8gZmlsZSBtb2RlIGJpdHMKCU1vZFRpbWUoKSB0aW1lLlRpbWUgLy8gbW9kaWZpY2F0aW9uIHRpbWUKCUlzRGlyKCkgYm9vbCAgICAgICAgLy8gYWJicmV2aWF0aW9uIGZvciBNb2RlKCkuSXNEaXIoKQoJU3lzKCkgYW55ICAgICAgICAgICAvLyB1bmRlcmx5aW5nIGRhdGEgc291cmNlIChjYW4gcmV0dXJuIG5pbCkKfQogICAgQSBGaWxlSW5mbyBkZXNjcmliZXMgYSBmaWxlIGFuZCBpcyByZXR1cm5lZCBieSBTdGF0LgoKZnVuYyBTdGF0KGZzeXMgRlMsIG5hbWUgc3RyaW5nKSAoRmlsZUluZm8sIGVycm9yKQ==", - "duration": 910388042, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "dirs", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.7:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "io/fs#FileInfo", - "href": "https://pkg.go.dev/io/fs#FileInfo", - "target": "_blank" - }, - "file": "dirs", - "nodes": [ - [ - { - "atom": "code", - "file": "dirs", - "nodes": [ - { - "text": "fs.FileInfo", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/io/fs#FileInfo" - } - ], - { - "text": " interface.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 7, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "dirs.md", - "nodes": [ - { - "text": "Consider ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-8" - }, - "file": "dirs.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-8" - }, - "nodes": [ - { - "text": "Listing 1.8", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-8" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ". We read the contents of the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "dirs.md", - "nodes": [ - { - "text": "data", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " directory, and print the mode, size, and name of each file.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-8", - "type": "listing" - }, - "file": "dirs.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "dirs", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "dirs/src/info/main.go#main" - }, - "lang": "go", - "nodes": [ - { - "content": "func main() {\n\tfiles, err := os.ReadDir(\"data\")\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\n\tfmt.Println(\"Mode\\t\\tSize\\tName\")\n\tfor _, file := range files {\n\t\tinfo, err := file.Info()\n\t\tif err != nil {\n\t\t\tlog.Fatal(err)\n\t\t}\n\n\t\tfmt.Printf(\"%s\\t%d\\t\\t%s\\n\", info.Mode(), info.Size(), info.Name())\n\t}\n}", - "file": "dirs/src/info/main.go", - "lang": "go", - "name": "main", - "start": 9, - "end": 27, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "atom": "hr", - "file": "dirs", - "type": "*hype.Element" - }, - [ - { - "args": [ - "go", - "run", - "." - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go run .", - "run": ".", - "src": "dirs/src/info" - }, - "expected_exit": 0, - "file": "dirs", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\nMode\t\tSize\tName\ndrwxr-xr-x\t96\t\t.hidden\n-rw-r--r--\t31\t\ta.txt\n-rw-r--r--\t9\t\tb.txt\ndrwxr-xr-x\t128\t\te\ndrwxr-xr-x\t96\t\ttestdata", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/14-files/dirs/src/info", - "stdout": "TW9kZQkJU2l6ZQlOYW1lCmRyd3hyLXhyLXgJOTYJCS5oaWRkZW4KLXJ3LXItLXItLQkzMQkJYS50eHQKLXJ3LXItLXItLQk5CQliLnR4dApkcnd4ci14ci14CTEyOAkJZQpkcnd4ci14ci14CTk2CQl0ZXN0ZGF0YQ==", - "duration": 553456792, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\nMode\t\tSize\tName\ndrwxr-xr-x\t96\t\t.hidden\n-rw-r--r--\t31\t\ta.txt\n-rw-r--r--\t9\t\tb.txt\ndrwxr-xr-x\t128\t\te\ndrwxr-xr-x\t96\t\ttestdata", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/14-files/dirs/src/info", - "stdout": "TW9kZQkJU2l6ZQlOYW1lCmRyd3hyLXhyLXgJOTYJCS5oaWRkZW4KLXJ3LXItLXItLQkzMQkJYS50eHQKLXJ3LXItLXItLQk5CQliLnR4dApkcnd4ci14ci14CTEyOAkJZQpkcnd4ci14ci14CTk2CQl0ZXN0ZGF0YQ==", - "duration": 553456792, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "dirs", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.8:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Using ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "io/fs#FileInfo", - "href": "https://pkg.go.dev/io/fs#FileInfo", - "target": "_blank" - }, - "file": "dirs", - "nodes": [ - [ - { - "atom": "code", - "file": "dirs", - "nodes": [ - { - "text": "fs.FileInfo", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/io/fs#FileInfo" - } - ], - { - "text": " to print information about files.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 8, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "dirs.md", - "level": 2, - "nodes": [ - { - "text": "Stating a File", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "dirs.md", - "nodes": [ - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "os#ReadDir", - "href": "https://pkg.go.dev/os#ReadDir", - "target": "_blank" - }, - "file": "dirs.md", - "nodes": [ - { - "atom": "code", - "file": "dirs.md", - "nodes": [ - { - "text": "os.ReadDir", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/os#ReadDir" - } - ], - { - "text": " function returns a slice of ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "os#DirEntry", - "href": "https://pkg.go.dev/os#DirEntry", - "target": "_blank" - }, - "file": "dirs.md", - "nodes": [ - { - "atom": "code", - "file": "dirs.md", - "nodes": [ - { - "text": "os.DirEntry", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/os#DirEntry" - } - ], - { - "text": " values, from which we can get the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "io/fs#FileInfo", - "href": "https://pkg.go.dev/io/fs#FileInfo", - "target": "_blank" - }, - "file": "dirs.md", - "nodes": [ - { - "atom": "code", - "file": "dirs.md", - "nodes": [ - { - "text": "fs.FileInfo", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/io/fs#FileInfo" - } - ], - { - "text": " from, ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "os#DirEntry.Info", - "href": "https://pkg.go.dev/os#DirEntry.Info", - "target": "_blank" - }, - "file": "dirs.md", - "nodes": [ - { - "atom": "code", - "file": "dirs.md", - "nodes": [ - { - "text": "os.DirEntry.Info", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/os#DirEntry.Info" - } - ], - { - "text": ". To get the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "io/fs#FileInfo", - "href": "https://pkg.go.dev/io/fs#FileInfo", - "target": "_blank" - }, - "file": "dirs.md", - "nodes": [ - { - "atom": "code", - "file": "dirs.md", - "nodes": [ - { - "text": "fs.FileInfo", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/io/fs#FileInfo" - } - ], - { - "text": " for a single file or directory we can use the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "os#Stat", - "href": "https://pkg.go.dev/os#Stat", - "target": "_blank" - }, - "file": "dirs.md", - "nodes": [ - { - "atom": "code", - "file": "dirs.md", - "nodes": [ - { - "text": "os.Stat", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/os#Stat" - } - ], - { - "text": " function, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-9" - }, - "file": "dirs.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-9" - }, - "nodes": [ - { - "text": "Listing 1.9", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-9" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-9", - "type": "listing" - }, - "file": "dirs.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "doc", - "os.Stat" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "doc": "os.Stat", - "exec": "go doc os.Stat" - }, - "expected_exit": 0, - "file": "dirs", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc os.Stat\n\npackage os // import \u0026#34;os\u0026#34;\n\nfunc Stat(name string) (FileInfo, error)\n Stat returns a FileInfo describing the named file. If there is an error,\n it will be of type *PathError.", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "os.Stat" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBvcyAvLyBpbXBvcnQgIm9zIgoKZnVuYyBTdGF0KG5hbWUgc3RyaW5nKSAoRmlsZUluZm8sIGVycm9yKQogICAgU3RhdCByZXR1cm5zIGEgRmlsZUluZm8gZGVzY3JpYmluZyB0aGUgbmFtZWQgZmlsZS4gSWYgdGhlcmUgaXMgYW4gZXJyb3IsCiAgICBpdCB3aWxsIGJlIG9mIHR5cGUgKlBhdGhFcnJvci4=", - "duration": 585994750, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc os.Stat\n\npackage os // import \u0026#34;os\u0026#34;\n\nfunc Stat(name string) (FileInfo, error)\n Stat returns a FileInfo describing the named file. If there is an error,\n it will be of type *PathError.", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "os.Stat" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBvcyAvLyBpbXBvcnQgIm9zIgoKZnVuYyBTdGF0KG5hbWUgc3RyaW5nKSAoRmlsZUluZm8sIGVycm9yKQogICAgU3RhdCByZXR1cm5zIGEgRmlsZUluZm8gZGVzY3JpYmluZyB0aGUgbmFtZWQgZmlsZS4gSWYgdGhlcmUgaXMgYW4gZXJyb3IsCiAgICBpdCB3aWxsIGJlIG9mIHR5cGUgKlBhdGhFcnJvci4=", - "duration": 585994750, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "dirs", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.9:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "os#Stat", - "href": "https://pkg.go.dev/os#Stat", - "target": "_blank" - }, - "file": "dirs", - "nodes": [ - [ - { - "atom": "code", - "file": "dirs", - "nodes": [ - { - "text": "os.Stat", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/os#Stat" - } - ], - { - "text": " function.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 9, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "dirs.md", - "nodes": [ - { - "text": "Consider ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-10" - }, - "file": "dirs.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-10" - }, - "nodes": [ - { - "text": "Listing 1.10", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-10" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", which prints the mode, size, and name of the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "dirs.md", - "nodes": [ - { - "text": "data/a.txt", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " file.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-10", - "type": "listing" - }, - "file": "dirs.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "dirs", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "dirs/src/stat/main.go#main" - }, - "lang": "go", - "nodes": [ - { - "content": "func main() {\n\tinfo, err := os.Stat(\"data/a.txt\")\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\n\tfmt.Printf(\"%s\\t%d\\t%s\\n\", info.Mode(), info.Size(), info.Name())\n}", - "file": "dirs/src/stat/main.go", - "lang": "go", - "name": "main", - "start": 9, - "end": 19, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "atom": "hr", - "file": "dirs", - "type": "*hype.Element" - }, - [ - { - "args": [ - "go", - "run", - "." - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go run .", - "run": ".", - "src": "dirs/src/stat" - }, - "expected_exit": 0, - "file": "dirs", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\n-rw-r--r--\t31\ta.txt", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/14-files/dirs/src/stat", - "stdout": "LXJ3LXItLXItLQkzMQlhLnR4dA==", - "duration": 1823247666, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\n-rw-r--r--\t31\ta.txt", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/14-files/dirs/src/stat", - "stdout": "LXJ3LXItLXItLQkzMQlhLnR4dA==", - "duration": 1823247666, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "dirs", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.10:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Using ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "os#Stat", - "href": "https://pkg.go.dev/os#Stat", - "target": "_blank" - }, - "file": "dirs", - "nodes": [ - [ - { - "atom": "code", - "file": "dirs", - "nodes": [ - { - "text": "os.Stat", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/os#Stat" - } - ], - { - "text": " to get information about a file.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 10, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "title": "Directory Entries and File Information", - "type": "*hype.Page" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "type": "*hype.Include" - } - ], - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "include", - "attributes": { - "src": "walk/walk.md" - }, - "dir": "walk", - "file": "module.md", - "nodes": [ - [ - { - "atom": "page", - "file": "walk.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "h1", - "file": "walk.md", - "level": 1, - "nodes": [ - { - "text": "Walking Directories", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "walk.md", - "nodes": [ - { - "text": "As we have seen, ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "os#ReadDir", - "href": "https://pkg.go.dev/os#ReadDir", - "target": "_blank" - }, - "file": "walk.md", - "nodes": [ - { - "atom": "code", - "file": "walk.md", - "nodes": [ - { - "text": "os.ReadDir", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/os#ReadDir" - } - ], - { - "text": " does not recurse into subdirectories. To be able to do that, we need to use ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "filepath#WalkDir", - "href": "https://pkg.go.dev/filepath#WalkDir", - "target": "_blank" - }, - "file": "walk.md", - "nodes": [ - { - "atom": "code", - "file": "walk.md", - "nodes": [ - { - "text": "filepath.WalkDir", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/filepath#WalkDir" - } - ], - { - "text": ", ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-11" - }, - "file": "walk.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-11" - }, - "nodes": [ - { - "text": "Listing 1.11", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-11" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ". This will walk through all files in a directory and all subdirectories.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - { - "atom": "blockquote", - "file": "walk.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "walk.md", - "nodes": [ - [ - { - "atom": "a", - "attributes": { - "for": "filepath#WalkDir", - "href": "https://pkg.go.dev/filepath#WalkDir", - "target": "_blank" - }, - "file": "walk.md", - "nodes": [ - { - "atom": "code", - "file": "walk.md", - "nodes": [ - { - "text": "filepath.WalkDir", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/filepath#WalkDir" - } - ], - { - "text": ", introduced in ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "walk.md", - "nodes": [ - { - "text": "go1.16", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ", replaces the less efficient ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "filepath#Walk", - "href": "https://pkg.go.dev/filepath#Walk", - "target": "_blank" - }, - "file": "walk.md", - "nodes": [ - { - "atom": "code", - "file": "walk.md", - "nodes": [ - { - "text": "filepath.Walk", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/filepath#Walk" - } - ], - { - "text": ". Older examples may use ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "filepath#Walk", - "href": "https://pkg.go.dev/filepath#Walk", - "target": "_blank" - }, - "file": "walk.md", - "nodes": [ - { - "atom": "code", - "file": "walk.md", - "nodes": [ - { - "text": "filepath.Walk", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/filepath#Walk" - } - ], - { - "text": ", but it is advised to use ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "filepath#WalkDir", - "href": "https://pkg.go.dev/filepath#WalkDir", - "target": "_blank" - }, - "file": "walk.md", - "nodes": [ - { - "atom": "code", - "file": "walk.md", - "nodes": [ - { - "text": "filepath.WalkDir", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/filepath#WalkDir" - } - ], - { - "text": " instead.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-11", - "type": "listing" - }, - "file": "walk.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "doc", - "filepath.WalkDir" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "doc": "filepath.WalkDir", - "exec": "go doc filepath.WalkDir" - }, - "expected_exit": 0, - "file": "walk", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc filepath.WalkDir\n\npackage filepath // import \u0026#34;path/filepath\u0026#34;\n\nfunc WalkDir(root string, fn fs.WalkDirFunc) error\n WalkDir walks the file tree rooted at root, calling fn for each file or\n directory in the tree, including root.\n\n All errors that arise visiting files and directories are filtered by fn:\n see the fs.WalkDirFunc documentation for details.\n\n The files are walked in lexical order, which makes the output deterministic\n but requires WalkDir to read an entire directory into memory before\n proceeding to walk that directory.\n\n WalkDir does not follow symbolic links.\n\n WalkDir calls fn with paths that use the separator character appropriate for\n the operating system. This is unlike io/fs.WalkDir, which always uses slash\n separated paths.", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "filepath.WalkDir" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBmaWxlcGF0aCAvLyBpbXBvcnQgInBhdGgvZmlsZXBhdGgiCgpmdW5jIFdhbGtEaXIocm9vdCBzdHJpbmcsIGZuIGZzLldhbGtEaXJGdW5jKSBlcnJvcgogICAgV2Fsa0RpciB3YWxrcyB0aGUgZmlsZSB0cmVlIHJvb3RlZCBhdCByb290LCBjYWxsaW5nIGZuIGZvciBlYWNoIGZpbGUgb3IKICAgIGRpcmVjdG9yeSBpbiB0aGUgdHJlZSwgaW5jbHVkaW5nIHJvb3QuCgogICAgQWxsIGVycm9ycyB0aGF0IGFyaXNlIHZpc2l0aW5nIGZpbGVzIGFuZCBkaXJlY3RvcmllcyBhcmUgZmlsdGVyZWQgYnkgZm46CiAgICBzZWUgdGhlIGZzLldhbGtEaXJGdW5jIGRvY3VtZW50YXRpb24gZm9yIGRldGFpbHMuCgogICAgVGhlIGZpbGVzIGFyZSB3YWxrZWQgaW4gbGV4aWNhbCBvcmRlciwgd2hpY2ggbWFrZXMgdGhlIG91dHB1dCBkZXRlcm1pbmlzdGljCiAgICBidXQgcmVxdWlyZXMgV2Fsa0RpciB0byByZWFkIGFuIGVudGlyZSBkaXJlY3RvcnkgaW50byBtZW1vcnkgYmVmb3JlCiAgICBwcm9jZWVkaW5nIHRvIHdhbGsgdGhhdCBkaXJlY3RvcnkuCgogICAgV2Fsa0RpciBkb2VzIG5vdCBmb2xsb3cgc3ltYm9saWMgbGlua3MuCgogICAgV2Fsa0RpciBjYWxscyBmbiB3aXRoIHBhdGhzIHRoYXQgdXNlIHRoZSBzZXBhcmF0b3IgY2hhcmFjdGVyIGFwcHJvcHJpYXRlIGZvcgogICAgdGhlIG9wZXJhdGluZyBzeXN0ZW0uIFRoaXMgaXMgdW5saWtlIGlvL2ZzLldhbGtEaXIsIHdoaWNoIGFsd2F5cyB1c2VzIHNsYXNoCiAgICBzZXBhcmF0ZWQgcGF0aHMu", - "duration": 672412667, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc filepath.WalkDir\n\npackage filepath // import \u0026#34;path/filepath\u0026#34;\n\nfunc WalkDir(root string, fn fs.WalkDirFunc) error\n WalkDir walks the file tree rooted at root, calling fn for each file or\n directory in the tree, including root.\n\n All errors that arise visiting files and directories are filtered by fn:\n see the fs.WalkDirFunc documentation for details.\n\n The files are walked in lexical order, which makes the output deterministic\n but requires WalkDir to read an entire directory into memory before\n proceeding to walk that directory.\n\n WalkDir does not follow symbolic links.\n\n WalkDir calls fn with paths that use the separator character appropriate for\n the operating system. This is unlike io/fs.WalkDir, which always uses slash\n separated paths.", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "filepath.WalkDir" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBmaWxlcGF0aCAvLyBpbXBvcnQgInBhdGgvZmlsZXBhdGgiCgpmdW5jIFdhbGtEaXIocm9vdCBzdHJpbmcsIGZuIGZzLldhbGtEaXJGdW5jKSBlcnJvcgogICAgV2Fsa0RpciB3YWxrcyB0aGUgZmlsZSB0cmVlIHJvb3RlZCBhdCByb290LCBjYWxsaW5nIGZuIGZvciBlYWNoIGZpbGUgb3IKICAgIGRpcmVjdG9yeSBpbiB0aGUgdHJlZSwgaW5jbHVkaW5nIHJvb3QuCgogICAgQWxsIGVycm9ycyB0aGF0IGFyaXNlIHZpc2l0aW5nIGZpbGVzIGFuZCBkaXJlY3RvcmllcyBhcmUgZmlsdGVyZWQgYnkgZm46CiAgICBzZWUgdGhlIGZzLldhbGtEaXJGdW5jIGRvY3VtZW50YXRpb24gZm9yIGRldGFpbHMuCgogICAgVGhlIGZpbGVzIGFyZSB3YWxrZWQgaW4gbGV4aWNhbCBvcmRlciwgd2hpY2ggbWFrZXMgdGhlIG91dHB1dCBkZXRlcm1pbmlzdGljCiAgICBidXQgcmVxdWlyZXMgV2Fsa0RpciB0byByZWFkIGFuIGVudGlyZSBkaXJlY3RvcnkgaW50byBtZW1vcnkgYmVmb3JlCiAgICBwcm9jZWVkaW5nIHRvIHdhbGsgdGhhdCBkaXJlY3RvcnkuCgogICAgV2Fsa0RpciBkb2VzIG5vdCBmb2xsb3cgc3ltYm9saWMgbGlua3MuCgogICAgV2Fsa0RpciBjYWxscyBmbiB3aXRoIHBhdGhzIHRoYXQgdXNlIHRoZSBzZXBhcmF0b3IgY2hhcmFjdGVyIGFwcHJvcHJpYXRlIGZvcgogICAgdGhlIG9wZXJhdGluZyBzeXN0ZW0uIFRoaXMgaXMgdW5saWtlIGlvL2ZzLldhbGtEaXIsIHdoaWNoIGFsd2F5cyB1c2VzIHNsYXNoCiAgICBzZXBhcmF0ZWQgcGF0aHMu", - "duration": 672412667, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "walk", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.11:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "filepath#WalkDir", - "href": "https://pkg.go.dev/filepath#WalkDir", - "target": "_blank" - }, - "file": "walk", - "nodes": [ - [ - { - "atom": "code", - "file": "walk", - "nodes": [ - { - "text": "filepath.WalkDir", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/filepath#WalkDir" - } - ], - { - "text": " function.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 11, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "walk.md", - "nodes": [ - { - "text": "In order to use ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "filepath#WalkDir", - "href": "https://pkg.go.dev/filepath#WalkDir", - "target": "_blank" - }, - "file": "walk.md", - "nodes": [ - { - "atom": "code", - "file": "walk.md", - "nodes": [ - { - "text": "filepath.WalkDir", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/filepath#WalkDir" - } - ], - { - "text": ", we need to, first, give it a path to walk, and then a function that will be called for each file. This function is the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "filepath#WalkFunc", - "href": "https://pkg.go.dev/filepath#WalkFunc", - "target": "_blank" - }, - "file": "walk.md", - "nodes": [ - { - "atom": "code", - "file": "walk.md", - "nodes": [ - { - "text": "filepath.WalkFunc", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/filepath#WalkFunc" - } - ], - { - "text": ", ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-12" - }, - "file": "walk.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-12" - }, - "nodes": [ - { - "text": "Listing 1.12", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-12" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-12", - "type": "listing" - }, - "file": "walk.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "doc", - "fs.WalkDirFunc" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "doc": "fs.WalkDirFunc", - "exec": "go doc fs.WalkDirFunc" - }, - "expected_exit": 0, - "file": "walk", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc fs.WalkDirFunc\n\npackage fs // import \u0026#34;io/fs\u0026#34;\n\ntype WalkDirFunc func(path string, d DirEntry, err error) error\n WalkDirFunc is the type of the function called by WalkDir to visit each file\n or directory.\n\n The path argument contains the argument to WalkDir as a prefix. That is,\n if WalkDir is called with root argument \u0026#34;dir\u0026#34; and finds a file named \u0026#34;a\u0026#34; in\n that directory, the walk function will be called with argument \u0026#34;dir/a\u0026#34;.\n\n The d argument is the fs.DirEntry for the named path.\n\n The error result returned by the function controls how WalkDir continues.\n If the function returns the special value SkipDir, WalkDir skips the current\n directory (path if d.IsDir() is true, otherwise path\u0026#39;s parent directory). If\n the function returns the special value SkipAll, WalkDir skips all remaining\n files and directories. Otherwise, if the function returns a non-nil error,\n WalkDir stops entirely and returns that error.\n\n The err argument reports an error related to path, signaling that WalkDir\n will not walk into that directory. The function can decide how to handle\n that error; as described earlier, returning the error will cause WalkDir to\n stop walking the entire tree.\n\n WalkDir calls the function with a non-nil err argument in two cases.\n\n First, if the initial fs.Stat on the root directory fails, WalkDir calls the\n function with path set to root, d set to nil, and err set to the error from\n fs.Stat.\n\n Second, if a directory\u0026#39;s ReadDir method fails, WalkDir calls the function\n with path set to the directory\u0026#39;s path, d set to an fs.DirEntry describing\n the directory, and err set to the error from ReadDir. In this second case,\n the function is called twice with the path of the directory: the first\n call is before the directory read is attempted and has err set to nil,\n giving the function a chance to return SkipDir or SkipAll and avoid the\n ReadDir entirely. The second call is after a failed ReadDir and reports the\n error from ReadDir. (If ReadDir succeeds, there is no second call.)\n\n The differences between WalkDirFunc compared to filepath.WalkFunc are:\n\n - The second argument has type fs.DirEntry instead of fs.FileInfo.\n - The function is called before reading a directory, to allow SkipDir\n or SkipAll to bypass the directory read entirely or skip all remaining\n files and directories respectively.\n - If a directory read fails, the function is called a second time for that\n directory to report the error.", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "fs.WalkDirFunc" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBmcyAvLyBpbXBvcnQgImlvL2ZzIgoKdHlwZSBXYWxrRGlyRnVuYyBmdW5jKHBhdGggc3RyaW5nLCBkIERpckVudHJ5LCBlcnIgZXJyb3IpIGVycm9yCiAgICBXYWxrRGlyRnVuYyBpcyB0aGUgdHlwZSBvZiB0aGUgZnVuY3Rpb24gY2FsbGVkIGJ5IFdhbGtEaXIgdG8gdmlzaXQgZWFjaCBmaWxlCiAgICBvciBkaXJlY3RvcnkuCgogICAgVGhlIHBhdGggYXJndW1lbnQgY29udGFpbnMgdGhlIGFyZ3VtZW50IHRvIFdhbGtEaXIgYXMgYSBwcmVmaXguIFRoYXQgaXMsCiAgICBpZiBXYWxrRGlyIGlzIGNhbGxlZCB3aXRoIHJvb3QgYXJndW1lbnQgImRpciIgYW5kIGZpbmRzIGEgZmlsZSBuYW1lZCAiYSIgaW4KICAgIHRoYXQgZGlyZWN0b3J5LCB0aGUgd2FsayBmdW5jdGlvbiB3aWxsIGJlIGNhbGxlZCB3aXRoIGFyZ3VtZW50ICJkaXIvYSIuCgogICAgVGhlIGQgYXJndW1lbnQgaXMgdGhlIGZzLkRpckVudHJ5IGZvciB0aGUgbmFtZWQgcGF0aC4KCiAgICBUaGUgZXJyb3IgcmVzdWx0IHJldHVybmVkIGJ5IHRoZSBmdW5jdGlvbiBjb250cm9scyBob3cgV2Fsa0RpciBjb250aW51ZXMuCiAgICBJZiB0aGUgZnVuY3Rpb24gcmV0dXJucyB0aGUgc3BlY2lhbCB2YWx1ZSBTa2lwRGlyLCBXYWxrRGlyIHNraXBzIHRoZSBjdXJyZW50CiAgICBkaXJlY3RvcnkgKHBhdGggaWYgZC5Jc0RpcigpIGlzIHRydWUsIG90aGVyd2lzZSBwYXRoJ3MgcGFyZW50IGRpcmVjdG9yeSkuIElmCiAgICB0aGUgZnVuY3Rpb24gcmV0dXJucyB0aGUgc3BlY2lhbCB2YWx1ZSBTa2lwQWxsLCBXYWxrRGlyIHNraXBzIGFsbCByZW1haW5pbmcKICAgIGZpbGVzIGFuZCBkaXJlY3Rvcmllcy4gT3RoZXJ3aXNlLCBpZiB0aGUgZnVuY3Rpb24gcmV0dXJucyBhIG5vbi1uaWwgZXJyb3IsCiAgICBXYWxrRGlyIHN0b3BzIGVudGlyZWx5IGFuZCByZXR1cm5zIHRoYXQgZXJyb3IuCgogICAgVGhlIGVyciBhcmd1bWVudCByZXBvcnRzIGFuIGVycm9yIHJlbGF0ZWQgdG8gcGF0aCwgc2lnbmFsaW5nIHRoYXQgV2Fsa0RpcgogICAgd2lsbCBub3Qgd2FsayBpbnRvIHRoYXQgZGlyZWN0b3J5LiBUaGUgZnVuY3Rpb24gY2FuIGRlY2lkZSBob3cgdG8gaGFuZGxlCiAgICB0aGF0IGVycm9yOyBhcyBkZXNjcmliZWQgZWFybGllciwgcmV0dXJuaW5nIHRoZSBlcnJvciB3aWxsIGNhdXNlIFdhbGtEaXIgdG8KICAgIHN0b3Agd2Fsa2luZyB0aGUgZW50aXJlIHRyZWUuCgogICAgV2Fsa0RpciBjYWxscyB0aGUgZnVuY3Rpb24gd2l0aCBhIG5vbi1uaWwgZXJyIGFyZ3VtZW50IGluIHR3byBjYXNlcy4KCiAgICBGaXJzdCwgaWYgdGhlIGluaXRpYWwgZnMuU3RhdCBvbiB0aGUgcm9vdCBkaXJlY3RvcnkgZmFpbHMsIFdhbGtEaXIgY2FsbHMgdGhlCiAgICBmdW5jdGlvbiB3aXRoIHBhdGggc2V0IHRvIHJvb3QsIGQgc2V0IHRvIG5pbCwgYW5kIGVyciBzZXQgdG8gdGhlIGVycm9yIGZyb20KICAgIGZzLlN0YXQuCgogICAgU2Vjb25kLCBpZiBhIGRpcmVjdG9yeSdzIFJlYWREaXIgbWV0aG9kIGZhaWxzLCBXYWxrRGlyIGNhbGxzIHRoZSBmdW5jdGlvbgogICAgd2l0aCBwYXRoIHNldCB0byB0aGUgZGlyZWN0b3J5J3MgcGF0aCwgZCBzZXQgdG8gYW4gZnMuRGlyRW50cnkgZGVzY3JpYmluZwogICAgdGhlIGRpcmVjdG9yeSwgYW5kIGVyciBzZXQgdG8gdGhlIGVycm9yIGZyb20gUmVhZERpci4gSW4gdGhpcyBzZWNvbmQgY2FzZSwKICAgIHRoZSBmdW5jdGlvbiBpcyBjYWxsZWQgdHdpY2Ugd2l0aCB0aGUgcGF0aCBvZiB0aGUgZGlyZWN0b3J5OiB0aGUgZmlyc3QKICAgIGNhbGwgaXMgYmVmb3JlIHRoZSBkaXJlY3RvcnkgcmVhZCBpcyBhdHRlbXB0ZWQgYW5kIGhhcyBlcnIgc2V0IHRvIG5pbCwKICAgIGdpdmluZyB0aGUgZnVuY3Rpb24gYSBjaGFuY2UgdG8gcmV0dXJuIFNraXBEaXIgb3IgU2tpcEFsbCBhbmQgYXZvaWQgdGhlCiAgICBSZWFkRGlyIGVudGlyZWx5LiBUaGUgc2Vjb25kIGNhbGwgaXMgYWZ0ZXIgYSBmYWlsZWQgUmVhZERpciBhbmQgcmVwb3J0cyB0aGUKICAgIGVycm9yIGZyb20gUmVhZERpci4gKElmIFJlYWREaXIgc3VjY2VlZHMsIHRoZXJlIGlzIG5vIHNlY29uZCBjYWxsLikKCiAgICBUaGUgZGlmZmVyZW5jZXMgYmV0d2VlbiBXYWxrRGlyRnVuYyBjb21wYXJlZCB0byBmaWxlcGF0aC5XYWxrRnVuYyBhcmU6CgogICAgICAtIFRoZSBzZWNvbmQgYXJndW1lbnQgaGFzIHR5cGUgZnMuRGlyRW50cnkgaW5zdGVhZCBvZiBmcy5GaWxlSW5mby4KICAgICAgLSBUaGUgZnVuY3Rpb24gaXMgY2FsbGVkIGJlZm9yZSByZWFkaW5nIGEgZGlyZWN0b3J5LCB0byBhbGxvdyBTa2lwRGlyCiAgICAgICAgb3IgU2tpcEFsbCB0byBieXBhc3MgdGhlIGRpcmVjdG9yeSByZWFkIGVudGlyZWx5IG9yIHNraXAgYWxsIHJlbWFpbmluZwogICAgICAgIGZpbGVzIGFuZCBkaXJlY3RvcmllcyByZXNwZWN0aXZlbHkuCiAgICAgIC0gSWYgYSBkaXJlY3RvcnkgcmVhZCBmYWlscywgdGhlIGZ1bmN0aW9uIGlzIGNhbGxlZCBhIHNlY29uZCB0aW1lIGZvciB0aGF0CiAgICAgICAgZGlyZWN0b3J5IHRvIHJlcG9ydCB0aGUgZXJyb3Iu", - "duration": 348876750, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc fs.WalkDirFunc\n\npackage fs // import \u0026#34;io/fs\u0026#34;\n\ntype WalkDirFunc func(path string, d DirEntry, err error) error\n WalkDirFunc is the type of the function called by WalkDir to visit each file\n or directory.\n\n The path argument contains the argument to WalkDir as a prefix. That is,\n if WalkDir is called with root argument \u0026#34;dir\u0026#34; and finds a file named \u0026#34;a\u0026#34; in\n that directory, the walk function will be called with argument \u0026#34;dir/a\u0026#34;.\n\n The d argument is the fs.DirEntry for the named path.\n\n The error result returned by the function controls how WalkDir continues.\n If the function returns the special value SkipDir, WalkDir skips the current\n directory (path if d.IsDir() is true, otherwise path\u0026#39;s parent directory). If\n the function returns the special value SkipAll, WalkDir skips all remaining\n files and directories. Otherwise, if the function returns a non-nil error,\n WalkDir stops entirely and returns that error.\n\n The err argument reports an error related to path, signaling that WalkDir\n will not walk into that directory. The function can decide how to handle\n that error; as described earlier, returning the error will cause WalkDir to\n stop walking the entire tree.\n\n WalkDir calls the function with a non-nil err argument in two cases.\n\n First, if the initial fs.Stat on the root directory fails, WalkDir calls the\n function with path set to root, d set to nil, and err set to the error from\n fs.Stat.\n\n Second, if a directory\u0026#39;s ReadDir method fails, WalkDir calls the function\n with path set to the directory\u0026#39;s path, d set to an fs.DirEntry describing\n the directory, and err set to the error from ReadDir. In this second case,\n the function is called twice with the path of the directory: the first\n call is before the directory read is attempted and has err set to nil,\n giving the function a chance to return SkipDir or SkipAll and avoid the\n ReadDir entirely. The second call is after a failed ReadDir and reports the\n error from ReadDir. (If ReadDir succeeds, there is no second call.)\n\n The differences between WalkDirFunc compared to filepath.WalkFunc are:\n\n - The second argument has type fs.DirEntry instead of fs.FileInfo.\n - The function is called before reading a directory, to allow SkipDir\n or SkipAll to bypass the directory read entirely or skip all remaining\n files and directories respectively.\n - If a directory read fails, the function is called a second time for that\n directory to report the error.", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "fs.WalkDirFunc" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBmcyAvLyBpbXBvcnQgImlvL2ZzIgoKdHlwZSBXYWxrRGlyRnVuYyBmdW5jKHBhdGggc3RyaW5nLCBkIERpckVudHJ5LCBlcnIgZXJyb3IpIGVycm9yCiAgICBXYWxrRGlyRnVuYyBpcyB0aGUgdHlwZSBvZiB0aGUgZnVuY3Rpb24gY2FsbGVkIGJ5IFdhbGtEaXIgdG8gdmlzaXQgZWFjaCBmaWxlCiAgICBvciBkaXJlY3RvcnkuCgogICAgVGhlIHBhdGggYXJndW1lbnQgY29udGFpbnMgdGhlIGFyZ3VtZW50IHRvIFdhbGtEaXIgYXMgYSBwcmVmaXguIFRoYXQgaXMsCiAgICBpZiBXYWxrRGlyIGlzIGNhbGxlZCB3aXRoIHJvb3QgYXJndW1lbnQgImRpciIgYW5kIGZpbmRzIGEgZmlsZSBuYW1lZCAiYSIgaW4KICAgIHRoYXQgZGlyZWN0b3J5LCB0aGUgd2FsayBmdW5jdGlvbiB3aWxsIGJlIGNhbGxlZCB3aXRoIGFyZ3VtZW50ICJkaXIvYSIuCgogICAgVGhlIGQgYXJndW1lbnQgaXMgdGhlIGZzLkRpckVudHJ5IGZvciB0aGUgbmFtZWQgcGF0aC4KCiAgICBUaGUgZXJyb3IgcmVzdWx0IHJldHVybmVkIGJ5IHRoZSBmdW5jdGlvbiBjb250cm9scyBob3cgV2Fsa0RpciBjb250aW51ZXMuCiAgICBJZiB0aGUgZnVuY3Rpb24gcmV0dXJucyB0aGUgc3BlY2lhbCB2YWx1ZSBTa2lwRGlyLCBXYWxrRGlyIHNraXBzIHRoZSBjdXJyZW50CiAgICBkaXJlY3RvcnkgKHBhdGggaWYgZC5Jc0RpcigpIGlzIHRydWUsIG90aGVyd2lzZSBwYXRoJ3MgcGFyZW50IGRpcmVjdG9yeSkuIElmCiAgICB0aGUgZnVuY3Rpb24gcmV0dXJucyB0aGUgc3BlY2lhbCB2YWx1ZSBTa2lwQWxsLCBXYWxrRGlyIHNraXBzIGFsbCByZW1haW5pbmcKICAgIGZpbGVzIGFuZCBkaXJlY3Rvcmllcy4gT3RoZXJ3aXNlLCBpZiB0aGUgZnVuY3Rpb24gcmV0dXJucyBhIG5vbi1uaWwgZXJyb3IsCiAgICBXYWxrRGlyIHN0b3BzIGVudGlyZWx5IGFuZCByZXR1cm5zIHRoYXQgZXJyb3IuCgogICAgVGhlIGVyciBhcmd1bWVudCByZXBvcnRzIGFuIGVycm9yIHJlbGF0ZWQgdG8gcGF0aCwgc2lnbmFsaW5nIHRoYXQgV2Fsa0RpcgogICAgd2lsbCBub3Qgd2FsayBpbnRvIHRoYXQgZGlyZWN0b3J5LiBUaGUgZnVuY3Rpb24gY2FuIGRlY2lkZSBob3cgdG8gaGFuZGxlCiAgICB0aGF0IGVycm9yOyBhcyBkZXNjcmliZWQgZWFybGllciwgcmV0dXJuaW5nIHRoZSBlcnJvciB3aWxsIGNhdXNlIFdhbGtEaXIgdG8KICAgIHN0b3Agd2Fsa2luZyB0aGUgZW50aXJlIHRyZWUuCgogICAgV2Fsa0RpciBjYWxscyB0aGUgZnVuY3Rpb24gd2l0aCBhIG5vbi1uaWwgZXJyIGFyZ3VtZW50IGluIHR3byBjYXNlcy4KCiAgICBGaXJzdCwgaWYgdGhlIGluaXRpYWwgZnMuU3RhdCBvbiB0aGUgcm9vdCBkaXJlY3RvcnkgZmFpbHMsIFdhbGtEaXIgY2FsbHMgdGhlCiAgICBmdW5jdGlvbiB3aXRoIHBhdGggc2V0IHRvIHJvb3QsIGQgc2V0IHRvIG5pbCwgYW5kIGVyciBzZXQgdG8gdGhlIGVycm9yIGZyb20KICAgIGZzLlN0YXQuCgogICAgU2Vjb25kLCBpZiBhIGRpcmVjdG9yeSdzIFJlYWREaXIgbWV0aG9kIGZhaWxzLCBXYWxrRGlyIGNhbGxzIHRoZSBmdW5jdGlvbgogICAgd2l0aCBwYXRoIHNldCB0byB0aGUgZGlyZWN0b3J5J3MgcGF0aCwgZCBzZXQgdG8gYW4gZnMuRGlyRW50cnkgZGVzY3JpYmluZwogICAgdGhlIGRpcmVjdG9yeSwgYW5kIGVyciBzZXQgdG8gdGhlIGVycm9yIGZyb20gUmVhZERpci4gSW4gdGhpcyBzZWNvbmQgY2FzZSwKICAgIHRoZSBmdW5jdGlvbiBpcyBjYWxsZWQgdHdpY2Ugd2l0aCB0aGUgcGF0aCBvZiB0aGUgZGlyZWN0b3J5OiB0aGUgZmlyc3QKICAgIGNhbGwgaXMgYmVmb3JlIHRoZSBkaXJlY3RvcnkgcmVhZCBpcyBhdHRlbXB0ZWQgYW5kIGhhcyBlcnIgc2V0IHRvIG5pbCwKICAgIGdpdmluZyB0aGUgZnVuY3Rpb24gYSBjaGFuY2UgdG8gcmV0dXJuIFNraXBEaXIgb3IgU2tpcEFsbCBhbmQgYXZvaWQgdGhlCiAgICBSZWFkRGlyIGVudGlyZWx5LiBUaGUgc2Vjb25kIGNhbGwgaXMgYWZ0ZXIgYSBmYWlsZWQgUmVhZERpciBhbmQgcmVwb3J0cyB0aGUKICAgIGVycm9yIGZyb20gUmVhZERpci4gKElmIFJlYWREaXIgc3VjY2VlZHMsIHRoZXJlIGlzIG5vIHNlY29uZCBjYWxsLikKCiAgICBUaGUgZGlmZmVyZW5jZXMgYmV0d2VlbiBXYWxrRGlyRnVuYyBjb21wYXJlZCB0byBmaWxlcGF0aC5XYWxrRnVuYyBhcmU6CgogICAgICAtIFRoZSBzZWNvbmQgYXJndW1lbnQgaGFzIHR5cGUgZnMuRGlyRW50cnkgaW5zdGVhZCBvZiBmcy5GaWxlSW5mby4KICAgICAgLSBUaGUgZnVuY3Rpb24gaXMgY2FsbGVkIGJlZm9yZSByZWFkaW5nIGEgZGlyZWN0b3J5LCB0byBhbGxvdyBTa2lwRGlyCiAgICAgICAgb3IgU2tpcEFsbCB0byBieXBhc3MgdGhlIGRpcmVjdG9yeSByZWFkIGVudGlyZWx5IG9yIHNraXAgYWxsIHJlbWFpbmluZwogICAgICAgIGZpbGVzIGFuZCBkaXJlY3RvcmllcyByZXNwZWN0aXZlbHkuCiAgICAgIC0gSWYgYSBkaXJlY3RvcnkgcmVhZCBmYWlscywgdGhlIGZ1bmN0aW9uIGlzIGNhbGxlZCBhIHNlY29uZCB0aW1lIGZvciB0aGF0CiAgICAgICAgZGlyZWN0b3J5IHRvIHJlcG9ydCB0aGUgZXJyb3Iu", - "duration": 348876750, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "walk", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.12:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "io/fs#WalkDirFunc", - "href": "https://pkg.go.dev/io/fs#WalkDirFunc", - "target": "_blank" - }, - "file": "walk", - "nodes": [ - [ - { - "atom": "code", - "file": "walk", - "nodes": [ - { - "text": "fs.WalkDirFunc", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/io/fs#WalkDirFunc" - } - ], - { - "text": " function.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 12, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "walk.md", - "nodes": [ - { - "text": "Consider ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-13" - }, - "file": "walk.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-13" - }, - "nodes": [ - { - "text": "Listing 1.13", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-13" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", in which we walk through the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "walk.md", - "nodes": [ - { - "text": "data", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " directory. For each file and directory, including the root directory, the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "filepath#WalkFunc", - "href": "https://pkg.go.dev/filepath#WalkFunc", - "target": "_blank" - }, - "file": "walk.md", - "nodes": [ - { - "atom": "code", - "file": "walk.md", - "nodes": [ - { - "text": "filepath.WalkFunc", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/filepath#WalkFunc" - } - ], - { - "text": " will be called.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-13", - "type": "listing" - }, - "file": "walk.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "walk", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "walk/src/tree/main.go#main" - }, - "lang": "go", - "nodes": [ - { - "content": "func main() {\n\terr := filepath.WalkDir(\"data\", func(path string, d fs.DirEntry, err error) error {\n\n\t\t// if there was an error, return it\n\t\t// if there is an error, it is most likely\n\t\t// because an error was an encoutered trying\n\t\t// to read the top level directory\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\t// if the file is a directory\n\t\t// return nil to tell walk to continue\n\t\t// walking the directory,\n\t\t// but to no longer continue\n\t\t// operating on the directory itself\n\t\tif d.IsDir() {\n\t\t\treturn nil\n\t\t}\n\n\t\t// get the file info for the file\n\t\tinfo, err := d.Info()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\t// if the file is not a directory\n\t\t// the print its mode, size, and path\n\t\tfmt.Printf(\"%s\\t%d\\t%s\\n\", info.Mode(), info.Size(), path)\n\n\t\t// return nil to tell walk to continue\n\t\treturn nil\n\t})\n\n\tif err != nil {\n\t\tfmt.Println(err)\n\t\tos.Exit(1)\n\t}\n}", - "file": "walk/src/tree/main.go", - "lang": "go", - "name": "main", - "start": 10, - "end": 51, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "walk", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.13:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Using ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "filepath#WalkDir", - "href": "https://pkg.go.dev/filepath#WalkDir", - "target": "_blank" - }, - "file": "walk", - "nodes": [ - [ - { - "atom": "code", - "file": "walk", - "nodes": [ - { - "text": "filepath.WalkDir", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/filepath#WalkDir" - } - ], - { - "text": " to recurse a directory.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 13, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "walk.md", - "nodes": [ - { - "text": "First, we need to check the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "walk.md", - "nodes": [ - { - "text": "error", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " that is passed in via the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "filepath#WalkFunc", - "href": "https://pkg.go.dev/filepath#WalkFunc", - "target": "_blank" - }, - "file": "walk.md", - "nodes": [ - { - "atom": "code", - "file": "walk.md", - "nodes": [ - { - "text": "filepath.WalkFunc", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/filepath#WalkFunc" - } - ], - { - "text": " function. If this error is not ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "walk.md", - "nodes": [ - { - "text": "nil", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ", it is most likely that the root directory could not be read. In this case, we can simply return the error and the walk will stop.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "walk.md", - "nodes": [ - { - "text": "If there is no error, we can then check to see if what we're dealing with is a directory or a file. If it is a directory, we can simply return ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "walk.md", - "nodes": [ - { - "text": "nil", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " to indicate that we don't want to continue processing directory itself, but walking of the directory will continue. The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "io/fs#DirEntry.IsDir", - "href": "https://pkg.go.dev/io/fs#DirEntry.IsDir", - "target": "_blank" - }, - "file": "walk.md", - "nodes": [ - { - "atom": "code", - "file": "walk.md", - "nodes": [ - { - "text": "fs.DirEntry.IsDir", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/io/fs#DirEntry.IsDir" - } - ], - { - "text": " method can be used to check this, return ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "walk.md", - "nodes": [ - { - "text": "true", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " for a directory, and ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "walk.md", - "nodes": [ - { - "text": "false", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " for a file.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "walk.md", - "nodes": [ - { - "text": "Finally, we print off the mode, size, and path of the file.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "walk.md", - "nodes": [ - { - "text": "As we can see from ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-14" - }, - "file": "walk.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-14" - }, - "nodes": [ - { - "text": "Listing 1.14", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-14" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", the walk function is called for each file and directory in the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "walk.md", - "nodes": [ - { - "text": "data", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " directory. Printing out the file information is lexical order, which is the order in which the files and directories are listed in the directory.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-14", - "type": "listing" - }, - "file": "walk.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "run", - "." - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go run .", - "run": ".", - "src": "walk/src/tree" - }, - "expected_exit": 0, - "file": "walk", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\n-rw-r--r--\t31\tdata/.hidden/d.txt\n-rw-r--r--\t31\tdata/a.txt\n-rw-r--r--\t9\tdata/b.txt\n-rw-r--r--\t31\tdata/e/f/_ignore/i.json\n-rw-r--r--\t31\tdata/e/f/g.txt\n-rw-r--r--\t31\tdata/e/f/h.txt\n-rw-r--r--\t9\tdata/e/j.txt\n-rw-r--r--\t31\tdata/testdata/c.txt", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/14-files/walk/src/tree", - "stdout": "LXJ3LXItLXItLQkzMQlkYXRhLy5oaWRkZW4vZC50eHQKLXJ3LXItLXItLQkzMQlkYXRhL2EudHh0Ci1ydy1yLS1yLS0JOQlkYXRhL2IudHh0Ci1ydy1yLS1yLS0JMzEJZGF0YS9lL2YvX2lnbm9yZS9pLmpzb24KLXJ3LXItLXItLQkzMQlkYXRhL2UvZi9nLnR4dAotcnctci0tci0tCTMxCWRhdGEvZS9mL2gudHh0Ci1ydy1yLS1yLS0JOQlkYXRhL2Uvai50eHQKLXJ3LXItLXItLQkzMQlkYXRhL3Rlc3RkYXRhL2MudHh0", - "duration": 1091086000, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\n-rw-r--r--\t31\tdata/.hidden/d.txt\n-rw-r--r--\t31\tdata/a.txt\n-rw-r--r--\t9\tdata/b.txt\n-rw-r--r--\t31\tdata/e/f/_ignore/i.json\n-rw-r--r--\t31\tdata/e/f/g.txt\n-rw-r--r--\t31\tdata/e/f/h.txt\n-rw-r--r--\t9\tdata/e/j.txt\n-rw-r--r--\t31\tdata/testdata/c.txt", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/14-files/walk/src/tree", - "stdout": "LXJ3LXItLXItLQkzMQlkYXRhLy5oaWRkZW4vZC50eHQKLXJ3LXItLXItLQkzMQlkYXRhL2EudHh0Ci1ydy1yLS1yLS0JOQlkYXRhL2IudHh0Ci1ydy1yLS1yLS0JMzEJZGF0YS9lL2YvX2lnbm9yZS9pLmpzb24KLXJ3LXItLXItLQkzMQlkYXRhL2UvZi9nLnR4dAotcnctci0tci0tCTMxCWRhdGEvZS9mL2gudHh0Ci1ydy1yLS1yLS0JOQlkYXRhL2Uvai50eHQKLXJ3LXItLXItLQkzMQlkYXRhL3Rlc3RkYXRhL2MudHh0", - "duration": 1091086000, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "walk", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.14:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The output of ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-13" - }, - "file": "walk", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-13" - }, - "nodes": [ - { - "text": "Listing 1.13", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-13" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 14, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "title": "Walking Directories", - "type": "*hype.Page" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "type": "*hype.Include" - } - ], - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "include", - "attributes": { - "src": "skip/skip.md" - }, - "dir": "skip", - "file": "module.md", - "nodes": [ - [ - { - "atom": "page", - "file": "skip.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "h1", - "file": "skip.md", - "level": 1, - "nodes": [ - { - "text": "Skipping Directories and Files", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "skip.md", - "nodes": [ - { - "text": "When walking through a directory tree, you may want to skip certain directories and files. For example, we may want to skip hidden folders like ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "skip.md", - "nodes": [ - { - "text": ".git", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " and ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "skip.md", - "nodes": [ - { - "text": ".vscode", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " or skip large folders such as ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "skip.md", - "nodes": [ - { - "text": "node_modules", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ". There may be other reasons to skip certain files and directories that are more specific to your application.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "skip.md", - "nodes": [ - { - "text": "To illustrate this, let's look at the excerpt from the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "skip.md", - "nodes": [ - { - "text": "go help test", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " command in ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-15" - }, - "file": "skip.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-15" - }, - "nodes": [ - { - "text": "Listing 1.15", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-15" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-15", - "type": "listing" - }, - "file": "skip.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "skip", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-plain", - "language": "plain" - }, - "file": "skip", - "lang": "plain", - "nodes": [ - { - "text": "Files whose names begin with \"_\" (including \"_test.go\") or \".\" are ignored.\n\nThe go tool will ignore a directory named \"testdata\", making it available\nto hold ancillary data needed by the tests.\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "skip", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.15:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Excerpt from the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "skip", - "nodes": [ - { - "text": "go help test", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " command.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 15, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "skip.md", - "nodes": [ - { - "text": "The documentation in ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-15" - }, - "file": "skip.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-15" - }, - "nodes": [ - { - "text": "Listing 1.15", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-15" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": " tells us that there are certain files and directories that Go will ignore when walking through a directory tree looking for test files.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "ul", - "file": "skip.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "li", - "file": "skip.md", - "list-type": "ul", - "nodes": [ - { - "text": "Files/Dirs whose names begin with ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "skip.md", - "nodes": [ - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " are ignored.", - "type": "hype.Text" - } - ], - "type": "*hype.LI" - } - ], - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "li", - "file": "skip.md", - "list-type": "ul", - "nodes": [ - { - "text": "Files/Dirs whose names begin with ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "skip.md", - "nodes": [ - { - "text": "_", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " are ignored.", - "type": "hype.Text" - } - ], - "type": "*hype.LI" - } - ], - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "li", - "file": "skip.md", - "list-type": "ul", - "nodes": [ - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "skip.md", - "nodes": [ - { - "text": "testdata", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " directory is ignored.", - "type": "hype.Text" - } - ], - "type": "*hype.LI" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "type": "*hype.UL" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "skip.md", - "nodes": [ - { - "text": "Let's implement these same restrictions in our own code.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "skip.md", - "level": 2, - "nodes": [ - { - "text": "Skipping Directories", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "skip.md", - "nodes": [ - { - "text": "In order to tell Go to skip a directory, we can return ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "io/fs#SkipDir", - "href": "https://pkg.go.dev/io/fs#SkipDir", - "target": "_blank" - }, - "file": "skip.md", - "nodes": [ - { - "atom": "code", - "file": "skip.md", - "nodes": [ - { - "text": "fs.SkipDir", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/io/fs#SkipDir" - } - ], - { - "text": ", ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-16" - }, - "file": "skip.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-16" - }, - "nodes": [ - { - "text": "Listing 1.16", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-16" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", from our ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "io/fs#WalkFunc", - "href": "https://pkg.go.dev/io/fs#WalkFunc", - "target": "_blank" - }, - "file": "skip.md", - "nodes": [ - { - "atom": "code", - "file": "skip.md", - "nodes": [ - { - "text": "fs.WalkFunc", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/io/fs#WalkFunc" - } - ], - { - "text": " function. While technically this is an ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "builtin#error", - "href": "https://pkg.go.dev/builtin#error", - "target": "_blank" - }, - "file": "skip.md", - "nodes": [ - { - "atom": "code", - "file": "skip.md", - "nodes": [ - { - "text": "error", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/builtin#error" - } - ], - { - "text": " type, Go is using this error as a sentinel value to indicate that the directory should be skipped. This is similar to how ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "io#EOF", - "href": "https://pkg.go.dev/io#EOF", - "target": "_blank" - }, - "file": "skip.md", - "nodes": [ - { - "atom": "code", - "file": "skip.md", - "nodes": [ - { - "text": "io.EOF", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/io#EOF" - } - ], - { - "text": " is used to indicated that the end of a file has been reached and there is no more data to be read.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-16", - "type": "listing" - }, - "file": "skip.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "doc", - "fs.SkipDir" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "doc": "fs.SkipDir", - "exec": "go doc fs.SkipDir" - }, - "expected_exit": 0, - "file": "skip", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc fs.SkipDir\n\npackage fs // import \u0026#34;io/fs\u0026#34;\n\nvar SkipDir = errors.New(\u0026#34;skip this directory\u0026#34;)\n SkipDir is used as a return value from WalkDirFuncs to indicate that the\n directory named in the call is to be skipped. It is not returned as an error\n by any function.", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "fs.SkipDir" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBmcyAvLyBpbXBvcnQgImlvL2ZzIgoKdmFyIFNraXBEaXIgPSBlcnJvcnMuTmV3KCJza2lwIHRoaXMgZGlyZWN0b3J5IikKICAgIFNraXBEaXIgaXMgdXNlZCBhcyBhIHJldHVybiB2YWx1ZSBmcm9tIFdhbGtEaXJGdW5jcyB0byBpbmRpY2F0ZSB0aGF0IHRoZQogICAgZGlyZWN0b3J5IG5hbWVkIGluIHRoZSBjYWxsIGlzIHRvIGJlIHNraXBwZWQuIEl0IGlzIG5vdCByZXR1cm5lZCBhcyBhbiBlcnJvcgogICAgYnkgYW55IGZ1bmN0aW9uLg==", - "duration": 982918125, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc fs.SkipDir\n\npackage fs // import \u0026#34;io/fs\u0026#34;\n\nvar SkipDir = errors.New(\u0026#34;skip this directory\u0026#34;)\n SkipDir is used as a return value from WalkDirFuncs to indicate that the\n directory named in the call is to be skipped. It is not returned as an error\n by any function.", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "fs.SkipDir" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBmcyAvLyBpbXBvcnQgImlvL2ZzIgoKdmFyIFNraXBEaXIgPSBlcnJvcnMuTmV3KCJza2lwIHRoaXMgZGlyZWN0b3J5IikKICAgIFNraXBEaXIgaXMgdXNlZCBhcyBhIHJldHVybiB2YWx1ZSBmcm9tIFdhbGtEaXJGdW5jcyB0byBpbmRpY2F0ZSB0aGF0IHRoZQogICAgZGlyZWN0b3J5IG5hbWVkIGluIHRoZSBjYWxsIGlzIHRvIGJlIHNraXBwZWQuIEl0IGlzIG5vdCByZXR1cm5lZCBhcyBhbiBlcnJvcgogICAgYnkgYW55IGZ1bmN0aW9uLg==", - "duration": 982918125, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "skip", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.16:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "io/fs#SkipDir", - "href": "https://pkg.go.dev/io/fs#SkipDir", - "target": "_blank" - }, - "file": "skip", - "nodes": [ - [ - { - "atom": "code", - "file": "skip", - "nodes": [ - { - "text": "fs.SkipDir", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/io/fs#SkipDir" - } - ], - { - "text": " ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "builtin#error", - "href": "https://pkg.go.dev/builtin#error", - "target": "_blank" - }, - "file": "skip", - "nodes": [ - [ - { - "atom": "code", - "file": "skip", - "nodes": [ - { - "text": "error", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/builtin#error" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 16, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "skip.md", - "nodes": [ - { - "text": "In ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-17" - }, - "file": "skip.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-17" - }, - "nodes": [ - { - "text": "Listing 1.17", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-17" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", instead of simply returning a ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "skip.md", - "nodes": [ - { - "text": "nil", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " when the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "io/fs#DirEntry", - "href": "https://pkg.go.dev/io/fs#DirEntry", - "target": "_blank" - }, - "file": "skip.md", - "nodes": [ - { - "atom": "code", - "file": "skip.md", - "nodes": [ - { - "text": "fs.DirEntry", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/io/fs#DirEntry" - } - ], - { - "text": " is a directory, we can check the name of the directory and make a decision on whether to ignore that directory or not. If we want to ignore a directory, ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "skip.md", - "nodes": [ - { - "text": "testdata", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " for example, we can return ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "io/fs#SkipDir", - "href": "https://pkg.go.dev/io/fs#SkipDir", - "target": "_blank" - }, - "file": "skip.md", - "nodes": [ - { - "atom": "code", - "file": "skip.md", - "nodes": [ - { - "text": "fs.SkipDir", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/io/fs#SkipDir" - } - ], - { - "text": " from our ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "io/fs#WalkFunc", - "href": "https://pkg.go.dev/io/fs#WalkFunc", - "target": "_blank" - }, - "file": "skip.md", - "nodes": [ - { - "atom": "code", - "file": "skip.md", - "nodes": [ - { - "text": "fs.WalkFunc", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/io/fs#WalkFunc" - } - ], - { - "text": " function. Go will then skip that directory and all of its children.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-17", - "type": "listing" - }, - "file": "skip.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "skip", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "skip/src/tree/demo.go" - }, - "lang": "go", - "nodes": [ - { - "text": "package demo\n\nimport (\n\t\u0026#34;io/fs\u0026#34;\n\t\u0026#34;path/filepath\u0026#34;\n\t\u0026#34;strings\u0026#34;\n)\n\nfunc Walk() ([]string, error) {\n\tvar entries []string\n\n\terr := filepath.WalkDir(\u0026#34;data\u0026#34;, func(path string, d fs.DirEntry, err error) error {\n\n\t\t// if there was an error, return it\n\t\t// if there is an error, it is most likely\n\t\t// because an error was an encoutered trying\n\t\t// to read the top level directory\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\t// if the entry is a directory, handle it\n\t\tif d.IsDir() {\n\n\t\t\t// name of the file or directory\n\t\t\tname := d.Name()\n\n\t\t\t// if the directory is a dot return nil\n\t\t\t// this may be the root directory\n\t\t\tif name == \u0026#34;.\u0026#34; || name == \u0026#34;..\u0026#34; {\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\t\t// if the directory name is \u0026#34;testdata\u0026#34;\n\t\t\t// or it starts with \u0026#34;.\u0026#34;\n\t\t\t// or it starts with \u0026#34;_\u0026#34;\n\t\t\t// then return filepath.SkipDir\n\t\t\tif name == \u0026#34;testdata\u0026#34; || strings.HasPrefix(name, \u0026#34;.\u0026#34;) || strings.HasPrefix(name, \u0026#34;_\u0026#34;) {\n\t\t\t\treturn fs.SkipDir\n\t\t\t}\n\n\t\t\treturn nil\n\t\t}\n\n\t\t// append the entry to the list\n\t\tentries = append(entries, path)\n\n\t\t// return nil to tell walk to continue\n\t\treturn nil\n\t})\n\n\treturn entries, err\n}\n\n", - "type": "hype.Text" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "skip", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.17:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Using ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "io/fs#SkipDir", - "href": "https://pkg.go.dev/io/fs#SkipDir", - "target": "_blank" - }, - "file": "skip", - "nodes": [ - [ - { - "atom": "code", - "file": "skip", - "nodes": [ - { - "text": "fs.SkipDir", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/io/fs#SkipDir" - } - ], - { - "text": " to skip directories.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 17, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "skip.md", - "nodes": [ - { - "text": "Next, in ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-18" - }, - "file": "skip.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-18" - }, - "nodes": [ - { - "text": "Listing 1.18", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-18" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", we can write a small test that asserts that the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "skip.md", - "nodes": [ - { - "text": "testdata", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " directory, and our other special directories, are skipped.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-18", - "type": "listing" - }, - "file": "skip.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "skip", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "skip/src/tree/demo_test.go#test" - }, - "lang": "go", - "nodes": [ - { - "content": "func Test_Walk(t *testing.T) {\n\tt.Parallel()\n\n\texp := []string{\n\t\t\"data/a.txt\",\n\t\t\"data/b.txt\",\n\t\t\"data/e/f/g.txt\",\n\t\t\"data/e/f/h.txt\",\n\t\t\"data/e/j.txt\",\n\t}\n\n\tact, err := Walk()\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\tes := strings.Join(exp, \", \")\n\tas := strings.Join(act, \", \")\n\n\tif es != as {\n\t\tt.Fatalf(\"expected %s, got %s\", es, as)\n\t}\n}", - "file": "skip/src/tree/demo_test.go", - "lang": "go", - "name": "test", - "start": 8, - "end": 33, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "atom": "hr", - "file": "skip", - "type": "*hype.Element" - }, - [ - { - "args": [ - "go", - "test", - "-v" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go test -v", - "src": "skip/src/tree", - "test": "-v" - }, - "expected_exit": 0, - "file": "skip", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go test -v\n\n=== RUN Test_Walk\n=== PAUSE Test_Walk\n=== CONT Test_Walk\n--- PASS: Test_Walk (0.00s)\nPASS\nok \tdemo\t0.399s", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "test", - "-v" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/14-files/skip/src/tree", - "stdout": "PT09IFJVTiAgIFRlc3RfV2Fsawo9PT0gUEFVU0UgVGVzdF9XYWxrCj09PSBDT05UICBUZXN0X1dhbGsKLS0tIFBBU1M6IFRlc3RfV2FsayAoMC4wMHMpClBBU1MKb2sgIAlkZW1vCTAuMzk5cw==", - "duration": 1618479417, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go test -v\n\n=== RUN Test_Walk\n=== PAUSE Test_Walk\n=== CONT Test_Walk\n--- PASS: Test_Walk (0.00s)\nPASS\nok \tdemo\t0.399s", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "test", - "-v" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/14-files/skip/src/tree", - "stdout": "PT09IFJVTiAgIFRlc3RfV2Fsawo9PT0gUEFVU0UgVGVzdF9XYWxrCj09PSBDT05UICBUZXN0X1dhbGsKLS0tIFBBU1M6IFRlc3RfV2FsayAoMC4wMHMpClBBU1MKb2sgIAlkZW1vCTAuMzk5cw==", - "duration": 1618479417, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "skip", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.18:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Asserting special directories are skipped.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 18, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "skip.md", - "nodes": [ - { - "text": "Finally, when compared to original file listing, we see that the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "skip.md", - "nodes": [ - { - "text": "testdata", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " directory, along with the other special directories, are no longer included in the file listing.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-19", - "type": "listing" - }, - "file": "skip.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "tree", - "-a" - ], - "atom": "cmd", - "attributes": { - "exec": "tree -a", - "src": "skip/src/tree/data" - }, - "expected_exit": 0, - "file": "skip", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ tree -a\n\n.\n├── .hidden\n│   └── d.txt\n├── a.txt\n├── b.txt\n├── e\n│   ├── f\n│   │   ├── _ignore\n│   │   │   └── i.txt\n│   │   ├── g.txt\n│   │   └── h.txt\n│   └── j.txt\n└── testdata\n └── c.txt\n\n6 directories, 8 files", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "tree", - "-a" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/14-files/skip/src/tree/data", - "stdout": "LgrilJzilIDilIAgLmhpZGRlbgrilILCoMKgIOKUlOKUgOKUgCBkLnR4dArilJzilIDilIAgYS50eHQK4pSc4pSA4pSAIGIudHh0CuKUnOKUgOKUgCBlCuKUgsKgwqAg4pSc4pSA4pSAIGYK4pSCwqDCoCDilILCoMKgIOKUnOKUgOKUgCBfaWdub3JlCuKUgsKgwqAg4pSCwqDCoCDilILCoMKgIOKUlOKUgOKUgCBpLnR4dArilILCoMKgIOKUgsKgwqAg4pSc4pSA4pSAIGcudHh0CuKUgsKgwqAg4pSCwqDCoCDilJTilIDilIAgaC50eHQK4pSCwqDCoCDilJTilIDilIAgai50eHQK4pSU4pSA4pSAIHRlc3RkYXRhCiAgICDilJTilIDilIAgYy50eHQKCjYgZGlyZWN0b3JpZXMsIDggZmlsZXM=", - "duration": 555800291, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ tree -a\n\n.\n├── .hidden\n│   └── d.txt\n├── a.txt\n├── b.txt\n├── e\n│   ├── f\n│   │   ├── _ignore\n│   │   │   └── i.txt\n│   │   ├── g.txt\n│   │   └── h.txt\n│   └── j.txt\n└── testdata\n └── c.txt\n\n6 directories, 8 files", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "tree", - "-a" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/14-files/skip/src/tree/data", - "stdout": "LgrilJzilIDilIAgLmhpZGRlbgrilILCoMKgIOKUlOKUgOKUgCBkLnR4dArilJzilIDilIAgYS50eHQK4pSc4pSA4pSAIGIudHh0CuKUnOKUgOKUgCBlCuKUgsKgwqAg4pSc4pSA4pSAIGYK4pSCwqDCoCDilILCoMKgIOKUnOKUgOKUgCBfaWdub3JlCuKUgsKgwqAg4pSCwqDCoCDilILCoMKgIOKUlOKUgOKUgCBpLnR4dArilILCoMKgIOKUgsKgwqAg4pSc4pSA4pSAIGcudHh0CuKUgsKgwqAg4pSCwqDCoCDilJTilIDilIAgaC50eHQK4pSCwqDCoCDilJTilIDilIAgai50eHQK4pSU4pSA4pSAIHRlc3RkYXRhCiAgICDilJTilIDilIAgYy50eHQKCjYgZGlyZWN0b3JpZXMsIDggZmlsZXM=", - "duration": 555800291, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "skip", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.19:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Original file listing.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 19, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "title": "Skipping Directories and Files", - "type": "*hype.Page" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "type": "*hype.Include" - } - ], - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "include", - "attributes": { - "src": "mkdir/mkdir.md" - }, - "dir": "mkdir", - "file": "module.md", - "nodes": [ - [ - { - "atom": "page", - "file": "mkdir.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "h1", - "file": "mkdir.md", - "level": 1, - "nodes": [ - { - "text": "Creating Directories and Subdirectories", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "mkdir.md", - "nodes": [ - { - "text": "Now that we have a working test suite that asserts our ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "mkdir.md", - "nodes": [ - { - "text": "Walk", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function returns the correct results, we can remove the hard-coded test data we've been using and generate the test data directly inside the test itself.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "mkdir.md", - "nodes": [ - { - "text": "To create a single directory, we can use the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "os#Mkdir", - "href": "https://pkg.go.dev/os#Mkdir", - "target": "_blank" - }, - "file": "mkdir.md", - "nodes": [ - { - "atom": "code", - "file": "mkdir.md", - "nodes": [ - { - "text": "os.Mkdir", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/os#Mkdir" - } - ], - { - "text": " function, ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "os#Mkdir", - "href": "https://pkg.go.dev/os#Mkdir", - "target": "_blank" - }, - "file": "mkdir.md", - "nodes": [ - { - "atom": "code", - "file": "mkdir.md", - "nodes": [ - { - "text": "os.Mkdir", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/os#Mkdir" - } - ], - { - "text": ". The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "os#Mkdir", - "href": "https://pkg.go.dev/os#Mkdir", - "target": "_blank" - }, - "file": "mkdir.md", - "nodes": [ - { - "atom": "code", - "file": "mkdir.md", - "nodes": [ - { - "text": "os.Mkdir", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/os#Mkdir" - } - ], - { - "text": " function creates a single directory at the path specified, and with the specified permissions.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-20", - "type": "listing" - }, - "file": "mkdir.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "doc", - "os.Mkdir" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "doc": "os.Mkdir", - "exec": "go doc os.Mkdir" - }, - "expected_exit": 0, - "file": "mkdir", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc os.Mkdir\n\npackage os // import \u0026#34;os\u0026#34;\n\nfunc Mkdir(name string, perm FileMode) error\n Mkdir creates a new directory with the specified name and permission bits\n (before umask). If there is an error, it will be of type *PathError.", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "os.Mkdir" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBvcyAvLyBpbXBvcnQgIm9zIgoKZnVuYyBNa2RpcihuYW1lIHN0cmluZywgcGVybSBGaWxlTW9kZSkgZXJyb3IKICAgIE1rZGlyIGNyZWF0ZXMgYSBuZXcgZGlyZWN0b3J5IHdpdGggdGhlIHNwZWNpZmllZCBuYW1lIGFuZCBwZXJtaXNzaW9uIGJpdHMKICAgIChiZWZvcmUgdW1hc2spLiBJZiB0aGVyZSBpcyBhbiBlcnJvciwgaXQgd2lsbCBiZSBvZiB0eXBlICpQYXRoRXJyb3Iu", - "duration": 716504166, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc os.Mkdir\n\npackage os // import \u0026#34;os\u0026#34;\n\nfunc Mkdir(name string, perm FileMode) error\n Mkdir creates a new directory with the specified name and permission bits\n (before umask). If there is an error, it will be of type *PathError.", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "os.Mkdir" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBvcyAvLyBpbXBvcnQgIm9zIgoKZnVuYyBNa2RpcihuYW1lIHN0cmluZywgcGVybSBGaWxlTW9kZSkgZXJyb3IKICAgIE1rZGlyIGNyZWF0ZXMgYSBuZXcgZGlyZWN0b3J5IHdpdGggdGhlIHNwZWNpZmllZCBuYW1lIGFuZCBwZXJtaXNzaW9uIGJpdHMKICAgIChiZWZvcmUgdW1hc2spLiBJZiB0aGVyZSBpcyBhbiBlcnJvciwgaXQgd2lsbCBiZSBvZiB0eXBlICpQYXRoRXJyb3Iu", - "duration": 716504166, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "mkdir", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.20:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "os#Mkdir", - "href": "https://pkg.go.dev/os#Mkdir", - "target": "_blank" - }, - "file": "mkdir", - "nodes": [ - [ - { - "atom": "code", - "file": "mkdir", - "nodes": [ - { - "text": "os.Mkdir", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/os#Mkdir" - } - ], - { - "text": " function.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 20, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "mkdir.md", - "nodes": [ - { - "text": "In order to create a directory, we need to provide a set of permissions for the directory. The permissions are specified in the form of an ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "os#FileMode", - "href": "https://pkg.go.dev/os#FileMode", - "target": "_blank" - }, - "file": "mkdir.md", - "nodes": [ - { - "atom": "code", - "file": "mkdir.md", - "nodes": [ - { - "text": "os.FileMode", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/os#FileMode" - } - ], - { - "text": " value, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-21" - }, - "file": "mkdir.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-21" - }, - "nodes": [ - { - "text": "Listing 1.21", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-21" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ". Those familiar with Unix style permissions will feel right at home here being able to use permissions such as ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "mkdir.md", - "nodes": [ - { - "text": "0755", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " to specify the permissions for the directory.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-21", - "type": "listing" - }, - "file": "mkdir.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "doc", - "os.FileMode" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "doc": "os.FileMode", - "exec": "go doc os.FileMode" - }, - "expected_exit": 0, - "file": "mkdir", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc os.FileMode\n\npackage os // import \u0026#34;os\u0026#34;\n\ntype FileMode = fs.FileMode\n A FileMode represents a file\u0026#39;s mode and permission bits. The bits have the\n same definition on all systems, so that information about files can be moved\n from one system to another portably. Not all bits apply to all systems.\n The only required bit is ModeDir for directories.", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "os.FileMode" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBvcyAvLyBpbXBvcnQgIm9zIgoKdHlwZSBGaWxlTW9kZSA9IGZzLkZpbGVNb2RlCiAgICBBIEZpbGVNb2RlIHJlcHJlc2VudHMgYSBmaWxlJ3MgbW9kZSBhbmQgcGVybWlzc2lvbiBiaXRzLiBUaGUgYml0cyBoYXZlIHRoZQogICAgc2FtZSBkZWZpbml0aW9uIG9uIGFsbCBzeXN0ZW1zLCBzbyB0aGF0IGluZm9ybWF0aW9uIGFib3V0IGZpbGVzIGNhbiBiZSBtb3ZlZAogICAgZnJvbSBvbmUgc3lzdGVtIHRvIGFub3RoZXIgcG9ydGFibHkuIE5vdCBhbGwgYml0cyBhcHBseSB0byBhbGwgc3lzdGVtcy4KICAgIFRoZSBvbmx5IHJlcXVpcmVkIGJpdCBpcyBNb2RlRGlyIGZvciBkaXJlY3Rvcmllcy4=", - "duration": 674547459, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc os.FileMode\n\npackage os // import \u0026#34;os\u0026#34;\n\ntype FileMode = fs.FileMode\n A FileMode represents a file\u0026#39;s mode and permission bits. The bits have the\n same definition on all systems, so that information about files can be moved\n from one system to another portably. Not all bits apply to all systems.\n The only required bit is ModeDir for directories.", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "os.FileMode" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBvcyAvLyBpbXBvcnQgIm9zIgoKdHlwZSBGaWxlTW9kZSA9IGZzLkZpbGVNb2RlCiAgICBBIEZpbGVNb2RlIHJlcHJlc2VudHMgYSBmaWxlJ3MgbW9kZSBhbmQgcGVybWlzc2lvbiBiaXRzLiBUaGUgYml0cyBoYXZlIHRoZQogICAgc2FtZSBkZWZpbml0aW9uIG9uIGFsbCBzeXN0ZW1zLCBzbyB0aGF0IGluZm9ybWF0aW9uIGFib3V0IGZpbGVzIGNhbiBiZSBtb3ZlZAogICAgZnJvbSBvbmUgc3lzdGVtIHRvIGFub3RoZXIgcG9ydGFibHkuIE5vdCBhbGwgYml0cyBhcHBseSB0byBhbGwgc3lzdGVtcy4KICAgIFRoZSBvbmx5IHJlcXVpcmVkIGJpdCBpcyBNb2RlRGlyIGZvciBkaXJlY3Rvcmllcy4=", - "duration": 674547459, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "mkdir", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.21:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "os#FileMode", - "href": "https://pkg.go.dev/os#FileMode", - "target": "_blank" - }, - "file": "mkdir", - "nodes": [ - [ - { - "atom": "code", - "file": "mkdir", - "nodes": [ - { - "text": "os.FileMode", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/os#FileMode" - } - ], - { - "text": " type.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 21, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "mkdir.md", - "nodes": [ - { - "text": "In ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-22" - }, - "file": "mkdir.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-22" - }, - "nodes": [ - { - "text": "Listing 1.22", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-22" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": " we can create a helper that will generate all of the files for us. In this helper we first remove any previous test data that may have been left behind from a previous test run, by using the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "os#RemoveAll", - "href": "https://pkg.go.dev/os#RemoveAll", - "target": "_blank" - }, - "file": "mkdir.md", - "nodes": [ - { - "atom": "code", - "file": "mkdir.md", - "nodes": [ - { - "text": "os.RemoveAll", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/os#RemoveAll" - } - ], - { - "text": " function. This will delete the directory at the path specified, and all of its contents, including any subdirectories.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-22", - "type": "listing" - }, - "file": "mkdir.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "mkdir", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "mkdir/src/mkdir/demo_test.go#helper" - }, - "lang": "go", - "nodes": [ - { - "content": "func createTestData(t testing.TB) {\n\tt.Helper()\n\n\t// remove any previous test data\n\tif err := os.RemoveAll(\"data\"); err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\t// create the data directory\n\tif err := os.Mkdir(\"data\", 0755); err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\tlist := []string{\n\t\t\"data/.hidden/d.txt\",\n\t\t\"data/a.txt\",\n\t\t\"data/b.txt\",\n\t\t\"data/e/f/_ignore/i.txt\",\n\t\t\"data/e/f/g.txt\",\n\t\t\"data/e/f/h.txt\",\n\t\t\"data/e/j.txt\",\n\t\t\"data/testdata/c.txt\",\n\t}\n\n\t// create the test data files\n\tfor _, path := range list {\n\t\tfmt.Println(\"creating:\", path)\n\t\tif err := os.Mkdir(path, 0755); err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\n\t}\n\n}", - "file": "mkdir/src/mkdir/demo_test.go", - "lang": "go", - "name": "helper", - "start": 10, - "end": 46, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "mkdir", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.22:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Using ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "os#Mkdir", - "href": "https://pkg.go.dev/os#Mkdir", - "target": "_blank" - }, - "file": "mkdir", - "nodes": [ - [ - { - "atom": "code", - "file": "mkdir", - "nodes": [ - { - "text": "os.Mkdir", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/os#Mkdir" - } - ], - { - "text": " to create directories on disk.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 22, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "mkdir.md", - "nodes": [ - { - "text": "Next we use the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "os#Mkdir", - "href": "https://pkg.go.dev/os#Mkdir", - "target": "_blank" - }, - "file": "mkdir.md", - "nodes": [ - { - "atom": "code", - "file": "mkdir.md", - "nodes": [ - { - "text": "os.Mkdir", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/os#Mkdir" - } - ], - { - "text": " function to create the parent ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "mkdir.md", - "nodes": [ - { - "text": "data", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " directory, giving it the permissions ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "mkdir.md", - "nodes": [ - { - "text": "0755", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " which will allow us to read and write to the directory.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "mkdir.md", - "nodes": [ - { - "text": "Finally, we loop over a list of files and directories that we want to create, and create each one using the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "os#Mkdir", - "href": "https://pkg.go.dev/os#Mkdir", - "target": "_blank" - }, - "file": "mkdir.md", - "nodes": [ - { - "atom": "code", - "file": "mkdir.md", - "nodes": [ - { - "text": "os.Mkdir", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/os#Mkdir" - } - ], - { - "text": " function.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "mkdir.md", - "nodes": [ - { - "text": "As we can see from the test output in ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-23" - }, - "file": "mkdir.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-23" - }, - "nodes": [ - { - "text": "Listing 1.23", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-23" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", this approach isn't working as expected. We run into errors trying to create the necessary files and directories. The biggest problem is that we are trying to use ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "os#Mkdir", - "href": "https://pkg.go.dev/os#Mkdir", - "target": "_blank" - }, - "file": "mkdir.md", - "nodes": [ - { - "atom": "code", - "file": "mkdir.md", - "nodes": [ - { - "text": "os.Mkdir", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/os#Mkdir" - } - ], - { - "text": " to create files instead of directories.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-23", - "type": "listing" - }, - "file": "mkdir.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "test", - "-v" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go test -v", - "exit": "-1", - "src": "mkdir/src/mkdir", - "test": "-v" - }, - "expected_exit": -1, - "file": "mkdir", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go test -v\n\n=== RUN Test_Walk\n=== PAUSE Test_Walk\n=== CONT Test_Walk\ncreating: data/.hidden/d.txt\n demo_test.go:52: mkdir data/.hidden/d.txt: no such file or directory\n--- FAIL: Test_Walk (0.00s)\nFAIL\nexit status 1\nFAIL\tdemo\t0.281s", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "test", - "-v" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/14-files/mkdir/src/mkdir", - "err": { - "Stderr": null - }, - "exit": 1, - "stdout": "PT09IFJVTiAgIFRlc3RfV2Fsawo9PT0gUEFVU0UgVGVzdF9XYWxrCj09PSBDT05UICBUZXN0X1dhbGsKY3JlYXRpbmc6IGRhdGEvLmhpZGRlbi9kLnR4dAogICAgZGVtb190ZXN0LmdvOjUyOiBta2RpciBkYXRhLy5oaWRkZW4vZC50eHQ6IG5vIHN1Y2ggZmlsZSBvciBkaXJlY3RvcnkKLS0tIEZBSUw6IFRlc3RfV2FsayAoMC4wMHMpCkZBSUwKZXhpdCBzdGF0dXMgMQpGQUlMCWRlbW8JMC4yODFz", - "duration": 835126875, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go test -v\n\n=== RUN Test_Walk\n=== PAUSE Test_Walk\n=== CONT Test_Walk\ncreating: data/.hidden/d.txt\n demo_test.go:52: mkdir data/.hidden/d.txt: no such file or directory\n--- FAIL: Test_Walk (0.00s)\nFAIL\nexit status 1\nFAIL\tdemo\t0.281s", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "test", - "-v" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/14-files/mkdir/src/mkdir", - "err": { - "Stderr": null - }, - "exit": 1, - "stdout": "PT09IFJVTiAgIFRlc3RfV2Fsawo9PT0gUEFVU0UgVGVzdF9XYWxrCj09PSBDT05UICBUZXN0X1dhbGsKY3JlYXRpbmc6IGRhdGEvLmhpZGRlbi9kLnR4dAogICAgZGVtb190ZXN0LmdvOjUyOiBta2RpciBkYXRhLy5oaWRkZW4vZC50eHQ6IG5vIHN1Y2ggZmlsZSBvciBkaXJlY3RvcnkKLS0tIEZBSUw6IFRlc3RfV2FsayAoMC4wMHMpCkZBSUwKZXhpdCBzdGF0dXMgMQpGQUlMCWRlbW8JMC4yODFz", - "duration": 835126875, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "mkdir", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.23:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Error using ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "os#Mkdir", - "href": "https://pkg.go.dev/os#Mkdir", - "target": "_blank" - }, - "file": "mkdir", - "nodes": [ - [ - { - "atom": "code", - "file": "mkdir", - "nodes": [ - { - "text": "os.Mkdir", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/os#Mkdir" - } - ], - { - "text": " to create files.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 23, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "title": "Creating Directories and Subdirectories", - "type": "*hype.Page" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "type": "*hype.Include" - } - ], - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "include", - "attributes": { - "src": "fphelpers/fphelpers.md" - }, - "dir": "fphelpers", - "file": "module.md", - "nodes": [ - [ - { - "atom": "page", - "file": "fphelpers.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "h1", - "file": "fphelpers.md", - "level": 1, - "nodes": [ - { - "text": "File Path Helpers", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "fphelpers.md", - "nodes": [ - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "filepath", - "href": "https://pkg.go.dev/filepath", - "target": "_blank" - }, - "file": "fphelpers.md", - "nodes": [ - { - "atom": "code", - "file": "fphelpers.md", - "nodes": [ - { - "text": "filepath", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/filepath" - } - ], - { - "text": " package, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-24" - }, - "file": "fphelpers.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-24" - }, - "nodes": [ - { - "text": "Listing 1.24", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-24" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", provides a number of functions that help us manipulate file paths.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-24", - "type": "listing" - }, - "file": "fphelpers.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "doc", - "-short", - "filepath" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "doc": "-short filepath", - "exec": "go doc -short filepath" - }, - "expected_exit": 0, - "file": "fphelpers", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc -short filepath\n\nconst Separator = os.PathSeparator ...\nvar ErrBadPattern = errors.New(\u0026#34;syntax error in pattern\u0026#34;)\nvar SkipAll error = fs.SkipAll\nvar SkipDir error = fs.SkipDir\nfunc Abs(path string) (string, error)\nfunc Base(path string) string\nfunc Clean(path string) string\nfunc Dir(path string) string\nfunc EvalSymlinks(path string) (string, error)\nfunc Ext(path string) string\nfunc FromSlash(path string) string\nfunc Glob(pattern string) (matches []string, err error)\nfunc HasPrefix(p, prefix string) bool\nfunc IsAbs(path string) bool\nfunc IsLocal(path string) bool\nfunc Join(elem ...string) string\nfunc Match(pattern, name string) (matched bool, err error)\nfunc Rel(basepath, targpath string) (string, error)\nfunc Split(path string) (dir, file string)\nfunc SplitList(path string) []string\nfunc ToSlash(path string) string\nfunc VolumeName(path string) string\nfunc Walk(root string, fn WalkFunc) error\nfunc WalkDir(root string, fn fs.WalkDirFunc) error\ntype WalkFunc func(path string, info fs.FileInfo, err error) error", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "-short", - "filepath" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "Y29uc3QgU2VwYXJhdG9yID0gb3MuUGF0aFNlcGFyYXRvciAuLi4KdmFyIEVyckJhZFBhdHRlcm4gPSBlcnJvcnMuTmV3KCJzeW50YXggZXJyb3IgaW4gcGF0dGVybiIpCnZhciBTa2lwQWxsIGVycm9yID0gZnMuU2tpcEFsbAp2YXIgU2tpcERpciBlcnJvciA9IGZzLlNraXBEaXIKZnVuYyBBYnMocGF0aCBzdHJpbmcpIChzdHJpbmcsIGVycm9yKQpmdW5jIEJhc2UocGF0aCBzdHJpbmcpIHN0cmluZwpmdW5jIENsZWFuKHBhdGggc3RyaW5nKSBzdHJpbmcKZnVuYyBEaXIocGF0aCBzdHJpbmcpIHN0cmluZwpmdW5jIEV2YWxTeW1saW5rcyhwYXRoIHN0cmluZykgKHN0cmluZywgZXJyb3IpCmZ1bmMgRXh0KHBhdGggc3RyaW5nKSBzdHJpbmcKZnVuYyBGcm9tU2xhc2gocGF0aCBzdHJpbmcpIHN0cmluZwpmdW5jIEdsb2IocGF0dGVybiBzdHJpbmcpIChtYXRjaGVzIFtdc3RyaW5nLCBlcnIgZXJyb3IpCmZ1bmMgSGFzUHJlZml4KHAsIHByZWZpeCBzdHJpbmcpIGJvb2wKZnVuYyBJc0FicyhwYXRoIHN0cmluZykgYm9vbApmdW5jIElzTG9jYWwocGF0aCBzdHJpbmcpIGJvb2wKZnVuYyBKb2luKGVsZW0gLi4uc3RyaW5nKSBzdHJpbmcKZnVuYyBNYXRjaChwYXR0ZXJuLCBuYW1lIHN0cmluZykgKG1hdGNoZWQgYm9vbCwgZXJyIGVycm9yKQpmdW5jIFJlbChiYXNlcGF0aCwgdGFyZ3BhdGggc3RyaW5nKSAoc3RyaW5nLCBlcnJvcikKZnVuYyBTcGxpdChwYXRoIHN0cmluZykgKGRpciwgZmlsZSBzdHJpbmcpCmZ1bmMgU3BsaXRMaXN0KHBhdGggc3RyaW5nKSBbXXN0cmluZwpmdW5jIFRvU2xhc2gocGF0aCBzdHJpbmcpIHN0cmluZwpmdW5jIFZvbHVtZU5hbWUocGF0aCBzdHJpbmcpIHN0cmluZwpmdW5jIFdhbGsocm9vdCBzdHJpbmcsIGZuIFdhbGtGdW5jKSBlcnJvcgpmdW5jIFdhbGtEaXIocm9vdCBzdHJpbmcsIGZuIGZzLldhbGtEaXJGdW5jKSBlcnJvcgp0eXBlIFdhbGtGdW5jIGZ1bmMocGF0aCBzdHJpbmcsIGluZm8gZnMuRmlsZUluZm8sIGVyciBlcnJvcikgZXJyb3I=", - "duration": 451564541, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc -short filepath\n\nconst Separator = os.PathSeparator ...\nvar ErrBadPattern = errors.New(\u0026#34;syntax error in pattern\u0026#34;)\nvar SkipAll error = fs.SkipAll\nvar SkipDir error = fs.SkipDir\nfunc Abs(path string) (string, error)\nfunc Base(path string) string\nfunc Clean(path string) string\nfunc Dir(path string) string\nfunc EvalSymlinks(path string) (string, error)\nfunc Ext(path string) string\nfunc FromSlash(path string) string\nfunc Glob(pattern string) (matches []string, err error)\nfunc HasPrefix(p, prefix string) bool\nfunc IsAbs(path string) bool\nfunc IsLocal(path string) bool\nfunc Join(elem ...string) string\nfunc Match(pattern, name string) (matched bool, err error)\nfunc Rel(basepath, targpath string) (string, error)\nfunc Split(path string) (dir, file string)\nfunc SplitList(path string) []string\nfunc ToSlash(path string) string\nfunc VolumeName(path string) string\nfunc Walk(root string, fn WalkFunc) error\nfunc WalkDir(root string, fn fs.WalkDirFunc) error\ntype WalkFunc func(path string, info fs.FileInfo, err error) error", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "-short", - "filepath" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "Y29uc3QgU2VwYXJhdG9yID0gb3MuUGF0aFNlcGFyYXRvciAuLi4KdmFyIEVyckJhZFBhdHRlcm4gPSBlcnJvcnMuTmV3KCJzeW50YXggZXJyb3IgaW4gcGF0dGVybiIpCnZhciBTa2lwQWxsIGVycm9yID0gZnMuU2tpcEFsbAp2YXIgU2tpcERpciBlcnJvciA9IGZzLlNraXBEaXIKZnVuYyBBYnMocGF0aCBzdHJpbmcpIChzdHJpbmcsIGVycm9yKQpmdW5jIEJhc2UocGF0aCBzdHJpbmcpIHN0cmluZwpmdW5jIENsZWFuKHBhdGggc3RyaW5nKSBzdHJpbmcKZnVuYyBEaXIocGF0aCBzdHJpbmcpIHN0cmluZwpmdW5jIEV2YWxTeW1saW5rcyhwYXRoIHN0cmluZykgKHN0cmluZywgZXJyb3IpCmZ1bmMgRXh0KHBhdGggc3RyaW5nKSBzdHJpbmcKZnVuYyBGcm9tU2xhc2gocGF0aCBzdHJpbmcpIHN0cmluZwpmdW5jIEdsb2IocGF0dGVybiBzdHJpbmcpIChtYXRjaGVzIFtdc3RyaW5nLCBlcnIgZXJyb3IpCmZ1bmMgSGFzUHJlZml4KHAsIHByZWZpeCBzdHJpbmcpIGJvb2wKZnVuYyBJc0FicyhwYXRoIHN0cmluZykgYm9vbApmdW5jIElzTG9jYWwocGF0aCBzdHJpbmcpIGJvb2wKZnVuYyBKb2luKGVsZW0gLi4uc3RyaW5nKSBzdHJpbmcKZnVuYyBNYXRjaChwYXR0ZXJuLCBuYW1lIHN0cmluZykgKG1hdGNoZWQgYm9vbCwgZXJyIGVycm9yKQpmdW5jIFJlbChiYXNlcGF0aCwgdGFyZ3BhdGggc3RyaW5nKSAoc3RyaW5nLCBlcnJvcikKZnVuYyBTcGxpdChwYXRoIHN0cmluZykgKGRpciwgZmlsZSBzdHJpbmcpCmZ1bmMgU3BsaXRMaXN0KHBhdGggc3RyaW5nKSBbXXN0cmluZwpmdW5jIFRvU2xhc2gocGF0aCBzdHJpbmcpIHN0cmluZwpmdW5jIFZvbHVtZU5hbWUocGF0aCBzdHJpbmcpIHN0cmluZwpmdW5jIFdhbGsocm9vdCBzdHJpbmcsIGZuIFdhbGtGdW5jKSBlcnJvcgpmdW5jIFdhbGtEaXIocm9vdCBzdHJpbmcsIGZuIGZzLldhbGtEaXJGdW5jKSBlcnJvcgp0eXBlIFdhbGtGdW5jIGZ1bmMocGF0aCBzdHJpbmcsIGluZm8gZnMuRmlsZUluZm8sIGVyciBlcnJvcikgZXJyb3I=", - "duration": 451564541, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "fphelpers", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.24:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "filepath", - "href": "https://pkg.go.dev/filepath", - "target": "_blank" - }, - "file": "fphelpers", - "nodes": [ - [ - { - "atom": "code", - "file": "fphelpers", - "nodes": [ - { - "text": "filepath", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/filepath" - } - ], - { - "text": " package.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 24, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "fphelpers.md", - "nodes": [ - { - "text": "There are three functions in particular that are going to be useful to us in our test suite. These are ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "filepath#Dir", - "href": "https://pkg.go.dev/filepath#Dir", - "target": "_blank" - }, - "file": "fphelpers.md", - "nodes": [ - { - "atom": "code", - "file": "fphelpers.md", - "nodes": [ - { - "text": "filepath.Dir", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/filepath#Dir" - } - ], - { - "text": ", ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "filepath#Base", - "href": "https://pkg.go.dev/filepath#Base", - "target": "_blank" - }, - "file": "fphelpers.md", - "nodes": [ - { - "atom": "code", - "file": "fphelpers.md", - "nodes": [ - { - "text": "filepath.Base", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/filepath#Base" - } - ], - { - "text": ", and ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "filepath#Ext", - "href": "https://pkg.go.dev/filepath#Ext", - "target": "_blank" - }, - "file": "fphelpers.md", - "nodes": [ - { - "atom": "code", - "file": "fphelpers.md", - "nodes": [ - { - "text": "filepath.Ext", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/filepath#Ext" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "fphelpers.md", - "level": 2, - "nodes": [ - { - "text": "Getting a File's Extension", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "fphelpers.md", - "nodes": [ - { - "text": "When presented with a file path in ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "fphelpers.md", - "nodes": [ - { - "text": "string", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " form, such as ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "fphelpers.md", - "nodes": [ - { - "text": "/path/to/file.txt", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ", we need to be able to tell if the path is a file or a directory. The easiest, although not without potential errors, way to do this is to check if the path has a file extension. If it does then we can assume the path to be a file, and if it doesn't then we can assume the path to be a directory. The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "filepath#Ext", - "href": "https://pkg.go.dev/filepath#Ext", - "target": "_blank" - }, - "file": "fphelpers.md", - "nodes": [ - { - "atom": "code", - "file": "fphelpers.md", - "nodes": [ - { - "text": "filepath.Ext", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/filepath#Ext" - } - ], - { - "text": " function, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-25" - }, - "file": "fphelpers.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-25" - }, - "nodes": [ - { - "text": "Listing 1.25", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-25" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", will return the file extension of a file path. If the path is ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "fphelpers.md", - "nodes": [ - { - "text": "/path/to/file.txt", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " then the function will return ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "fphelpers.md", - "nodes": [ - { - "text": ".txt", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-25", - "type": "listing" - }, - "file": "fphelpers.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "doc", - "filepath.Ext" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "doc": "filepath.Ext", - "exec": "go doc filepath.Ext" - }, - "expected_exit": 0, - "file": "fphelpers", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc filepath.Ext\n\npackage filepath // import \u0026#34;path/filepath\u0026#34;\n\nfunc Ext(path string) string\n Ext returns the file name extension used by path. The extension is the\n suffix beginning at the final dot in the final element of path; it is empty\n if there is no dot.", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "filepath.Ext" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBmaWxlcGF0aCAvLyBpbXBvcnQgInBhdGgvZmlsZXBhdGgiCgpmdW5jIEV4dChwYXRoIHN0cmluZykgc3RyaW5nCiAgICBFeHQgcmV0dXJucyB0aGUgZmlsZSBuYW1lIGV4dGVuc2lvbiB1c2VkIGJ5IHBhdGguIFRoZSBleHRlbnNpb24gaXMgdGhlCiAgICBzdWZmaXggYmVnaW5uaW5nIGF0IHRoZSBmaW5hbCBkb3QgaW4gdGhlIGZpbmFsIGVsZW1lbnQgb2YgcGF0aDsgaXQgaXMgZW1wdHkKICAgIGlmIHRoZXJlIGlzIG5vIGRvdC4=", - "duration": 317446334, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc filepath.Ext\n\npackage filepath // import \u0026#34;path/filepath\u0026#34;\n\nfunc Ext(path string) string\n Ext returns the file name extension used by path. The extension is the\n suffix beginning at the final dot in the final element of path; it is empty\n if there is no dot.", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "filepath.Ext" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBmaWxlcGF0aCAvLyBpbXBvcnQgInBhdGgvZmlsZXBhdGgiCgpmdW5jIEV4dChwYXRoIHN0cmluZykgc3RyaW5nCiAgICBFeHQgcmV0dXJucyB0aGUgZmlsZSBuYW1lIGV4dGVuc2lvbiB1c2VkIGJ5IHBhdGguIFRoZSBleHRlbnNpb24gaXMgdGhlCiAgICBzdWZmaXggYmVnaW5uaW5nIGF0IHRoZSBmaW5hbCBkb3QgaW4gdGhlIGZpbmFsIGVsZW1lbnQgb2YgcGF0aDsgaXQgaXMgZW1wdHkKICAgIGlmIHRoZXJlIGlzIG5vIGRvdC4=", - "duration": 317446334, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "fphelpers", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.25:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "filepath#Ext", - "href": "https://pkg.go.dev/filepath#Ext", - "target": "_blank" - }, - "file": "fphelpers", - "nodes": [ - [ - { - "atom": "code", - "file": "fphelpers", - "nodes": [ - { - "text": "filepath.Ext", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/filepath#Ext" - } - ], - { - "text": " function.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 25, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "fphelpers.md", - "level": 2, - "nodes": [ - { - "text": "Getting a File's Directory", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "fphelpers.md", - "nodes": [ - { - "text": "If the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "filepath#Ext", - "href": "https://pkg.go.dev/filepath#Ext", - "target": "_blank" - }, - "file": "fphelpers.md", - "nodes": [ - { - "atom": "code", - "file": "fphelpers.md", - "nodes": [ - { - "text": "filepath.Ext", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/filepath#Ext" - } - ], - { - "text": " function returns an extensions, such as ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "fphelpers.md", - "nodes": [ - { - "text": ".txt", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ", then we can assume the path is a file. To get the directory of a file, we can use the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "filepath#Dir", - "href": "https://pkg.go.dev/filepath#Dir", - "target": "_blank" - }, - "file": "fphelpers.md", - "nodes": [ - { - "atom": "code", - "file": "fphelpers.md", - "nodes": [ - { - "text": "filepath.Dir", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/filepath#Dir" - } - ], - { - "text": " function, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-26" - }, - "file": "fphelpers.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-26" - }, - "nodes": [ - { - "text": "Listing 1.26", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-26" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ". If the path is ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "fphelpers.md", - "nodes": [ - { - "text": "/path/to/file.txt", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " then the function will return ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "fphelpers.md", - "nodes": [ - { - "text": "/path/to", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-26", - "type": "listing" - }, - "file": "fphelpers.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "doc", - "filepath.Dir" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "doc": "filepath.Dir", - "exec": "go doc filepath.Dir" - }, - "expected_exit": 0, - "file": "fphelpers", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc filepath.Dir\n\npackage filepath // import \u0026#34;path/filepath\u0026#34;\n\nfunc Dir(path string) string\n Dir returns all but the last element of path, typically the path\u0026#39;s\n directory. After dropping the final element, Dir calls Clean on the path and\n trailing slashes are removed. If the path is empty, Dir returns \u0026#34;.\u0026#34;. If the\n path consists entirely of separators, Dir returns a single separator. The\n returned path does not end in a separator unless it is the root directory.", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "filepath.Dir" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBmaWxlcGF0aCAvLyBpbXBvcnQgInBhdGgvZmlsZXBhdGgiCgpmdW5jIERpcihwYXRoIHN0cmluZykgc3RyaW5nCiAgICBEaXIgcmV0dXJucyBhbGwgYnV0IHRoZSBsYXN0IGVsZW1lbnQgb2YgcGF0aCwgdHlwaWNhbGx5IHRoZSBwYXRoJ3MKICAgIGRpcmVjdG9yeS4gQWZ0ZXIgZHJvcHBpbmcgdGhlIGZpbmFsIGVsZW1lbnQsIERpciBjYWxscyBDbGVhbiBvbiB0aGUgcGF0aCBhbmQKICAgIHRyYWlsaW5nIHNsYXNoZXMgYXJlIHJlbW92ZWQuIElmIHRoZSBwYXRoIGlzIGVtcHR5LCBEaXIgcmV0dXJucyAiLiIuIElmIHRoZQogICAgcGF0aCBjb25zaXN0cyBlbnRpcmVseSBvZiBzZXBhcmF0b3JzLCBEaXIgcmV0dXJucyBhIHNpbmdsZSBzZXBhcmF0b3IuIFRoZQogICAgcmV0dXJuZWQgcGF0aCBkb2VzIG5vdCBlbmQgaW4gYSBzZXBhcmF0b3IgdW5sZXNzIGl0IGlzIHRoZSByb290IGRpcmVjdG9yeS4=", - "duration": 114476208, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc filepath.Dir\n\npackage filepath // import \u0026#34;path/filepath\u0026#34;\n\nfunc Dir(path string) string\n Dir returns all but the last element of path, typically the path\u0026#39;s\n directory. After dropping the final element, Dir calls Clean on the path and\n trailing slashes are removed. If the path is empty, Dir returns \u0026#34;.\u0026#34;. If the\n path consists entirely of separators, Dir returns a single separator. The\n returned path does not end in a separator unless it is the root directory.", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "filepath.Dir" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBmaWxlcGF0aCAvLyBpbXBvcnQgInBhdGgvZmlsZXBhdGgiCgpmdW5jIERpcihwYXRoIHN0cmluZykgc3RyaW5nCiAgICBEaXIgcmV0dXJucyBhbGwgYnV0IHRoZSBsYXN0IGVsZW1lbnQgb2YgcGF0aCwgdHlwaWNhbGx5IHRoZSBwYXRoJ3MKICAgIGRpcmVjdG9yeS4gQWZ0ZXIgZHJvcHBpbmcgdGhlIGZpbmFsIGVsZW1lbnQsIERpciBjYWxscyBDbGVhbiBvbiB0aGUgcGF0aCBhbmQKICAgIHRyYWlsaW5nIHNsYXNoZXMgYXJlIHJlbW92ZWQuIElmIHRoZSBwYXRoIGlzIGVtcHR5LCBEaXIgcmV0dXJucyAiLiIuIElmIHRoZQogICAgcGF0aCBjb25zaXN0cyBlbnRpcmVseSBvZiBzZXBhcmF0b3JzLCBEaXIgcmV0dXJucyBhIHNpbmdsZSBzZXBhcmF0b3IuIFRoZQogICAgcmV0dXJuZWQgcGF0aCBkb2VzIG5vdCBlbmQgaW4gYSBzZXBhcmF0b3IgdW5sZXNzIGl0IGlzIHRoZSByb290IGRpcmVjdG9yeS4=", - "duration": 114476208, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "fphelpers", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.26:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "filepath#Dir", - "href": "https://pkg.go.dev/filepath#Dir", - "target": "_blank" - }, - "file": "fphelpers", - "nodes": [ - [ - { - "atom": "code", - "file": "fphelpers", - "nodes": [ - { - "text": "filepath.Dir", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/filepath#Dir" - } - ], - { - "text": " function.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 26, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "fphelpers.md", - "level": 2, - "nodes": [ - { - "text": "Getting a File/Directory's Name", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "fphelpers.md", - "nodes": [ - { - "text": "Whether our path has an extension or not, it does have a \"base\" name. The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "filepath#Base", - "href": "https://pkg.go.dev/filepath#Base", - "target": "_blank" - }, - "file": "fphelpers.md", - "nodes": [ - { - "atom": "code", - "file": "fphelpers.md", - "nodes": [ - { - "text": "filepath.Base", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/filepath#Base" - } - ], - { - "text": " function can be used to return the name of the file, or directory, at the end of the file path. For example, if the path is ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "fphelpers.md", - "nodes": [ - { - "text": "/path/to/file.txt", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " then \"base\" name would be ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "fphelpers.md", - "nodes": [ - { - "text": "file.txt", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ". If the path is ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "fphelpers.md", - "nodes": [ - { - "text": "/path/to/dir", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " then the \"base\" name would be ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "fphelpers.md", - "nodes": [ - { - "text": "dir", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-27", - "type": "listing" - }, - "file": "fphelpers.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "doc", - "filepath.Base" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "doc": "filepath.Base", - "exec": "go doc filepath.Base" - }, - "expected_exit": 0, - "file": "fphelpers", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc filepath.Base\n\npackage filepath // import \u0026#34;path/filepath\u0026#34;\n\nfunc Base(path string) string\n Base returns the last element of path. Trailing path separators are removed\n before extracting the last element. If the path is empty, Base returns \u0026#34;.\u0026#34;.\n If the path consists entirely of separators, Base returns a single\n separator.", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "filepath.Base" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBmaWxlcGF0aCAvLyBpbXBvcnQgInBhdGgvZmlsZXBhdGgiCgpmdW5jIEJhc2UocGF0aCBzdHJpbmcpIHN0cmluZwogICAgQmFzZSByZXR1cm5zIHRoZSBsYXN0IGVsZW1lbnQgb2YgcGF0aC4gVHJhaWxpbmcgcGF0aCBzZXBhcmF0b3JzIGFyZSByZW1vdmVkCiAgICBiZWZvcmUgZXh0cmFjdGluZyB0aGUgbGFzdCBlbGVtZW50LiBJZiB0aGUgcGF0aCBpcyBlbXB0eSwgQmFzZSByZXR1cm5zICIuIi4KICAgIElmIHRoZSBwYXRoIGNvbnNpc3RzIGVudGlyZWx5IG9mIHNlcGFyYXRvcnMsIEJhc2UgcmV0dXJucyBhIHNpbmdsZQogICAgc2VwYXJhdG9yLg==", - "duration": 303147959, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc filepath.Base\n\npackage filepath // import \u0026#34;path/filepath\u0026#34;\n\nfunc Base(path string) string\n Base returns the last element of path. Trailing path separators are removed\n before extracting the last element. If the path is empty, Base returns \u0026#34;.\u0026#34;.\n If the path consists entirely of separators, Base returns a single\n separator.", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "filepath.Base" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBmaWxlcGF0aCAvLyBpbXBvcnQgInBhdGgvZmlsZXBhdGgiCgpmdW5jIEJhc2UocGF0aCBzdHJpbmcpIHN0cmluZwogICAgQmFzZSByZXR1cm5zIHRoZSBsYXN0IGVsZW1lbnQgb2YgcGF0aC4gVHJhaWxpbmcgcGF0aCBzZXBhcmF0b3JzIGFyZSByZW1vdmVkCiAgICBiZWZvcmUgZXh0cmFjdGluZyB0aGUgbGFzdCBlbGVtZW50LiBJZiB0aGUgcGF0aCBpcyBlbXB0eSwgQmFzZSByZXR1cm5zICIuIi4KICAgIElmIHRoZSBwYXRoIGNvbnNpc3RzIGVudGlyZWx5IG9mIHNlcGFyYXRvcnMsIEJhc2UgcmV0dXJucyBhIHNpbmdsZQogICAgc2VwYXJhdG9yLg==", - "duration": 303147959, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "fphelpers", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.27:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "filepath#Base", - "href": "https://pkg.go.dev/filepath#Base", - "target": "_blank" - }, - "file": "fphelpers", - "nodes": [ - [ - { - "atom": "code", - "file": "fphelpers", - "nodes": [ - { - "text": "filepath.Base", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/filepath#Base" - } - ], - { - "text": " function.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 27, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "fphelpers.md", - "level": 2, - "nodes": [ - { - "text": "Using File Path Helpers", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "fphelpers.md", - "nodes": [ - { - "text": "Now that we know how to find the directory, base, and extension of a file path, we can use these functions to update our helper to create ", - "type": "hype.Text" - }, - { - "atom": "strong", - "file": "fphelpers.md", - "nodes": [ - { - "text": "only", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " directories, and not files.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-28", - "type": "listing" - }, - "file": "fphelpers.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "fphelpers", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "fphelpers/src/tree/demo_test.go#helper" - }, - "lang": "go", - "nodes": [ - { - "content": "func createTestData(t testing.TB) {\n\tt.Helper()\n\n\t// remove any previous test data\n\tif err := os.RemoveAll(\"data\"); err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\t// create the data directory\n\tif err := os.Mkdir(\"data\", 0755); err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\tlist := []string{\n\t\t\"data/.hidden/d.txt\",\n\t\t\"data/a.txt\",\n\t\t\"data/b.txt\",\n\t\t\"data/e/f/_ignore/i.txt\",\n\t\t\"data/e/f/g.txt\",\n\t\t\"data/e/f/h.txt\",\n\t\t\"data/e/j.txt\",\n\t\t\"data/testdata/c.txt\",\n\t}\n\n\t// create the test data files\n\tfor _, path := range list {\n\t\tif ext := filepath.Ext(path); len(ext) \u003e 0 {\n\t\t\tpath = filepath.Dir(path)\n\t\t}\n\n\t\tfmt.Println(\"creating:\", path)\n\t\tif err := os.Mkdir(path, 0755); err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\n\t}\n\n}", - "file": "fphelpers/src/tree/demo_test.go", - "lang": "go", - "name": "helper", - "start": 11, - "end": 51, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "fphelpers", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.28:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Helper function to create test folder, and file, structures.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 28, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "fphelpers.md", - "nodes": [ - { - "text": "When we look at the test output, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-29" - }, - "file": "fphelpers.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-29" - }, - "nodes": [ - { - "text": "Listing 1.29", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-29" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", however, we can see that the helper function is still not working as expected. It is trying to create a directory, ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "fphelpers.md", - "nodes": [ - { - "text": "data", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ", that already exists.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-29", - "type": "listing" - }, - "file": "fphelpers.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "test", - "-v" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go test -v", - "exit": "-1", - "src": "fphelpers/src/tree", - "test": "-v" - }, - "expected_exit": -1, - "file": "fphelpers", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go test -v\n\n=== RUN Test_Walk\n=== PAUSE Test_Walk\n=== CONT Test_Walk\ncreating: data/.hidden\ncreating: data\n demo_test.go:57: mkdir data: file exists\n--- FAIL: Test_Walk (0.00s)\nFAIL\nexit status 1\nFAIL\tdemo\t0.532s", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "test", - "-v" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/14-files/fphelpers/src/tree", - "err": { - "Stderr": null - }, - "exit": 1, - "stdout": "PT09IFJVTiAgIFRlc3RfV2Fsawo9PT0gUEFVU0UgVGVzdF9XYWxrCj09PSBDT05UICBUZXN0X1dhbGsKY3JlYXRpbmc6IGRhdGEvLmhpZGRlbgpjcmVhdGluZzogZGF0YQogICAgZGVtb190ZXN0LmdvOjU3OiBta2RpciBkYXRhOiBmaWxlIGV4aXN0cwotLS0gRkFJTDogVGVzdF9XYWxrICgwLjAwcykKRkFJTApleGl0IHN0YXR1cyAxCkZBSUwJZGVtbwkwLjUzMnM=", - "duration": 1974721167, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go test -v\n\n=== RUN Test_Walk\n=== PAUSE Test_Walk\n=== CONT Test_Walk\ncreating: data/.hidden\ncreating: data\n demo_test.go:57: mkdir data: file exists\n--- FAIL: Test_Walk (0.00s)\nFAIL\nexit status 1\nFAIL\tdemo\t0.532s", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "test", - "-v" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/14-files/fphelpers/src/tree", - "err": { - "Stderr": null - }, - "exit": 1, - "stdout": "PT09IFJVTiAgIFRlc3RfV2Fsawo9PT0gUEFVU0UgVGVzdF9XYWxrCj09PSBDT05UICBUZXN0X1dhbGsKY3JlYXRpbmc6IGRhdGEvLmhpZGRlbgpjcmVhdGluZzogZGF0YQogICAgZGVtb190ZXN0LmdvOjU3OiBta2RpciBkYXRhOiBmaWxlIGV4aXN0cwotLS0gRkFJTDogVGVzdF9XYWxrICgwLjAwcykKRkFJTApleGl0IHN0YXR1cyAxCkZBSUwJZGVtbwkwLjUzMnM=", - "duration": 1974721167, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "fphelpers", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.29:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Test output.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 29, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "fphelpers.md", - "level": 2, - "nodes": [ - { - "text": "Checking the Error", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "fphelpers.md", - "nodes": [ - { - "text": "To try and fix our helper we should properly check the error returned by the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "os#Mkdir", - "href": "https://pkg.go.dev/os#Mkdir", - "target": "_blank" - }, - "file": "fphelpers.md", - "nodes": [ - { - "atom": "code", - "file": "fphelpers.md", - "nodes": [ - { - "text": "os.Mkdir", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/os#Mkdir" - } - ], - { - "text": " function. If the error is not nil, we need to check if the error is because the directory already exists. If it is, then we can ignore the error and continue. If the error is something else, then we need to return the error to the caller.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-30", - "type": "listing" - }, - "file": "fphelpers.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "fphelpers", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "fphelpers/src/errcheck/demo_test.go#helper" - }, - "lang": "go", - "nodes": [ - { - "content": "func createTestData(t testing.TB) {\n\tt.Helper()\n\n\t// remove any previous test data\n\tif err := os.RemoveAll(\"data\"); err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\t// create the data directory\n\tif err := os.Mkdir(\"data\", 0755); err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\tlist := []string{\n\t\t\"data/.hidden/d.txt\",\n\t\t\"data/a.txt\",\n\t\t\"data/b.txt\",\n\t\t\"data/e/f/_ignore/i.txt\",\n\t\t\"data/e/f/g.txt\",\n\t\t\"data/e/f/h.txt\",\n\t\t\"data/e/j.txt\",\n\t\t\"data/testdata/c.txt\",\n\t}\n\n\t// create the test data files\n\tfor _, path := range list {\n\t\tif ext := filepath.Ext(path); len(ext) \u003e 0 {\n\t\t\tpath = filepath.Dir(path)\n\t\t}\n\n\t\tfmt.Println(\"creating:\", path)\n\t\tif err := os.Mkdir(path, 0755); err != nil {\n\t\t\t// ignore if the directory already exists\n\t\t\tif !errors.Is(err, fs.ErrExist) {\n\t\t\t\tt.Fatal(err)\n\t\t\t}\n\t\t}\n\n\t}\n\n}", - "file": "fphelpers/src/errcheck/demo_test.go", - "lang": "go", - "name": "helper", - "start": 13, - "end": 56, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "fphelpers", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.30:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Helper function to check for error.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 30, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "fphelpers.md", - "nodes": [ - { - "text": "Now when we look at the test output, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-31" - }, - "file": "fphelpers.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-31" - }, - "nodes": [ - { - "text": "Listing 1.31", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-31" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", we can see that the helper function is still not working as expected, but we have moved beyond the first error to a new one. We are trying to create nested sub-directories, ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "fphelpers.md", - "nodes": [ - { - "text": "data/e/f/_ignore", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ", using the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "os#Mkdir", - "href": "https://pkg.go.dev/os#Mkdir", - "target": "_blank" - }, - "file": "fphelpers.md", - "nodes": [ - { - "atom": "code", - "file": "fphelpers.md", - "nodes": [ - { - "text": "os.Mkdir", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/os#Mkdir" - } - ], - { - "text": " function which is designed to only create one directory at a time.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-31", - "type": "listing" - }, - "file": "fphelpers.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "test", - "-v" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go test -v", - "exit": "-1", - "src": "fphelpers/src/errcheck", - "test": "-v" - }, - "expected_exit": -1, - "file": "fphelpers", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go test -v\n\n=== RUN Test_Walk\n=== PAUSE Test_Walk\n=== CONT Test_Walk\ncreating: data/.hidden\ncreating: data\ncreating: data\ncreating: data/e/f/_ignore\n demo_test.go:62: mkdir data/e/f/_ignore: no such file or directory\n--- FAIL: Test_Walk (0.00s)\nFAIL\nexit status 1\nFAIL\tdemo\t0.598s", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "test", - "-v" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/14-files/fphelpers/src/errcheck", - "err": { - "Stderr": null - }, - "exit": 1, - "stdout": "PT09IFJVTiAgIFRlc3RfV2Fsawo9PT0gUEFVU0UgVGVzdF9XYWxrCj09PSBDT05UICBUZXN0X1dhbGsKY3JlYXRpbmc6IGRhdGEvLmhpZGRlbgpjcmVhdGluZzogZGF0YQpjcmVhdGluZzogZGF0YQpjcmVhdGluZzogZGF0YS9lL2YvX2lnbm9yZQogICAgZGVtb190ZXN0LmdvOjYyOiBta2RpciBkYXRhL2UvZi9faWdub3JlOiBubyBzdWNoIGZpbGUgb3IgZGlyZWN0b3J5Ci0tLSBGQUlMOiBUZXN0X1dhbGsgKDAuMDBzKQpGQUlMCmV4aXQgc3RhdHVzIDEKRkFJTAlkZW1vCTAuNTk4cw==", - "duration": 1284591667, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go test -v\n\n=== RUN Test_Walk\n=== PAUSE Test_Walk\n=== CONT Test_Walk\ncreating: data/.hidden\ncreating: data\ncreating: data\ncreating: data/e/f/_ignore\n demo_test.go:62: mkdir data/e/f/_ignore: no such file or directory\n--- FAIL: Test_Walk (0.00s)\nFAIL\nexit status 1\nFAIL\tdemo\t0.598s", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "test", - "-v" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/14-files/fphelpers/src/errcheck", - "err": { - "Stderr": null - }, - "exit": 1, - "stdout": "PT09IFJVTiAgIFRlc3RfV2Fsawo9PT0gUEFVU0UgVGVzdF9XYWxrCj09PSBDT05UICBUZXN0X1dhbGsKY3JlYXRpbmc6IGRhdGEvLmhpZGRlbgpjcmVhdGluZzogZGF0YQpjcmVhdGluZzogZGF0YQpjcmVhdGluZzogZGF0YS9lL2YvX2lnbm9yZQogICAgZGVtb190ZXN0LmdvOjYyOiBta2RpciBkYXRhL2UvZi9faWdub3JlOiBubyBzdWNoIGZpbGUgb3IgZGlyZWN0b3J5Ci0tLSBGQUlMOiBUZXN0X1dhbGsgKDAuMDBzKQpGQUlMCmV4aXQgc3RhdHVzIDEKRkFJTAlkZW1vCTAuNTk4cw==", - "duration": 1284591667, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "fphelpers", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.31:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Using ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "errors#Is", - "href": "https://pkg.go.dev/errors#Is", - "target": "_blank" - }, - "file": "fphelpers", - "nodes": [ - [ - { - "atom": "code", - "file": "fphelpers", - "nodes": [ - { - "text": "errors.Is", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/errors#Is" - } - ], - { - "text": " to check for the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "io/fs#ErrExit", - "href": "https://pkg.go.dev/io/fs#ErrExit", - "target": "_blank" - }, - "file": "fphelpers", - "nodes": [ - [ - { - "atom": "code", - "file": "fphelpers", - "nodes": [ - { - "text": "fs.ErrExit", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/io/fs#ErrExit" - } - ], - { - "text": " ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "builtin#error", - "href": "https://pkg.go.dev/builtin#error", - "target": "_blank" - }, - "file": "fphelpers", - "nodes": [ - [ - { - "atom": "code", - "file": "fphelpers", - "nodes": [ - { - "text": "error", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/builtin#error" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 31, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "title": "File Path Helpers", - "type": "*hype.Page" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "type": "*hype.Include" - } - ], - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "include", - "attributes": { - "src": "walk/mkdirall.md" - }, - "dir": "walk", - "file": "module.md", - "nodes": [ - [ - { - "atom": "page", - "file": "walk/mkdirall.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "h1", - "file": "walk/mkdirall.md", - "level": 1, - "nodes": [ - { - "text": "Creating Multiple Directories", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "walk/mkdirall.md", - "nodes": [ - { - "text": "To create multiple directories at once we can use the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "os#MkdirAll", - "href": "https://pkg.go.dev/os#MkdirAll", - "target": "_blank" - }, - "file": "walk/mkdirall.md", - "nodes": [ - { - "atom": "code", - "file": "walk/mkdirall.md", - "nodes": [ - { - "text": "os.MkdirAll", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/os#MkdirAll" - } - ], - { - "text": " function, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-32" - }, - "file": "walk/mkdirall.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-32" - }, - "nodes": [ - { - "text": "Listing 1.32", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-32" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ". This behaves identically to ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "os#Mkdir", - "href": "https://pkg.go.dev/os#Mkdir", - "target": "_blank" - }, - "file": "walk/mkdirall.md", - "nodes": [ - { - "atom": "code", - "file": "walk/mkdirall.md", - "nodes": [ - { - "text": "os.Mkdir", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/os#Mkdir" - } - ], - { - "text": " except that it creates all the directories in the path.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-32", - "type": "listing" - }, - "file": "walk/mkdirall.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "doc", - "os.MkdirAll" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "doc": "os.MkdirAll", - "exec": "go doc os.MkdirAll" - }, - "expected_exit": 0, - "file": "walk", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc os.MkdirAll\n\npackage os // import \u0026#34;os\u0026#34;\n\nfunc MkdirAll(path string, perm FileMode) error\n MkdirAll creates a directory named path, along with any necessary parents,\n and returns nil, or else returns an error. The permission bits perm (before\n umask) are used for all directories that MkdirAll creates. If path is\n already a directory, MkdirAll does nothing and returns nil.", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "os.MkdirAll" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBvcyAvLyBpbXBvcnQgIm9zIgoKZnVuYyBNa2RpckFsbChwYXRoIHN0cmluZywgcGVybSBGaWxlTW9kZSkgZXJyb3IKICAgIE1rZGlyQWxsIGNyZWF0ZXMgYSBkaXJlY3RvcnkgbmFtZWQgcGF0aCwgYWxvbmcgd2l0aCBhbnkgbmVjZXNzYXJ5IHBhcmVudHMsCiAgICBhbmQgcmV0dXJucyBuaWwsIG9yIGVsc2UgcmV0dXJucyBhbiBlcnJvci4gVGhlIHBlcm1pc3Npb24gYml0cyBwZXJtIChiZWZvcmUKICAgIHVtYXNrKSBhcmUgdXNlZCBmb3IgYWxsIGRpcmVjdG9yaWVzIHRoYXQgTWtkaXJBbGwgY3JlYXRlcy4gSWYgcGF0aCBpcwogICAgYWxyZWFkeSBhIGRpcmVjdG9yeSwgTWtkaXJBbGwgZG9lcyBub3RoaW5nIGFuZCByZXR1cm5zIG5pbC4=", - "duration": 368989125, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc os.MkdirAll\n\npackage os // import \u0026#34;os\u0026#34;\n\nfunc MkdirAll(path string, perm FileMode) error\n MkdirAll creates a directory named path, along with any necessary parents,\n and returns nil, or else returns an error. The permission bits perm (before\n umask) are used for all directories that MkdirAll creates. If path is\n already a directory, MkdirAll does nothing and returns nil.", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "os.MkdirAll" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBvcyAvLyBpbXBvcnQgIm9zIgoKZnVuYyBNa2RpckFsbChwYXRoIHN0cmluZywgcGVybSBGaWxlTW9kZSkgZXJyb3IKICAgIE1rZGlyQWxsIGNyZWF0ZXMgYSBkaXJlY3RvcnkgbmFtZWQgcGF0aCwgYWxvbmcgd2l0aCBhbnkgbmVjZXNzYXJ5IHBhcmVudHMsCiAgICBhbmQgcmV0dXJucyBuaWwsIG9yIGVsc2UgcmV0dXJucyBhbiBlcnJvci4gVGhlIHBlcm1pc3Npb24gYml0cyBwZXJtIChiZWZvcmUKICAgIHVtYXNrKSBhcmUgdXNlZCBmb3IgYWxsIGRpcmVjdG9yaWVzIHRoYXQgTWtkaXJBbGwgY3JlYXRlcy4gSWYgcGF0aCBpcwogICAgYWxyZWFkeSBhIGRpcmVjdG9yeSwgTWtkaXJBbGwgZG9lcyBub3RoaW5nIGFuZCByZXR1cm5zIG5pbC4=", - "duration": 368989125, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "walk", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.32:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "os#MkdirAll", - "href": "https://pkg.go.dev/os#MkdirAll", - "target": "_blank" - }, - "file": "walk", - "nodes": [ - [ - { - "atom": "code", - "file": "walk", - "nodes": [ - { - "text": "os.MkdirAll", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/os#MkdirAll" - } - ], - { - "text": " function.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 32, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "walk/mkdirall.md", - "nodes": [ - { - "text": "We can update our test helper to use ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "os#MkdirAll", - "href": "https://pkg.go.dev/os#MkdirAll", - "target": "_blank" - }, - "file": "walk/mkdirall.md", - "nodes": [ - { - "atom": "code", - "file": "walk/mkdirall.md", - "nodes": [ - { - "text": "os.MkdirAll", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/os#MkdirAll" - } - ], - { - "text": " to create the directories, instead of ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "os#Mkdir", - "href": "https://pkg.go.dev/os#Mkdir", - "target": "_blank" - }, - "file": "walk/mkdirall.md", - "nodes": [ - { - "atom": "code", - "file": "walk/mkdirall.md", - "nodes": [ - { - "text": "os.Mkdir", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/os#Mkdir" - } - ], - { - "text": ", to ensure that the directories are created.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-33", - "type": "listing" - }, - "file": "walk/mkdirall.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "walk", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "walk/src/mkdirall/demo_test.go#helper" - }, - "lang": "go", - "nodes": [ - { - "content": "func createTestData(t testing.TB) {\n\tt.Helper()\n\n\t// remove any previous test data\n\tif err := os.RemoveAll(\"data\"); err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\t// create the data directory\n\tif err := os.Mkdir(\"data\", 0755); err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\tlist := []string{\n\t\t\"data/.hidden/d.txt\",\n\t\t\"data/a.txt\",\n\t\t\"data/b.txt\",\n\t\t\"data/e/f/_ignore/i.txt\",\n\t\t\"data/e/f/g.txt\",\n\t\t\"data/e/f/h.txt\",\n\t\t\"data/e/j.txt\",\n\t\t\"data/testdata/c.txt\",\n\t}\n\n\t// create the test data files\n\tfor _, path := range list {\n\t\tif ext := filepath.Ext(path); len(ext) \u003e 0 {\n\t\t\tpath = filepath.Dir(path)\n\t\t}\n\n\t\tfmt.Println(\"creating:\", path)\n\t\tif err := os.MkdirAll(path, 0755); err != nil {\n\t\t\t// ignore if the directory already exists\n\t\t\tif !errors.Is(err, fs.ErrExist) {\n\t\t\t\tt.Fatal(err)\n\t\t\t}\n\t\t}\n\n\t}\n\n}", - "file": "walk/src/mkdirall/demo_test.go", - "lang": "go", - "name": "helper", - "start": 13, - "end": 56, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "atom": "hr", - "file": "walk", - "type": "*hype.Element" - }, - [ - { - "args": [ - "go", - "test", - "-v" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go test -v", - "exit": "-1", - "src": "walk/src/mkdirall", - "test": "-v" - }, - "expected_exit": -1, - "file": "walk", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go test -v\n\n=== RUN Test_Walk\n=== PAUSE Test_Walk\n=== CONT Test_Walk\ncreating: data/.hidden\ncreating: data\ncreating: data\ncreating: data/e/f/_ignore\ncreating: data/e/f\ncreating: data/e/f\ncreating: data/e\ncreating: data/testdata\n demo_test.go:81: expected data/a.txt, data/b.txt, data/e/f/g.txt, data/e/f/h.txt, data/e/j.txt, got \n--- FAIL: Test_Walk (0.01s)\nFAIL\nexit status 1\nFAIL\tdemo\t0.732s", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "test", - "-v" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/14-files/walk/src/mkdirall", - "err": { - "Stderr": null - }, - "exit": 1, - "stdout": "PT09IFJVTiAgIFRlc3RfV2Fsawo9PT0gUEFVU0UgVGVzdF9XYWxrCj09PSBDT05UICBUZXN0X1dhbGsKY3JlYXRpbmc6IGRhdGEvLmhpZGRlbgpjcmVhdGluZzogZGF0YQpjcmVhdGluZzogZGF0YQpjcmVhdGluZzogZGF0YS9lL2YvX2lnbm9yZQpjcmVhdGluZzogZGF0YS9lL2YKY3JlYXRpbmc6IGRhdGEvZS9mCmNyZWF0aW5nOiBkYXRhL2UKY3JlYXRpbmc6IGRhdGEvdGVzdGRhdGEKICAgIGRlbW9fdGVzdC5nbzo4MTogZXhwZWN0ZWQgZGF0YS9hLnR4dCwgZGF0YS9iLnR4dCwgZGF0YS9lL2YvZy50eHQsIGRhdGEvZS9mL2gudHh0LCBkYXRhL2Uvai50eHQsIGdvdCAKLS0tIEZBSUw6IFRlc3RfV2FsayAoMC4wMXMpCkZBSUwKZXhpdCBzdGF0dXMgMQpGQUlMCWRlbW8JMC43MzJz", - "duration": 1399677916, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go test -v\n\n=== RUN Test_Walk\n=== PAUSE Test_Walk\n=== CONT Test_Walk\ncreating: data/.hidden\ncreating: data\ncreating: data\ncreating: data/e/f/_ignore\ncreating: data/e/f\ncreating: data/e/f\ncreating: data/e\ncreating: data/testdata\n demo_test.go:81: expected data/a.txt, data/b.txt, data/e/f/g.txt, data/e/f/h.txt, data/e/j.txt, got \n--- FAIL: Test_Walk (0.01s)\nFAIL\nexit status 1\nFAIL\tdemo\t0.732s", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "test", - "-v" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/14-files/walk/src/mkdirall", - "err": { - "Stderr": null - }, - "exit": 1, - "stdout": "PT09IFJVTiAgIFRlc3RfV2Fsawo9PT0gUEFVU0UgVGVzdF9XYWxrCj09PSBDT05UICBUZXN0X1dhbGsKY3JlYXRpbmc6IGRhdGEvLmhpZGRlbgpjcmVhdGluZzogZGF0YQpjcmVhdGluZzogZGF0YQpjcmVhdGluZzogZGF0YS9lL2YvX2lnbm9yZQpjcmVhdGluZzogZGF0YS9lL2YKY3JlYXRpbmc6IGRhdGEvZS9mCmNyZWF0aW5nOiBkYXRhL2UKY3JlYXRpbmc6IGRhdGEvdGVzdGRhdGEKICAgIGRlbW9fdGVzdC5nbzo4MTogZXhwZWN0ZWQgZGF0YS9hLnR4dCwgZGF0YS9iLnR4dCwgZGF0YS9lL2YvZy50eHQsIGRhdGEvZS9mL2gudHh0LCBkYXRhL2Uvai50eHQsIGdvdCAKLS0tIEZBSUw6IFRlc3RfV2FsayAoMC4wMXMpCkZBSUwKZXhpdCBzdGF0dXMgMQpGQUlMCWRlbW8JMC43MzJz", - "duration": 1399677916, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "walk", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.33:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Helper function to create test folder, and file, structures.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 33, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "walk/mkdirall.md", - "nodes": [ - { - "text": "As we can see from the test output in ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-34" - }, - "file": "walk/mkdirall.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-34" - }, - "nodes": [ - { - "text": "Listing 1.34", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-34" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", our tests are still not passing. This is because we have yet to create the necessary files.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "walk/mkdirall.md", - "nodes": [ - { - "text": "A look at the filesystem itself confirms that the directories were indeed created.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-34", - "type": "listing" - }, - "file": "walk/mkdirall.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "tree", - "-a" - ], - "atom": "cmd", - "attributes": { - "exec": "tree -a", - "src": "walk/src/mkdirall" - }, - "expected_exit": 0, - "file": "walk", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ tree -a\n\n.\n├── data\n│   ├── .hidden\n│   ├── e\n│   │   └── f\n│   │   └── _ignore\n│   └── testdata\n├── demo.go\n├── demo_test.go\n└── go.mod\n\n7 directories, 3 files", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "tree", - "-a" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/14-files/walk/src/mkdirall", - "stdout": "LgrilJzilIDilIAgZGF0YQrilILCoMKgIOKUnOKUgOKUgCAuaGlkZGVuCuKUgsKgwqAg4pSc4pSA4pSAIGUK4pSCwqDCoCDilILCoMKgIOKUlOKUgOKUgCBmCuKUgsKgwqAg4pSCwqDCoCAgICAg4pSU4pSA4pSAIF9pZ25vcmUK4pSCwqDCoCDilJTilIDilIAgdGVzdGRhdGEK4pSc4pSA4pSAIGRlbW8uZ28K4pSc4pSA4pSAIGRlbW9fdGVzdC5nbwrilJTilIDilIAgZ28ubW9kCgo3IGRpcmVjdG9yaWVzLCAzIGZpbGVz", - "duration": 500628750, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ tree -a\n\n.\n├── data\n│   ├── .hidden\n│   ├── e\n│   │   └── f\n│   │   └── _ignore\n│   └── testdata\n├── demo.go\n├── demo_test.go\n└── go.mod\n\n7 directories, 3 files", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "tree", - "-a" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/14-files/walk/src/mkdirall", - "stdout": "LgrilJzilIDilIAgZGF0YQrilILCoMKgIOKUnOKUgOKUgCAuaGlkZGVuCuKUgsKgwqAg4pSc4pSA4pSAIGUK4pSCwqDCoCDilILCoMKgIOKUlOKUgOKUgCBmCuKUgsKgwqAg4pSCwqDCoCAgICAg4pSU4pSA4pSAIF9pZ25vcmUK4pSCwqDCoCDilJTilIDilIAgdGVzdGRhdGEK4pSc4pSA4pSAIGRlbW8uZ28K4pSc4pSA4pSAIGRlbW9fdGVzdC5nbwrilJTilIDilIAgZ28ubW9kCgo3IGRpcmVjdG9yaWVzLCAzIGZpbGVz", - "duration": 500628750, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "walk", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.34:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The directory structure created by the test helper.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 34, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "title": "Creating Multiple Directories", - "type": "*hype.Page" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "type": "*hype.Include" - } - ], - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "include", - "attributes": { - "src": "creating/creating.md" - }, - "dir": "creating", - "file": "module.md", - "nodes": [ - [ - { - "atom": "page", - "file": "creating.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "h1", - "file": "creating.md", - "level": 1, - "nodes": [ - { - "text": "Creating Files", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "creating.md", - "nodes": [ - { - "text": "Before we can read a file, we need to create it. To create new file we can use the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "os#Create", - "href": "https://pkg.go.dev/os#Create", - "target": "_blank" - }, - "file": "creating.md", - "nodes": [ - { - "atom": "code", - "file": "creating.md", - "nodes": [ - { - "text": "os.Create", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/os#Create" - } - ], - { - "text": " function, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-35" - }, - "file": "creating.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-35" - }, - "nodes": [ - { - "text": "Listing 1.35", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-35" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ". The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "os#Create", - "href": "https://pkg.go.dev/os#Create", - "target": "_blank" - }, - "file": "creating.md", - "nodes": [ - { - "atom": "code", - "file": "creating.md", - "nodes": [ - { - "text": "os.Create", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/os#Create" - } - ], - { - "text": " function will create a new file at the specified path if one does not already exist. If the file already exists, the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "os#Create", - "href": "https://pkg.go.dev/os#Create", - "target": "_blank" - }, - "file": "creating.md", - "nodes": [ - { - "atom": "code", - "file": "creating.md", - "nodes": [ - { - "text": "os.Create", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/os#Create" - } - ], - { - "text": " function will erase, or truncate, the existing file's contents.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-35", - "type": "listing" - }, - "file": "creating.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "doc", - "os.Create" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "doc": "os.Create", - "exec": "go doc os.Create" - }, - "expected_exit": 0, - "file": "creating", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc os.Create\n\npackage os // import \u0026#34;os\u0026#34;\n\nfunc Create(name string) (*File, error)\n Create creates or truncates the named file. If the file already exists,\n it is truncated. If the file does not exist, it is created with mode 0666\n (before umask). If successful, methods on the returned File can be used for\n I/O; the associated file descriptor has mode O_RDWR. If there is an error,\n it will be of type *PathError.", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "os.Create" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBvcyAvLyBpbXBvcnQgIm9zIgoKZnVuYyBDcmVhdGUobmFtZSBzdHJpbmcpICgqRmlsZSwgZXJyb3IpCiAgICBDcmVhdGUgY3JlYXRlcyBvciB0cnVuY2F0ZXMgdGhlIG5hbWVkIGZpbGUuIElmIHRoZSBmaWxlIGFscmVhZHkgZXhpc3RzLAogICAgaXQgaXMgdHJ1bmNhdGVkLiBJZiB0aGUgZmlsZSBkb2VzIG5vdCBleGlzdCwgaXQgaXMgY3JlYXRlZCB3aXRoIG1vZGUgMDY2NgogICAgKGJlZm9yZSB1bWFzaykuIElmIHN1Y2Nlc3NmdWwsIG1ldGhvZHMgb24gdGhlIHJldHVybmVkIEZpbGUgY2FuIGJlIHVzZWQgZm9yCiAgICBJL087IHRoZSBhc3NvY2lhdGVkIGZpbGUgZGVzY3JpcHRvciBoYXMgbW9kZSBPX1JEV1IuIElmIHRoZXJlIGlzIGFuIGVycm9yLAogICAgaXQgd2lsbCBiZSBvZiB0eXBlICpQYXRoRXJyb3Iu", - "duration": 524976417, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc os.Create\n\npackage os // import \u0026#34;os\u0026#34;\n\nfunc Create(name string) (*File, error)\n Create creates or truncates the named file. If the file already exists,\n it is truncated. If the file does not exist, it is created with mode 0666\n (before umask). If successful, methods on the returned File can be used for\n I/O; the associated file descriptor has mode O_RDWR. If there is an error,\n it will be of type *PathError.", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "os.Create" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBvcyAvLyBpbXBvcnQgIm9zIgoKZnVuYyBDcmVhdGUobmFtZSBzdHJpbmcpICgqRmlsZSwgZXJyb3IpCiAgICBDcmVhdGUgY3JlYXRlcyBvciB0cnVuY2F0ZXMgdGhlIG5hbWVkIGZpbGUuIElmIHRoZSBmaWxlIGFscmVhZHkgZXhpc3RzLAogICAgaXQgaXMgdHJ1bmNhdGVkLiBJZiB0aGUgZmlsZSBkb2VzIG5vdCBleGlzdCwgaXQgaXMgY3JlYXRlZCB3aXRoIG1vZGUgMDY2NgogICAgKGJlZm9yZSB1bWFzaykuIElmIHN1Y2Nlc3NmdWwsIG1ldGhvZHMgb24gdGhlIHJldHVybmVkIEZpbGUgY2FuIGJlIHVzZWQgZm9yCiAgICBJL087IHRoZSBhc3NvY2lhdGVkIGZpbGUgZGVzY3JpcHRvciBoYXMgbW9kZSBPX1JEV1IuIElmIHRoZXJlIGlzIGFuIGVycm9yLAogICAgaXQgd2lsbCBiZSBvZiB0eXBlICpQYXRoRXJyb3Iu", - "duration": 524976417, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "creating", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.35:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "os#Create", - "href": "https://pkg.go.dev/os#Create", - "target": "_blank" - }, - "file": "creating", - "nodes": [ - [ - { - "atom": "code", - "file": "creating", - "nodes": [ - { - "text": "os.Create", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/os#Create" - } - ], - { - "text": " function.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 35, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "creating.md", - "nodes": [ - { - "text": "Consider ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-36" - }, - "file": "creating.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-36" - }, - "nodes": [ - { - "text": "Listing 1.36", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-36" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ". We have a ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "creating.md", - "nodes": [ - { - "text": "Create", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function that creates a new file at the specified path and writes the specified data to the file.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-36", - "type": "listing" - }, - "file": "creating.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "creating", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "creating/src/creating/demo.go#create" - }, - "lang": "go", - "nodes": [ - { - "content": "func Create(name string, body []byte) error {\n\t// create a new file, this will\n\t// truncate the file if it already exists\n\tf, err := os.Create(name)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer f.Close()\n\n\t// write the body to the file\n\t_, err = f.Write(body)\n\treturn err\n}", - "file": "creating/src/creating/demo.go", - "lang": "go", - "name": "create", - "start": 7, - "end": 22, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "creating", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.36:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "creating", - "nodes": [ - { - "text": "Create", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 36, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "creating.md", - "nodes": [ - { - "text": "If successful, ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "os#Create", - "href": "https://pkg.go.dev/os#Create", - "target": "_blank" - }, - "file": "creating.md", - "nodes": [ - { - "atom": "code", - "file": "creating.md", - "nodes": [ - { - "text": "os.Create", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/os#Create" - } - ], - { - "text": " returns a ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "os#File", - "href": "https://pkg.go.dev/os#File", - "target": "_blank" - }, - "file": "creating.md", - "nodes": [ - { - "atom": "code", - "file": "creating.md", - "nodes": [ - { - "text": "os.File", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/os#File" - } - ], - { - "text": " value representing the new file. This file can then be written to and read from. In this case, we are writing the string ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "creating.md", - "nodes": [ - { - "text": "Hello, World!", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " to the file.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "creating.md", - "nodes": [ - { - "text": "Next, let's write a test, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-37" - }, - "file": "creating.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-37" - }, - "nodes": [ - { - "text": "Listing 1.37", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-37" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", that confirms the file was created, and its contents are correct.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-37", - "type": "listing" - }, - "file": "creating.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "creating", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "creating/src/creating/demo_test.go#create" - }, - "lang": "go", - "nodes": [ - { - "content": "func Test_Create(t *testing.T) {\n\tt.Parallel()\n\n\tfp := \"data/test.txt\"\n\n\t// create test data directory\n\tcreateTestData(t)\n\n\t// assert the file does not exist\n\t// by trying to stat it.\n\t// this should return an error\n\t_, err := os.Stat(fp)\n\tif err != nil {\n\t\tif !errors.Is(err, fs.ErrNotExist) {\n\t\t\tt.Fatal(err)\n\t\t}\n\t}\n\n\tbody := []byte(\"Hello, World!\")\n\n\t// create the file\n\terr = Create(fp, body)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\t// read the file into memory\n\tb, err := os.ReadFile(fp)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\tact := string(b)\n\texp := string(body)\n\n\t// assert the file contents are correct\n\tif exp != act {\n\t\tt.Fatalf(\"expected %s, got %s\", exp, act)\n\t}\n\n}", - "file": "creating/src/creating/demo_test.go", - "lang": "go", - "name": "create", - "start": 26, - "end": 69, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "creating", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.37:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Testing the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "creating", - "nodes": [ - { - "text": "Create", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function from ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-36" - }, - "file": "creating", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-36" - }, - "nodes": [ - { - "text": "Listing 1.36", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-36" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 37, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "creating.md", - "nodes": [ - { - "text": "First, we need to make sure the file does not already exist. To do this, we can use the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "os#Stat", - "href": "https://pkg.go.dev/os#Stat", - "target": "_blank" - }, - "file": "creating.md", - "nodes": [ - { - "atom": "code", - "file": "creating.md", - "nodes": [ - { - "text": "os.Stat", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/os#Stat" - } - ], - { - "text": " function to check if the file exists.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "creating.md", - "nodes": [ - { - "text": "Next, we can read the contents of the file using the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "os#ReadFile", - "href": "https://pkg.go.dev/os#ReadFile", - "target": "_blank" - }, - "file": "creating.md", - "nodes": [ - { - "atom": "code", - "file": "creating.md", - "nodes": [ - { - "text": "os.ReadFile", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/os#ReadFile" - } - ], - { - "text": " function. This function will read the entire contents of the file into a byte slice. If the file does not exist, the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "os#ReadFile", - "href": "https://pkg.go.dev/os#ReadFile", - "target": "_blank" - }, - "file": "creating.md", - "nodes": [ - { - "atom": "code", - "file": "creating.md", - "nodes": [ - { - "text": "os.ReadFile", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/os#ReadFile" - } - ], - { - "text": " function, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-38" - }, - "file": "creating.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-38" - }, - "nodes": [ - { - "text": "Listing 1.38", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-38" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", will return an error.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-38", - "type": "listing" - }, - "file": "creating.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "doc", - "os.ReadFile" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "doc": "os.ReadFile", - "exec": "go doc os.ReadFile" - }, - "expected_exit": 0, - "file": "creating", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc os.ReadFile\n\npackage os // import \u0026#34;os\u0026#34;\n\nfunc ReadFile(name string) ([]byte, error)\n ReadFile reads the named file and returns the contents. A successful call\n returns err == nil, not err == EOF. Because ReadFile reads the whole file,\n it does not treat an EOF from Read as an error to be reported.", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "os.ReadFile" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBvcyAvLyBpbXBvcnQgIm9zIgoKZnVuYyBSZWFkRmlsZShuYW1lIHN0cmluZykgKFtdYnl0ZSwgZXJyb3IpCiAgICBSZWFkRmlsZSByZWFkcyB0aGUgbmFtZWQgZmlsZSBhbmQgcmV0dXJucyB0aGUgY29udGVudHMuIEEgc3VjY2Vzc2Z1bCBjYWxsCiAgICByZXR1cm5zIGVyciA9PSBuaWwsIG5vdCBlcnIgPT0gRU9GLiBCZWNhdXNlIFJlYWRGaWxlIHJlYWRzIHRoZSB3aG9sZSBmaWxlLAogICAgaXQgZG9lcyBub3QgdHJlYXQgYW4gRU9GIGZyb20gUmVhZCBhcyBhbiBlcnJvciB0byBiZSByZXBvcnRlZC4=", - "duration": 835440000, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc os.ReadFile\n\npackage os // import \u0026#34;os\u0026#34;\n\nfunc ReadFile(name string) ([]byte, error)\n ReadFile reads the named file and returns the contents. A successful call\n returns err == nil, not err == EOF. Because ReadFile reads the whole file,\n it does not treat an EOF from Read as an error to be reported.", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "os.ReadFile" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBvcyAvLyBpbXBvcnQgIm9zIgoKZnVuYyBSZWFkRmlsZShuYW1lIHN0cmluZykgKFtdYnl0ZSwgZXJyb3IpCiAgICBSZWFkRmlsZSByZWFkcyB0aGUgbmFtZWQgZmlsZSBhbmQgcmV0dXJucyB0aGUgY29udGVudHMuIEEgc3VjY2Vzc2Z1bCBjYWxsCiAgICByZXR1cm5zIGVyciA9PSBuaWwsIG5vdCBlcnIgPT0gRU9GLiBCZWNhdXNlIFJlYWRGaWxlIHJlYWRzIHRoZSB3aG9sZSBmaWxlLAogICAgaXQgZG9lcyBub3QgdHJlYXQgYW4gRU9GIGZyb20gUmVhZCBhcyBhbiBlcnJvciB0byBiZSByZXBvcnRlZC4=", - "duration": 835440000, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "creating", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.38:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "os#ReadFile", - "href": "https://pkg.go.dev/os#ReadFile", - "target": "_blank" - }, - "file": "creating", - "nodes": [ - [ - { - "atom": "code", - "file": "creating", - "nodes": [ - { - "text": "os.ReadFile", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/os#ReadFile" - } - ], - { - "text": " function.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 38, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - { - "atom": "blockquote", - "file": "creating.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "creating.md", - "nodes": [ - { - "text": "Note: Care must be taken when using the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "os#ReadFile", - "href": "https://pkg.go.dev/os#ReadFile", - "target": "_blank" - }, - "file": "creating.md", - "nodes": [ - { - "atom": "code", - "file": "creating.md", - "nodes": [ - { - "text": "os.ReadFile", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/os#ReadFile" - } - ], - { - "text": " function. If the file is very large, it may cause your program to run out of memory.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "creating.md", - "nodes": [ - { - "text": "Finally, we can compare the contents of the file to the expected contents. The test output, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-39" - }, - "file": "creating.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-39" - }, - "nodes": [ - { - "text": "Listing 1.39", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-39" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", confirms that the file was created, and its contents are correct.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-39", - "type": "listing" - }, - "file": "creating.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "test", - "-v" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go test -v", - "src": "creating/src/creating", - "test": "-v" - }, - "expected_exit": 0, - "file": "creating", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go test -v\n\n=== RUN Test_Create\n=== PAUSE Test_Create\n=== CONT Test_Create\n--- PASS: Test_Create (0.01s)\nPASS\nok \tdemo\t0.816s", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "test", - "-v" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/14-files/creating/src/creating", - "stdout": "PT09IFJVTiAgIFRlc3RfQ3JlYXRlCj09PSBQQVVTRSBUZXN0X0NyZWF0ZQo9PT0gQ09OVCAgVGVzdF9DcmVhdGUKLS0tIFBBU1M6IFRlc3RfQ3JlYXRlICgwLjAxcykKUEFTUwpvayAgCWRlbW8JMC44MTZz", - "duration": 1476041542, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go test -v\n\n=== RUN Test_Create\n=== PAUSE Test_Create\n=== CONT Test_Create\n--- PASS: Test_Create (0.01s)\nPASS\nok \tdemo\t0.816s", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "test", - "-v" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/14-files/creating/src/creating", - "stdout": "PT09IFJVTiAgIFRlc3RfQ3JlYXRlCj09PSBQQVVTRSBUZXN0X0NyZWF0ZQo9PT0gQ09OVCAgVGVzdF9DcmVhdGUKLS0tIFBBU1M6IFRlc3RfQ3JlYXRlICgwLjAxcykKUEFTUwpvayAgCWRlbW8JMC44MTZz", - "duration": 1476041542, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "creating", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.39:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Test output from ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-37" - }, - "file": "creating", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-37" - }, - "nodes": [ - { - "text": "Listing 1.37", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-37" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 39, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "creating.md", - "nodes": [ - { - "text": "If we look directly at the file on disk, we can see that the file has been created, and its contents are correct.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-40", - "type": "listing" - }, - "file": "creating.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "cat", - "data/test.txt" - ], - "atom": "cmd", - "attributes": { - "exec": "cat data/test.txt", - "src": "creating/src/creating" - }, - "expected_exit": 0, - "file": "creating", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ cat data/test.txt\n\nHello, World!", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "cat", - "data/test.txt" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/14-files/creating/src/creating", - "stdout": "SGVsbG8sIFdvcmxkIQ==", - "duration": 906182333, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ cat data/test.txt\n\nHello, World!", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "cat", - "data/test.txt" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/14-files/creating/src/creating", - "stdout": "SGVsbG8sIFdvcmxkIQ==", - "duration": 906182333, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "creating", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.40:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Contents of ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-40" - }, - "file": "creating", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-40" - }, - "nodes": [ - { - "text": "Listing 1.40", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-40" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 40, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "creating.md", - "level": 2, - "nodes": [ - { - "text": "Truncation", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "creating.md", - "nodes": [ - { - "text": "If a file already exists, the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "os#Create", - "href": "https://pkg.go.dev/os#Create", - "target": "_blank" - }, - "file": "creating.md", - "nodes": [ - { - "atom": "code", - "file": "creating.md", - "nodes": [ - { - "text": "os.Create", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/os#Create" - } - ], - { - "text": " function will truncate the existing file's contents. This means that if a file already exists, and has contents, the file will erased before the new contents are written. This can lead to unexpected results.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "creating.md", - "nodes": [ - { - "text": "Consider the following example. In this test, we are creating a file and setting its contents. Then, we create the file again, this time with different contents. The original contents of the file are erased and replaced with the new contents.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-41", - "type": "listing" - }, - "file": "creating.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "creating", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "creating/src/truncating/demo_test.go#truncate" - }, - "lang": "go", - "nodes": [ - { - "content": "func Test_Create(t *testing.T) {\n\tt.Parallel()\n\n\tfp := \"data/test.txt\"\n\n\t// create the file and assert\n\t// the file should now equal the string\n\t// \"Hello, World!\"\n\tcreateTestFile(t, fp, []byte(\"Hello, World!\"))\n\n\t// create the file, again, and assert\n\t// the file should now equal the string\n\t// \"Hello, Universe!\"\n\tcreateTestFile(t, fp, []byte(\"Hello, Universe!\"))\n}", - "file": "creating/src/truncating/demo_test.go", - "lang": "go", - "name": "truncate", - "start": 27, - "end": 44, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "creating", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.41:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Using ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "os#Create", - "href": "https://pkg.go.dev/os#Create", - "target": "_blank" - }, - "file": "creating", - "nodes": [ - [ - { - "atom": "code", - "file": "creating", - "nodes": [ - { - "text": "os.Create", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/os#Create" - } - ], - { - "text": " will truncate, and replace, an existing file on disk.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 41, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "creating.md", - "nodes": [ - { - "text": "To keep the test clean, we can use a helper function, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-42" - }, - "file": "creating.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-42" - }, - "nodes": [ - { - "text": "Listing 1.42", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-42" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", to create a file, set its contents, and then assert that the contents are correct.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-42", - "type": "listing" - }, - "file": "creating.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "creating", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "creating/src/truncating/demo_test.go#file-helper" - }, - "lang": "go", - "nodes": [ - { - "content": "func createTestFile(t testing.TB, fp string, body []byte) {\n\tt.Helper()\n\n\t// create test data directory\n\tcreateTestData(t)\n\n\t// assert the file does not exist\n\t// by trying to stat it.\n\t// this should return an error\n\t_, err := os.Stat(fp)\n\tif err != nil {\n\t\tif !errors.Is(err, fs.ErrNotExist) {\n\t\t\tt.Fatal(err)\n\t\t}\n\t}\n\n\t// create the file\n\terr = Create(fp, body)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\t// read the file into memory\n\tb, err := ioutil.ReadFile(fp)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\tact := string(b)\n\texp := string(body)\n\n\t// assert the file contents are correct\n\tif exp != act {\n\t\tt.Fatalf(\"expected %s, got %s\", exp, act)\n\t}\n\n}", - "file": "creating/src/truncating/demo_test.go", - "lang": "go", - "name": "file-helper", - "start": 46, - "end": 85, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "atom": "hr", - "file": "creating", - "type": "*hype.Element" - }, - [ - { - "args": [ - "go", - "test", - "-v" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go test -v", - "src": "creating/src/truncating", - "test": "-v" - }, - "expected_exit": 0, - "file": "creating", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go test -v\n\n=== RUN Test_Create\n=== PAUSE Test_Create\n=== CONT Test_Create\n--- PASS: Test_Create (0.01s)\nPASS\nok \tdemo\t0.690s", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "test", - "-v" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/14-files/creating/src/truncating", - "stdout": "PT09IFJVTiAgIFRlc3RfQ3JlYXRlCj09PSBQQVVTRSBUZXN0X0NyZWF0ZQo9PT0gQ09OVCAgVGVzdF9DcmVhdGUKLS0tIFBBU1M6IFRlc3RfQ3JlYXRlICgwLjAxcykKUEFTUwpvayAgCWRlbW8JMC42OTBz", - "duration": 1316409375, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go test -v\n\n=== RUN Test_Create\n=== PAUSE Test_Create\n=== CONT Test_Create\n--- PASS: Test_Create (0.01s)\nPASS\nok \tdemo\t0.690s", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "test", - "-v" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/14-files/creating/src/truncating", - "stdout": "PT09IFJVTiAgIFRlc3RfQ3JlYXRlCj09PSBQQVVTRSBUZXN0X0NyZWF0ZQo9PT0gQ09OVCAgVGVzdF9DcmVhdGUKLS0tIFBBU1M6IFRlc3RfQ3JlYXRlICgwLjAxcykKUEFTUwpvayAgCWRlbW8JMC42OTBz", - "duration": 1316409375, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "creating", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.42:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "creating", - "nodes": [ - { - "text": "fileHelper", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 42, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "creating.md", - "nodes": [ - { - "text": "From the test output, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-42" - }, - "file": "creating.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-42" - }, - "nodes": [ - { - "text": "Listing 1.42", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-42" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", we can see that the original contents of the file were erased, and the new contents were written.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "creating.md", - "nodes": [ - { - "text": "A look at the file on disk, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-43" - }, - "file": "creating.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-43" - }, - "nodes": [ - { - "text": "Listing 1.43", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-43" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", confirms that the new content was written.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-43", - "type": "listing" - }, - "file": "creating.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "cat", - "data/test.txt" - ], - "atom": "cmd", - "attributes": { - "exec": "cat data/test.txt", - "src": "creating/src/truncating" - }, - "expected_exit": 0, - "file": "creating", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ cat data/test.txt\n\nHello, Universe!", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "cat", - "data/test.txt" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/14-files/creating/src/truncating", - "stdout": "SGVsbG8sIFVuaXZlcnNlIQ==", - "duration": 107075291, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ cat data/test.txt\n\nHello, Universe!", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "cat", - "data/test.txt" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/14-files/creating/src/truncating", - "stdout": "SGVsbG8sIFVuaXZlcnNlIQ==", - "duration": 107075291, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "creating", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.43:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Contents of ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-40" - }, - "file": "creating", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-40" - }, - "nodes": [ - { - "text": "Listing 1.40", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-40" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 43, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "title": "Creating Files", - "type": "*hype.Page" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "type": "*hype.Include" - } - ], - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "include", - "attributes": { - "src": "walk/fixed.md" - }, - "dir": "walk", - "file": "module.md", - "nodes": [ - [ - { - "atom": "page", - "file": "walk/fixed.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "h1", - "file": "walk/fixed.md", - "level": 1, - "nodes": [ - { - "text": "Fixing the Walk Tests", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "walk/fixed.md", - "nodes": [ - { - "text": "When we last looked at the tests for our ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "walk/fixed.md", - "nodes": [ - { - "text": "Walk", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function, we saw that the tests were failing, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-44" - }, - "file": "walk/fixed.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-44" - }, - "nodes": [ - { - "text": "Listing 1.44", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-44" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ". Our tests are failing because we have yet to create the files necessary. We have only created the directories.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-44", - "type": "listing" - }, - "file": "walk/fixed.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "test", - "-v" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go test -v", - "exit": "-1", - "src": "walk/src/mkdirall", - "test": "-v" - }, - "expected_exit": -1, - "file": "walk", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go test -v\n\n=== RUN Test_Walk\n=== PAUSE Test_Walk\n=== CONT Test_Walk\ncreating: data/.hidden\ncreating: data\ncreating: data\ncreating: data/e/f/_ignore\ncreating: data/e/f\ncreating: data/e/f\ncreating: data/e\ncreating: data/testdata\n demo_test.go:81: expected data/a.txt, data/b.txt, data/e/f/g.txt, data/e/f/h.txt, data/e/j.txt, got \n--- FAIL: Test_Walk (0.00s)\nFAIL\nexit status 1\nFAIL\tdemo\t0.520s", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "test", - "-v" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/14-files/walk/src/mkdirall", - "err": { - "Stderr": null - }, - "exit": 1, - "stdout": "PT09IFJVTiAgIFRlc3RfV2Fsawo9PT0gUEFVU0UgVGVzdF9XYWxrCj09PSBDT05UICBUZXN0X1dhbGsKY3JlYXRpbmc6IGRhdGEvLmhpZGRlbgpjcmVhdGluZzogZGF0YQpjcmVhdGluZzogZGF0YQpjcmVhdGluZzogZGF0YS9lL2YvX2lnbm9yZQpjcmVhdGluZzogZGF0YS9lL2YKY3JlYXRpbmc6IGRhdGEvZS9mCmNyZWF0aW5nOiBkYXRhL2UKY3JlYXRpbmc6IGRhdGEvdGVzdGRhdGEKICAgIGRlbW9fdGVzdC5nbzo4MTogZXhwZWN0ZWQgZGF0YS9hLnR4dCwgZGF0YS9iLnR4dCwgZGF0YS9lL2YvZy50eHQsIGRhdGEvZS9mL2gudHh0LCBkYXRhL2Uvai50eHQsIGdvdCAKLS0tIEZBSUw6IFRlc3RfV2FsayAoMC4wMHMpCkZBSUwKZXhpdCBzdGF0dXMgMQpGQUlMCWRlbW8JMC41MjBz", - "duration": 1534809708, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go test -v\n\n=== RUN Test_Walk\n=== PAUSE Test_Walk\n=== CONT Test_Walk\ncreating: data/.hidden\ncreating: data\ncreating: data\ncreating: data/e/f/_ignore\ncreating: data/e/f\ncreating: data/e/f\ncreating: data/e\ncreating: data/testdata\n demo_test.go:81: expected data/a.txt, data/b.txt, data/e/f/g.txt, data/e/f/h.txt, data/e/j.txt, got \n--- FAIL: Test_Walk (0.00s)\nFAIL\nexit status 1\nFAIL\tdemo\t0.520s", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "test", - "-v" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/14-files/walk/src/mkdirall", - "err": { - "Stderr": null - }, - "exit": 1, - "stdout": "PT09IFJVTiAgIFRlc3RfV2Fsawo9PT0gUEFVU0UgVGVzdF9XYWxrCj09PSBDT05UICBUZXN0X1dhbGsKY3JlYXRpbmc6IGRhdGEvLmhpZGRlbgpjcmVhdGluZzogZGF0YQpjcmVhdGluZzogZGF0YQpjcmVhdGluZzogZGF0YS9lL2YvX2lnbm9yZQpjcmVhdGluZzogZGF0YS9lL2YKY3JlYXRpbmc6IGRhdGEvZS9mCmNyZWF0aW5nOiBkYXRhL2UKY3JlYXRpbmc6IGRhdGEvdGVzdGRhdGEKICAgIGRlbW9fdGVzdC5nbzo4MTogZXhwZWN0ZWQgZGF0YS9hLnR4dCwgZGF0YS9iLnR4dCwgZGF0YS9lL2YvZy50eHQsIGRhdGEvZS9mL2gudHh0LCBkYXRhL2Uvai50eHQsIGdvdCAKLS0tIEZBSUw6IFRlc3RfV2FsayAoMC4wMHMpCkZBSUwKZXhpdCBzdGF0dXMgMQpGQUlMCWRlbW8JMC41MjBz", - "duration": 1534809708, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "walk", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.44:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Failing test output.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 44, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "walk/fixed.md", - "nodes": [ - { - "text": "A look at the filesystem, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-45" - }, - "file": "walk/fixed.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-45" - }, - "nodes": [ - { - "text": "Listing 1.45", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-45" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", confirms that the directories were created, but the files were not.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-45", - "type": "listing" - }, - "file": "walk/fixed.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "tree", - "-a" - ], - "atom": "cmd", - "attributes": { - "exec": "tree -a", - "src": "walk/src/mkdirall" - }, - "expected_exit": 0, - "file": "walk", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ tree -a\n\n.\n├── data\n│   ├── .hidden\n│   ├── e\n│   │   └── f\n│   │   └── _ignore\n│   └── testdata\n├── demo.go\n├── demo_test.go\n└── go.mod\n\n7 directories, 3 files", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "tree", - "-a" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/14-files/walk/src/mkdirall", - "stdout": "LgrilJzilIDilIAgZGF0YQrilILCoMKgIOKUnOKUgOKUgCAuaGlkZGVuCuKUgsKgwqAg4pSc4pSA4pSAIGUK4pSCwqDCoCDilILCoMKgIOKUlOKUgOKUgCBmCuKUgsKgwqAg4pSCwqDCoCAgICAg4pSU4pSA4pSAIF9pZ25vcmUK4pSCwqDCoCDilJTilIDilIAgdGVzdGRhdGEK4pSc4pSA4pSAIGRlbW8uZ28K4pSc4pSA4pSAIGRlbW9fdGVzdC5nbwrilJTilIDilIAgZ28ubW9kCgo3IGRpcmVjdG9yaWVzLCAzIGZpbGVz", - "duration": 481183500, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ tree -a\n\n.\n├── data\n│   ├── .hidden\n│   ├── e\n│   │   └── f\n│   │   └── _ignore\n│   └── testdata\n├── demo.go\n├── demo_test.go\n└── go.mod\n\n7 directories, 3 files", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "tree", - "-a" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/14-files/walk/src/mkdirall", - "stdout": "LgrilJzilIDilIAgZGF0YQrilILCoMKgIOKUnOKUgOKUgCAuaGlkZGVuCuKUgsKgwqAg4pSc4pSA4pSAIGUK4pSCwqDCoCDilILCoMKgIOKUlOKUgOKUgCBmCuKUgsKgwqAg4pSCwqDCoCAgICAg4pSU4pSA4pSAIF9pZ25vcmUK4pSCwqDCoCDilJTilIDilIAgdGVzdGRhdGEK4pSc4pSA4pSAIGRlbW8uZ28K4pSc4pSA4pSAIGRlbW9fdGVzdC5nbwrilJTilIDilIAgZ28ubW9kCgo3IGRpcmVjdG9yaWVzLCAzIGZpbGVz", - "duration": 481183500, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "walk", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.45:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Folders, but not files, were created in ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-44" - }, - "file": "walk", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-44" - }, - "nodes": [ - { - "text": "Listing 1.44", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-44" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 45, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "walk/fixed.md", - "level": 2, - "nodes": [ - { - "text": "Creating the Files", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "walk/fixed.md", - "nodes": [ - { - "text": "With knowledge of how to create files, we can now create the files necessary for our tests, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-46" - }, - "file": "walk/fixed.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-46" - }, - "nodes": [ - { - "text": "Listing 1.46", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-46" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-46", - "type": "listing" - }, - "file": "walk/fixed.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "walk", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "walk/src/fixed/demo_test.go#create" - }, - "lang": "go", - "nodes": [ - { - "content": "// create the test data files\nfor _, path := range list {\n\tdir := path\n\tif ext := filepath.Ext(path); len(ext) \u003e 0 {\n\t\tdir = filepath.Dir(path)\n\t}\n\n\tif err := os.MkdirAll(dir, 0755); err != nil {\n\t\t// ignore if the directory already exists\n\t\tif !errors.Is(err, fs.ErrExist) {\n\t\t\tt.Fatal(err)\n\t\t}\n\t}\n\n\tfmt.Println(\"creating\", path)\n\tf, err := os.Create(path)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\tfmt.Fprint(f, strings.ToUpper(path))\n\n\tif err := f.Close(); err != nil {\n\t\tt.Fatal(err)\n\t}\n\n}", - "file": "walk/src/fixed/demo_test.go", - "lang": "go", - "name": "create", - "start": 38, - "end": 66, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "atom": "hr", - "file": "walk", - "type": "*hype.Element" - }, - [ - { - "args": [ - "go", - "test", - "-v" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go test -v", - "src": "walk/src/fixed", - "test": "-v" - }, - "expected_exit": 0, - "file": "walk", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go test -v\n\n=== RUN Test_Walk\n=== PAUSE Test_Walk\n=== CONT Test_Walk\ncreating data/.hidden/d.txt\ncreating data/a.txt\ncreating data/b.txt\ncreating data/e/f/_ignore/i.txt\ncreating data/e/f/g.txt\ncreating data/e/f/h.txt\ncreating data/e/j.txt\ncreating data/testdata/c.txt\n--- PASS: Test_Walk (0.02s)\nPASS\nok \tdemo\t0.226s", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "test", - "-v" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/14-files/walk/src/fixed", - "stdout": "PT09IFJVTiAgIFRlc3RfV2Fsawo9PT0gUEFVU0UgVGVzdF9XYWxrCj09PSBDT05UICBUZXN0X1dhbGsKY3JlYXRpbmcgZGF0YS8uaGlkZGVuL2QudHh0CmNyZWF0aW5nIGRhdGEvYS50eHQKY3JlYXRpbmcgZGF0YS9iLnR4dApjcmVhdGluZyBkYXRhL2UvZi9faWdub3JlL2kudHh0CmNyZWF0aW5nIGRhdGEvZS9mL2cudHh0CmNyZWF0aW5nIGRhdGEvZS9mL2gudHh0CmNyZWF0aW5nIGRhdGEvZS9qLnR4dApjcmVhdGluZyBkYXRhL3Rlc3RkYXRhL2MudHh0Ci0tLSBQQVNTOiBUZXN0X1dhbGsgKDAuMDJzKQpQQVNTCm9rICAJZGVtbwkwLjIyNnM=", - "duration": 792712583, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go test -v\n\n=== RUN Test_Walk\n=== PAUSE Test_Walk\n=== CONT Test_Walk\ncreating data/.hidden/d.txt\ncreating data/a.txt\ncreating data/b.txt\ncreating data/e/f/_ignore/i.txt\ncreating data/e/f/g.txt\ncreating data/e/f/h.txt\ncreating data/e/j.txt\ncreating data/testdata/c.txt\n--- PASS: Test_Walk (0.02s)\nPASS\nok \tdemo\t0.226s", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "test", - "-v" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/14-files/walk/src/fixed", - "stdout": "PT09IFJVTiAgIFRlc3RfV2Fsawo9PT0gUEFVU0UgVGVzdF9XYWxrCj09PSBDT05UICBUZXN0X1dhbGsKY3JlYXRpbmcgZGF0YS8uaGlkZGVuL2QudHh0CmNyZWF0aW5nIGRhdGEvYS50eHQKY3JlYXRpbmcgZGF0YS9iLnR4dApjcmVhdGluZyBkYXRhL2UvZi9faWdub3JlL2kudHh0CmNyZWF0aW5nIGRhdGEvZS9mL2cudHh0CmNyZWF0aW5nIGRhdGEvZS9mL2gudHh0CmNyZWF0aW5nIGRhdGEvZS9qLnR4dApjcmVhdGluZyBkYXRhL3Rlc3RkYXRhL2MudHh0Ci0tLSBQQVNTOiBUZXN0X1dhbGsgKDAuMDJzKQpQQVNTCm9rICAJZGVtbwkwLjIyNnM=", - "duration": 792712583, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "walk", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.46:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Create files with ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "os#Create", - "href": "https://pkg.go.dev/os#Create", - "target": "_blank" - }, - "file": "walk", - "nodes": [ - [ - { - "atom": "code", - "file": "walk", - "nodes": [ - { - "text": "os.Create", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/os#Create" - } - ], - { - "text": ", and directories with ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "os#MkdirAll", - "href": "https://pkg.go.dev/os#MkdirAll", - "target": "_blank" - }, - "file": "walk", - "nodes": [ - [ - { - "atom": "code", - "file": "walk", - "nodes": [ - { - "text": "os.MkdirAll", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/os#MkdirAll" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 46, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "walk/fixed.md", - "nodes": [ - { - "text": "The tests are now passing, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-47" - }, - "file": "walk/fixed.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-47" - }, - "nodes": [ - { - "text": "Listing 1.47", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-47" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", and all files and directories are created as expected, and the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "walk/fixed.md", - "nodes": [ - { - "text": "Walk", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function is working as expected.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "walk/fixed.md", - "nodes": [ - { - "text": "A look at the filesystem, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-47" - }, - "file": "walk/fixed.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-47" - }, - "nodes": [ - { - "text": "Listing 1.47", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-47" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", confirms that the files were created as expected.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-47", - "type": "listing" - }, - "file": "walk/fixed.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "tree", - "-a" - ], - "atom": "cmd", - "attributes": { - "exec": "tree -a", - "src": "walk/src/fixed" - }, - "expected_exit": 0, - "file": "walk", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ tree -a\n\n.\n├── data\n│   ├── .hidden\n│   │   └── d.txt\n│   ├── a.txt\n│   ├── b.txt\n│   ├── e\n│   │   ├── f\n│   │   │   ├── _ignore\n│   │   │   │   └── i.txt\n│   │   │   ├── g.txt\n│   │   │   └── h.txt\n│   │   └── j.txt\n│   └── testdata\n│   └── c.txt\n├── demo.go\n├── demo_test.go\n└── go.mod\n\n7 directories, 11 files", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "tree", - "-a" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/14-files/walk/src/fixed", - "stdout": "LgrilJzilIDilIAgZGF0YQrilILCoMKgIOKUnOKUgOKUgCAuaGlkZGVuCuKUgsKgwqAg4pSCwqDCoCDilJTilIDilIAgZC50eHQK4pSCwqDCoCDilJzilIDilIAgYS50eHQK4pSCwqDCoCDilJzilIDilIAgYi50eHQK4pSCwqDCoCDilJzilIDilIAgZQrilILCoMKgIOKUgsKgwqAg4pSc4pSA4pSAIGYK4pSCwqDCoCDilILCoMKgIOKUgsKgwqAg4pSc4pSA4pSAIF9pZ25vcmUK4pSCwqDCoCDilILCoMKgIOKUgsKgwqAg4pSCwqDCoCDilJTilIDilIAgaS50eHQK4pSCwqDCoCDilILCoMKgIOKUgsKgwqAg4pSc4pSA4pSAIGcudHh0CuKUgsKgwqAg4pSCwqDCoCDilILCoMKgIOKUlOKUgOKUgCBoLnR4dArilILCoMKgIOKUgsKgwqAg4pSU4pSA4pSAIGoudHh0CuKUgsKgwqAg4pSU4pSA4pSAIHRlc3RkYXRhCuKUgsKgwqAgICAgIOKUlOKUgOKUgCBjLnR4dArilJzilIDilIAgZGVtby5nbwrilJzilIDilIAgZGVtb190ZXN0LmdvCuKUlOKUgOKUgCBnby5tb2QKCjcgZGlyZWN0b3JpZXMsIDExIGZpbGVz", - "duration": 420035417, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ tree -a\n\n.\n├── data\n│   ├── .hidden\n│   │   └── d.txt\n│   ├── a.txt\n│   ├── b.txt\n│   ├── e\n│   │   ├── f\n│   │   │   ├── _ignore\n│   │   │   │   └── i.txt\n│   │   │   ├── g.txt\n│   │   │   └── h.txt\n│   │   └── j.txt\n│   └── testdata\n│   └── c.txt\n├── demo.go\n├── demo_test.go\n└── go.mod\n\n7 directories, 11 files", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "tree", - "-a" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/14-files/walk/src/fixed", - "stdout": "LgrilJzilIDilIAgZGF0YQrilILCoMKgIOKUnOKUgOKUgCAuaGlkZGVuCuKUgsKgwqAg4pSCwqDCoCDilJTilIDilIAgZC50eHQK4pSCwqDCoCDilJzilIDilIAgYS50eHQK4pSCwqDCoCDilJzilIDilIAgYi50eHQK4pSCwqDCoCDilJzilIDilIAgZQrilILCoMKgIOKUgsKgwqAg4pSc4pSA4pSAIGYK4pSCwqDCoCDilILCoMKgIOKUgsKgwqAg4pSc4pSA4pSAIF9pZ25vcmUK4pSCwqDCoCDilILCoMKgIOKUgsKgwqAg4pSCwqDCoCDilJTilIDilIAgaS50eHQK4pSCwqDCoCDilILCoMKgIOKUgsKgwqAg4pSc4pSA4pSAIGcudHh0CuKUgsKgwqAg4pSCwqDCoCDilILCoMKgIOKUlOKUgOKUgCBoLnR4dArilILCoMKgIOKUgsKgwqAg4pSU4pSA4pSAIGoudHh0CuKUgsKgwqAg4pSU4pSA4pSAIHRlc3RkYXRhCuKUgsKgwqAgICAgIOKUlOKUgOKUgCBjLnR4dArilJzilIDilIAgZGVtby5nbwrilJzilIDilIAgZGVtb190ZXN0LmdvCuKUlOKUgOKUgCBnby5tb2QKCjcgZGlyZWN0b3JpZXMsIDExIGZpbGVz", - "duration": 420035417, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "walk", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.47:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The file system.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 47, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "title": "Fixing the Walk Tests", - "type": "*hype.Page" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "type": "*hype.Include" - } - ], - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "include", - "attributes": { - "src": "appending/appending.md" - }, - "dir": "appending", - "file": "module.md", - "nodes": [ - [ - { - "atom": "page", - "file": "appending.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "h1", - "file": "appending.md", - "level": 1, - "nodes": [ - { - "text": "Appending to Files", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "appending.md", - "nodes": [ - { - "text": "As we have seen when we use ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "os#Create", - "href": "https://pkg.go.dev/os#Create", - "target": "_blank" - }, - "file": "appending.md", - "nodes": [ - { - "atom": "code", - "file": "appending.md", - "nodes": [ - { - "text": "os.Create", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/os#Create" - } - ], - { - "text": " to create a file, if that file already exists, the file is overwritten. This is expected behavior when creating a new file. It would be strange to find previously written contents in a new file.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "appending.md", - "nodes": [ - { - "text": "There often plenty of times when we want to append to an existing file, instead of overwriting it. For example, we might want to append to a log file with new entries and not overwrite the previous log entries. In this case, we can use ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "os#OpenFile", - "href": "https://pkg.go.dev/os#OpenFile", - "target": "_blank" - }, - "file": "appending.md", - "nodes": [ - { - "atom": "code", - "file": "appending.md", - "nodes": [ - { - "text": "os.OpenFile", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/os#OpenFile" - } - ], - { - "text": " to open the file for appending.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-48", - "type": "listing" - }, - "file": "appending.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "doc", - "os.OpenFile" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "doc": "os.OpenFile", - "exec": "go doc os.OpenFile" - }, - "expected_exit": 0, - "file": "appending", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc os.OpenFile\n\npackage os // import \u0026#34;os\u0026#34;\n\nfunc OpenFile(name string, flag int, perm FileMode) (*File, error)\n OpenFile is the generalized open call; most users will use Open or Create\n instead. It opens the named file with specified flag (O_RDONLY etc.).\n If the file does not exist, and the O_CREATE flag is passed, it is created\n with mode perm (before umask). If successful, methods on the returned File\n can be used for I/O. If there is an error, it will be of type *PathError.", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "os.OpenFile" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBvcyAvLyBpbXBvcnQgIm9zIgoKZnVuYyBPcGVuRmlsZShuYW1lIHN0cmluZywgZmxhZyBpbnQsIHBlcm0gRmlsZU1vZGUpICgqRmlsZSwgZXJyb3IpCiAgICBPcGVuRmlsZSBpcyB0aGUgZ2VuZXJhbGl6ZWQgb3BlbiBjYWxsOyBtb3N0IHVzZXJzIHdpbGwgdXNlIE9wZW4gb3IgQ3JlYXRlCiAgICBpbnN0ZWFkLiBJdCBvcGVucyB0aGUgbmFtZWQgZmlsZSB3aXRoIHNwZWNpZmllZCBmbGFnIChPX1JET05MWSBldGMuKS4KICAgIElmIHRoZSBmaWxlIGRvZXMgbm90IGV4aXN0LCBhbmQgdGhlIE9fQ1JFQVRFIGZsYWcgaXMgcGFzc2VkLCBpdCBpcyBjcmVhdGVkCiAgICB3aXRoIG1vZGUgcGVybSAoYmVmb3JlIHVtYXNrKS4gSWYgc3VjY2Vzc2Z1bCwgbWV0aG9kcyBvbiB0aGUgcmV0dXJuZWQgRmlsZQogICAgY2FuIGJlIHVzZWQgZm9yIEkvTy4gSWYgdGhlcmUgaXMgYW4gZXJyb3IsIGl0IHdpbGwgYmUgb2YgdHlwZSAqUGF0aEVycm9yLg==", - "duration": 1112400583, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc os.OpenFile\n\npackage os // import \u0026#34;os\u0026#34;\n\nfunc OpenFile(name string, flag int, perm FileMode) (*File, error)\n OpenFile is the generalized open call; most users will use Open or Create\n instead. It opens the named file with specified flag (O_RDONLY etc.).\n If the file does not exist, and the O_CREATE flag is passed, it is created\n with mode perm (before umask). If successful, methods on the returned File\n can be used for I/O. If there is an error, it will be of type *PathError.", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "os.OpenFile" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBvcyAvLyBpbXBvcnQgIm9zIgoKZnVuYyBPcGVuRmlsZShuYW1lIHN0cmluZywgZmxhZyBpbnQsIHBlcm0gRmlsZU1vZGUpICgqRmlsZSwgZXJyb3IpCiAgICBPcGVuRmlsZSBpcyB0aGUgZ2VuZXJhbGl6ZWQgb3BlbiBjYWxsOyBtb3N0IHVzZXJzIHdpbGwgdXNlIE9wZW4gb3IgQ3JlYXRlCiAgICBpbnN0ZWFkLiBJdCBvcGVucyB0aGUgbmFtZWQgZmlsZSB3aXRoIHNwZWNpZmllZCBmbGFnIChPX1JET05MWSBldGMuKS4KICAgIElmIHRoZSBmaWxlIGRvZXMgbm90IGV4aXN0LCBhbmQgdGhlIE9fQ1JFQVRFIGZsYWcgaXMgcGFzc2VkLCBpdCBpcyBjcmVhdGVkCiAgICB3aXRoIG1vZGUgcGVybSAoYmVmb3JlIHVtYXNrKS4gSWYgc3VjY2Vzc2Z1bCwgbWV0aG9kcyBvbiB0aGUgcmV0dXJuZWQgRmlsZQogICAgY2FuIGJlIHVzZWQgZm9yIEkvTy4gSWYgdGhlcmUgaXMgYW4gZXJyb3IsIGl0IHdpbGwgYmUgb2YgdHlwZSAqUGF0aEVycm9yLg==", - "duration": 1112400583, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "appending", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.48:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "os#OpenFile", - "href": "https://pkg.go.dev/os#OpenFile", - "target": "_blank" - }, - "file": "appending", - "nodes": [ - [ - { - "atom": "code", - "file": "appending", - "nodes": [ - { - "text": "os.OpenFile", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/os#OpenFile" - } - ], - { - "text": " function.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 48, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "appending.md", - "nodes": [ - { - "text": "Consider ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-49" - }, - "file": "appending.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-49" - }, - "nodes": [ - { - "text": "Listing 1.49", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-49" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ". We have an ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "appending.md", - "nodes": [ - { - "text": "Append", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function that uses ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "os#OpenFile", - "href": "https://pkg.go.dev/os#OpenFile", - "target": "_blank" - }, - "file": "appending.md", - "nodes": [ - { - "atom": "code", - "file": "appending.md", - "nodes": [ - { - "text": "os.OpenFile", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/os#OpenFile" - } - ], - { - "text": " to open the file for appending. The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "os#OpenFile", - "href": "https://pkg.go.dev/os#OpenFile", - "target": "_blank" - }, - "file": "appending.md", - "nodes": [ - { - "atom": "code", - "file": "appending.md", - "nodes": [ - { - "text": "os.OpenFile", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/os#OpenFile" - } - ], - { - "text": " function can be configured with flags to tell Go how to open the file. In this example, we creating the file if it does not exist and appending to it if it does.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-49", - "type": "listing" - }, - "file": "appending.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "appending", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "appending/src/appending/demo.go#append" - }, - "lang": "go", - "nodes": [ - { - "content": "func Append(name string, body []byte) error {\n\t// if the file doesn't exist, create it, or append to the file\n\tf, err := os.OpenFile(name, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer f.Close()\n\n\t// write the body to the file\n\t_, err = f.Write(body)\n\treturn err\n}", - "file": "appending/src/appending/demo.go", - "lang": "go", - "name": "append", - "start": 24, - "end": 38, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "appending", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.49:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "appending", - "nodes": [ - { - "text": "Append", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 49, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "appending.md", - "nodes": [ - { - "text": "Next, we can write a test to confirm that the file is appended to properly, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-50" - }, - "file": "appending.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-50" - }, - "nodes": [ - { - "text": "Listing 1.50", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-50" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ". We can make use of our ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "appending.md", - "nodes": [ - { - "text": "createTestFile", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " helper to create the initial file and fill it with some data, but we will need a new helper to append to the file.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-50", - "type": "listing" - }, - "file": "appending.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "appending", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "appending/src/appending/demo_test.go#test" - }, - "lang": "go", - "nodes": [ - { - "content": "func Test_Append(t *testing.T) {\n\tt.Parallel()\n\n\tfp := \"data/test.txt\"\n\n\t// create the file and assert\n\t// the file should now equal the string\n\t// \"Hello, World!\"\n\tcreateTestFile(t, fp, []byte(\"Hello, World!\"))\n\n\t// create the file, again, and assert\n\t// the file should now equal the string\n\t// \"Hello, Universe!\"\n\tappendTestFile(t, fp, []byte(\"Hello, Universe!\"))\n}", - "file": "appending/src/appending/demo_test.go", - "lang": "go", - "name": "test", - "start": 26, - "end": 43, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "appending", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.50:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Testing the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "appending", - "nodes": [ - { - "text": "Append", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 50, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "appending.md", - "nodes": [ - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "appending.md", - "nodes": [ - { - "text": "appendTestFile", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " helper will read in the original contents of the file, append the new data, and then read the new contents of the file. Finally, we can compare the new contents of the file are equal to the original contents plus the new data.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-51", - "type": "listing" - }, - "file": "appending.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "appending", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "appending/src/appending/demo_test.go#append" - }, - "lang": "go", - "nodes": [ - { - "content": "func appendTestFile(t testing.TB, fp string, body []byte) {\n\tt.Helper()\n\n\t// read the existing file into memory\n\tbefore, err := os.ReadFile(fp)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\t// append the new data\n\tif err := Append(fp, body); err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\t// read the new file into memory\n\tafter, err := os.ReadFile(fp)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\t// assert the new file contents\n\t// contain the old and new data\n\t// Hello, World!Hello, Universe!\n\texp := string(append(before, body...))\n\tact := string(after)\n\n\tif exp != act {\n\t\tt.Fatalf(\"expected %s, got %s\", exp, act)\n\t}\n}", - "file": "appending/src/appending/demo_test.go", - "lang": "go", - "name": "append", - "start": 45, - "end": 77, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "atom": "hr", - "file": "appending", - "type": "*hype.Element" - }, - [ - { - "args": [ - "go", - "test", - "-v" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go test -v", - "src": "appending/src/appending", - "test": "-v" - }, - "expected_exit": 0, - "file": "appending", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go test -v\n\n=== RUN Test_Append\n=== PAUSE Test_Append\n=== CONT Test_Append\n--- PASS: Test_Append (0.00s)\nPASS\nok \tdemo\t0.599s", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "test", - "-v" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/14-files/appending/src/appending", - "stdout": "PT09IFJVTiAgIFRlc3RfQXBwZW5kCj09PSBQQVVTRSBUZXN0X0FwcGVuZAo9PT0gQ09OVCAgVGVzdF9BcHBlbmQKLS0tIFBBU1M6IFRlc3RfQXBwZW5kICgwLjAwcykKUEFTUwpvayAgCWRlbW8JMC41OTlz", - "duration": 2055623917, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go test -v\n\n=== RUN Test_Append\n=== PAUSE Test_Append\n=== CONT Test_Append\n--- PASS: Test_Append (0.00s)\nPASS\nok \tdemo\t0.599s", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "test", - "-v" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/14-files/appending/src/appending", - "stdout": "PT09IFJVTiAgIFRlc3RfQXBwZW5kCj09PSBQQVVTRSBUZXN0X0FwcGVuZAo9PT0gQ09OVCAgVGVzdF9BcHBlbmQKLS0tIFBBU1M6IFRlc3RfQXBwZW5kICgwLjAwcykKUEFTUwpvayAgCWRlbW8JMC41OTlz", - "duration": 2055623917, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "appending", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.51:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "appending", - "nodes": [ - { - "text": "appendTestFile", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " helper.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 51, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "appending.md", - "nodes": [ - { - "text": "The tests in ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-51" - }, - "file": "appending.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-51" - }, - "nodes": [ - { - "text": "Listing 1.51", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-51" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", show that the file is appended to properly. Finally, a look at the file system shows that the file is appended to properly, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-52" - }, - "file": "appending.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-52" - }, - "nodes": [ - { - "text": "Listing 1.52", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-52" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-52", - "type": "listing" - }, - "file": "appending.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "cat", - "data/test.txt" - ], - "atom": "cmd", - "attributes": { - "exec": "cat data/test.txt", - "src": "appending/src/appending" - }, - "expected_exit": 0, - "file": "appending", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ cat data/test.txt\n\nHello, World!Hello, Universe!", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "cat", - "data/test.txt" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/14-files/appending/src/appending", - "stdout": "SGVsbG8sIFdvcmxkIUhlbGxvLCBVbml2ZXJzZSE=", - "duration": 389127500, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ cat data/test.txt\n\nHello, World!Hello, Universe!", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "cat", - "data/test.txt" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/14-files/appending/src/appending", - "stdout": "SGVsbG8sIFdvcmxkIUhlbGxvLCBVbml2ZXJzZSE=", - "duration": 389127500, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "appending", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.52:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The contents of the file.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 52, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "title": "Appending to Files", - "type": "*hype.Page" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "type": "*hype.Include" - } - ], - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "include", - "attributes": { - "src": "reading/reading.md" - }, - "dir": "reading", - "file": "module.md", - "nodes": [ - [ - { - "atom": "page", - "file": "reading.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "h1", - "file": "reading.md", - "level": 1, - "nodes": [ - { - "text": "Reading Files", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "reading.md", - "nodes": [ - { - "text": "So far we have been reading files directly into memory using the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "os#ReadFile", - "href": "https://pkg.go.dev/os#ReadFile", - "target": "_blank" - }, - "file": "reading.md", - "nodes": [ - { - "atom": "code", - "file": "reading.md", - "nodes": [ - { - "text": "os.ReadFile", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/os#ReadFile" - } - ], - { - "text": " function. While this is a very simple way to read a file, it is not the most efficient way to do so. If the file is very large, reading it into memory may not be feasible. It may also not be necessary. For example, if had a media file, such as a video, we might only want to read its metadata at the beginning of the file, and then stop reading it before we get to the actual video data.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "reading.md", - "nodes": [ - { - "text": "Using interfaces, such as ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "io#Reader", - "href": "https://pkg.go.dev/io#Reader", - "target": "_blank" - }, - "file": "reading.md", - "nodes": [ - { - "atom": "code", - "file": "reading.md", - "nodes": [ - { - "text": "io.Reader", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/io#Reader" - } - ], - { - "text": " and ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "io#Writer", - "href": "https://pkg.go.dev/io#Writer", - "target": "_blank" - }, - "file": "reading.md", - "nodes": [ - { - "atom": "code", - "file": "reading.md", - "nodes": [ - { - "text": "io.Writer", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/io#Writer" - } - ], - { - "text": ", and we can read and write files in a more efficient way.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "reading.md", - "nodes": [ - { - "text": "Consider the following example. We are opening a file using ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "os#Open", - "href": "https://pkg.go.dev/os#Open", - "target": "_blank" - }, - "file": "reading.md", - "nodes": [ - { - "atom": "code", - "file": "reading.md", - "nodes": [ - { - "text": "os.Open", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/os#Open" - } - ], - { - "text": ", which returns an ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "os#File", - "href": "https://pkg.go.dev/os#File", - "target": "_blank" - }, - "file": "reading.md", - "nodes": [ - { - "atom": "code", - "file": "reading.md", - "nodes": [ - { - "text": "os.File", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/os#File" - } - ], - { - "text": " that implements the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "io#Reader", - "href": "https://pkg.go.dev/io#Reader", - "target": "_blank" - }, - "file": "reading.md", - "nodes": [ - { - "atom": "code", - "file": "reading.md", - "nodes": [ - { - "text": "io.Reader", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/io#Reader" - } - ], - { - "text": " interface. We are passing the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "reading.md", - "nodes": [ - { - "text": "Read", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function an ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "io#Writer", - "href": "https://pkg.go.dev/io#Writer", - "target": "_blank" - }, - "file": "reading.md", - "nodes": [ - { - "atom": "code", - "file": "reading.md", - "nodes": [ - { - "text": "io.Writer", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/io#Writer" - } - ], - { - "text": " as an argument. We can make use of both of these interfaces to use the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "io#Copy", - "href": "https://pkg.go.dev/io#Copy", - "target": "_blank" - }, - "file": "reading.md", - "nodes": [ - { - "atom": "code", - "file": "reading.md", - "nodes": [ - { - "text": "io.Copy", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/io#Copy" - } - ], - { - "text": " function to copy the contents of the file to the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "io#Writer", - "href": "https://pkg.go.dev/io#Writer", - "target": "_blank" - }, - "file": "reading.md", - "nodes": [ - { - "atom": "code", - "file": "reading.md", - "nodes": [ - { - "text": "io.Writer", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/io#Writer" - } - ], - { - "text": ". If this ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "io#Writer", - "href": "https://pkg.go.dev/io#Writer", - "target": "_blank" - }, - "file": "reading.md", - "nodes": [ - { - "atom": "code", - "file": "reading.md", - "nodes": [ - { - "text": "io.Writer", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/io#Writer" - } - ], - { - "text": " is another ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "os#File", - "href": "https://pkg.go.dev/os#File", - "target": "_blank" - }, - "file": "reading.md", - "nodes": [ - { - "atom": "code", - "file": "reading.md", - "nodes": [ - { - "text": "os.File", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/os#File" - } - ], - { - "text": " then ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "io#Copy", - "href": "https://pkg.go.dev/io#Copy", - "target": "_blank" - }, - "file": "reading.md", - "nodes": [ - { - "atom": "code", - "file": "reading.md", - "nodes": [ - { - "text": "io.Copy", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/io#Copy" - } - ], - { - "text": " will stream the data directly from one file to the other.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-53", - "type": "listing" - }, - "file": "reading.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "reading", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "reading/src/reading/demo.go#read" - }, - "lang": "go", - "nodes": [ - { - "content": "func Read(fp string, w io.Writer) error {\n\tf, err := os.Open(fp)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer f.Close()\n\n\t_, err = io.Copy(w, f)\n\treturn err\n}", - "file": "reading/src/reading/demo.go", - "lang": "go", - "name": "read", - "start": 8, - "end": 20, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "reading", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.53:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "reading", - "nodes": [ - { - "text": "Read", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 53, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "reading.md", - "nodes": [ - { - "text": "In the test we can use a ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "bytes#Buffer", - "href": "https://pkg.go.dev/bytes#Buffer", - "target": "_blank" - }, - "file": "reading.md", - "nodes": [ - { - "atom": "code", - "file": "reading.md", - "nodes": [ - { - "text": "bytes.Buffer", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/bytes#Buffer" - } - ], - { - "text": " as the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "io#Writer", - "href": "https://pkg.go.dev/io#Writer", - "target": "_blank" - }, - "file": "reading.md", - "nodes": [ - { - "atom": "code", - "file": "reading.md", - "nodes": [ - { - "text": "io.Writer", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/io#Writer" - } - ], - { - "text": " we pass to the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "reading.md", - "nodes": [ - { - "text": "Read", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function. This then allows us to assert the contents of the file were properly read.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - null, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-54", - "type": "listing" - }, - "file": "reading.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "reading", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "reading/src/reading/demo_test.go#test" - }, - "lang": "go", - "nodes": [ - { - "content": "func Test_Read(t *testing.T) {\n\tt.Parallel()\n\n\tbb := \u0026bytes.Buffer{}\n\n\terr := Read(\"data/test.txt\", bb)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\texp := \"Hello, World!\"\n\tact := bb.String()\n\n\tif exp != act {\n\t\tt.Fatalf(\"expected %s, got %s\", exp, act)\n\t}\n}", - "file": "reading/src/reading/demo_test.go", - "lang": "go", - "name": "test", - "start": 8, - "end": 27, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "atom": "hr", - "file": "reading", - "type": "*hype.Element" - }, - [ - { - "args": [ - "go", - "test", - "-v" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go test -v", - "src": "reading/src/reading", - "test": "-v" - }, - "expected_exit": 0, - "file": "reading", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go test -v\n\n=== RUN Test_Read\n=== PAUSE Test_Read\n=== CONT Test_Read\n--- PASS: Test_Read (0.00s)\nPASS\nok \tdemo\t0.177s", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "test", - "-v" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/14-files/reading/src/reading", - "stdout": "PT09IFJVTiAgIFRlc3RfUmVhZAo9PT0gUEFVU0UgVGVzdF9SZWFkCj09PSBDT05UICBUZXN0X1JlYWQKLS0tIFBBU1M6IFRlc3RfUmVhZCAoMC4wMHMpClBBU1MKb2sgIAlkZW1vCTAuMTc3cw==", - "duration": 629446542, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go test -v\n\n=== RUN Test_Read\n=== PAUSE Test_Read\n=== CONT Test_Read\n--- PASS: Test_Read (0.00s)\nPASS\nok \tdemo\t0.177s", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "test", - "-v" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/14-files/reading/src/reading", - "stdout": "PT09IFJVTiAgIFRlc3RfUmVhZAo9PT0gUEFVU0UgVGVzdF9SZWFkCj09PSBDT05UICBUZXN0X1JlYWQKLS0tIFBBU1M6IFRlc3RfUmVhZCAoMC4wMHMpClBBU1MKb2sgIAlkZW1vCTAuMTc3cw==", - "duration": 629446542, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "reading", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.54:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Testing the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "reading", - "nodes": [ - { - "text": "Read", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 54, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "title": "Reading Files", - "type": "*hype.Page" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "type": "*hype.Include" - } - ], - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "include", - "attributes": { - "src": "windows/windows.md" - }, - "dir": "windows", - "file": "module.md", - "nodes": [ - [ - { - "atom": "page", - "file": "windows.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "h1", - "file": "windows.md", - "level": 1, - "nodes": [ - { - "text": "Beware of Windows", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "windows.md", - "nodes": [ - { - "text": "When discussing file systems, special attention must be paid to Windows. While Go has a done a great job of abstracting away the differences between Windows and Unix file systems, it is still possible to run into some issues.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "windows.md", - "nodes": [ - { - "text": "The largest issue is that Windows has a different file path system than Unix. In Unix, a file path is a series of directories separated by slashes, while in Windows, a file path is a series of directories separated by backslashes.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "windows.md", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-plain", - "language": "plain" - }, - "file": "windows.md", - "lang": "plain", - "nodes": [ - { - "text": "Unix: /home/user/go/src/github.com/golang/example/\nWindows: C:\\Users\\user\\go\\src\\github.com\\golang\\example\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "windows.md", - "nodes": [ - { - "text": "Because of this difference, whenever we want to use a nested filepath in Go, we need to use a function that will convert the path to the correct format. The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "filepath#Join", - "href": "https://pkg.go.dev/filepath#Join", - "target": "_blank" - }, - "file": "windows.md", - "nodes": [ - { - "atom": "code", - "file": "windows.md", - "nodes": [ - { - "text": "filepath.Join", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/filepath#Join" - } - ], - { - "text": " function, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-55" - }, - "file": "windows.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-55" - }, - "nodes": [ - { - "text": "Listing 1.55", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-55" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", will do this for us.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-55", - "type": "listing" - }, - "file": "windows.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "doc", - "filepath.Join" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "doc": "filepath.Join", - "exec": "go doc filepath.Join" - }, - "expected_exit": 0, - "file": "windows", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc filepath.Join\n\npackage filepath // import \u0026#34;path/filepath\u0026#34;\n\nfunc Join(elem ...string) string\n Join joins any number of path elements into a single path, separating them\n with an OS specific Separator. Empty elements are ignored. The result is\n Cleaned. However, if the argument list is empty or all its elements are\n empty, Join returns an empty string. On Windows, the result will only be a\n UNC path if the first non-empty element is a UNC path.", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "filepath.Join" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBmaWxlcGF0aCAvLyBpbXBvcnQgInBhdGgvZmlsZXBhdGgiCgpmdW5jIEpvaW4oZWxlbSAuLi5zdHJpbmcpIHN0cmluZwogICAgSm9pbiBqb2lucyBhbnkgbnVtYmVyIG9mIHBhdGggZWxlbWVudHMgaW50byBhIHNpbmdsZSBwYXRoLCBzZXBhcmF0aW5nIHRoZW0KICAgIHdpdGggYW4gT1Mgc3BlY2lmaWMgU2VwYXJhdG9yLiBFbXB0eSBlbGVtZW50cyBhcmUgaWdub3JlZC4gVGhlIHJlc3VsdCBpcwogICAgQ2xlYW5lZC4gSG93ZXZlciwgaWYgdGhlIGFyZ3VtZW50IGxpc3QgaXMgZW1wdHkgb3IgYWxsIGl0cyBlbGVtZW50cyBhcmUKICAgIGVtcHR5LCBKb2luIHJldHVybnMgYW4gZW1wdHkgc3RyaW5nLiBPbiBXaW5kb3dzLCB0aGUgcmVzdWx0IHdpbGwgb25seSBiZSBhCiAgICBVTkMgcGF0aCBpZiB0aGUgZmlyc3Qgbm9uLWVtcHR5IGVsZW1lbnQgaXMgYSBVTkMgcGF0aC4=", - "duration": 1135548625, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc filepath.Join\n\npackage filepath // import \u0026#34;path/filepath\u0026#34;\n\nfunc Join(elem ...string) string\n Join joins any number of path elements into a single path, separating them\n with an OS specific Separator. Empty elements are ignored. The result is\n Cleaned. However, if the argument list is empty or all its elements are\n empty, Join returns an empty string. On Windows, the result will only be a\n UNC path if the first non-empty element is a UNC path.", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "filepath.Join" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBmaWxlcGF0aCAvLyBpbXBvcnQgInBhdGgvZmlsZXBhdGgiCgpmdW5jIEpvaW4oZWxlbSAuLi5zdHJpbmcpIHN0cmluZwogICAgSm9pbiBqb2lucyBhbnkgbnVtYmVyIG9mIHBhdGggZWxlbWVudHMgaW50byBhIHNpbmdsZSBwYXRoLCBzZXBhcmF0aW5nIHRoZW0KICAgIHdpdGggYW4gT1Mgc3BlY2lmaWMgU2VwYXJhdG9yLiBFbXB0eSBlbGVtZW50cyBhcmUgaWdub3JlZC4gVGhlIHJlc3VsdCBpcwogICAgQ2xlYW5lZC4gSG93ZXZlciwgaWYgdGhlIGFyZ3VtZW50IGxpc3QgaXMgZW1wdHkgb3IgYWxsIGl0cyBlbGVtZW50cyBhcmUKICAgIGVtcHR5LCBKb2luIHJldHVybnMgYW4gZW1wdHkgc3RyaW5nLiBPbiBXaW5kb3dzLCB0aGUgcmVzdWx0IHdpbGwgb25seSBiZSBhCiAgICBVTkMgcGF0aCBpZiB0aGUgZmlyc3Qgbm9uLWVtcHR5IGVsZW1lbnQgaXMgYSBVTkMgcGF0aC4=", - "duration": 1135548625, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "windows", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.55:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "filepath#Join", - "href": "https://pkg.go.dev/filepath#Join", - "target": "_blank" - }, - "file": "windows", - "nodes": [ - [ - { - "atom": "code", - "file": "windows", - "nodes": [ - { - "text": "filepath.Join", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/filepath#Join" - } - ], - { - "text": " function.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 55, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "windows.md", - "nodes": [ - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "filepath#Join", - "href": "https://pkg.go.dev/filepath#Join", - "target": "_blank" - }, - "file": "windows.md", - "nodes": [ - { - "atom": "code", - "file": "windows.md", - "nodes": [ - { - "text": "filepath.Join", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/filepath#Join" - } - ], - { - "text": " is a function that takes a variable number of paths, and joins them together with the appropriate ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "filepath#Separator", - "href": "https://pkg.go.dev/filepath#Separator", - "target": "_blank" - }, - "file": "windows.md", - "nodes": [ - { - "atom": "code", - "file": "windows.md", - "nodes": [ - { - "text": "filepath.Separator", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/filepath#Separator" - } - ], - { - "text": ". The result will be a string that is a valid path in the appropriate file system.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-56", - "type": "listing" - }, - "file": "windows.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "windows", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go" - }, - "file": "windows", - "lang": "go", - "nodes": [ - { - "text": "path := filepath.Join(\"home\", \"user\", \"go\", \"src\", \"github.com\", \"golang\", \"example\")\n// Unix: /home/user/go/src/github.com/golang/example/\n// Windows: C:\\Users\\user\\go\\src\\github.com\\golang\\example\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "windows", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.56:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Using ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "filepath#Join", - "href": "https://pkg.go.dev/filepath#Join", - "target": "_blank" - }, - "file": "windows", - "nodes": [ - [ - { - "atom": "code", - "file": "windows", - "nodes": [ - { - "text": "filepath.Join", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/filepath#Join" - } - ], - { - "text": " function to create platform specific file paths.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 56, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "windows.md", - "nodes": [ - { - "text": "As we will see shortly, when we use the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "fs", - "href": "https://pkg.go.dev/fs", - "target": "_blank" - }, - "file": "windows.md", - "nodes": [ - { - "atom": "code", - "file": "windows.md", - "nodes": [ - { - "text": "fs", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/fs" - } - ], - { - "text": " package, we can use ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "windows.md", - "nodes": [ - { - "text": "/", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " as the separator and the filepath will be converted to the correct format for the current operating system.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "title": "Beware of Windows", - "type": "*hype.Page" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "type": "*hype.Include" - } - ], - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "include", - "attributes": { - "src": "fs/fs.md" - }, - "dir": "fs", - "file": "module.md", - "nodes": [ - [ - { - "atom": "page", - "file": "fs.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "h1", - "file": "fs.md", - "level": 1, - "nodes": [ - { - "text": "The FS Package", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "fs.md", - "nodes": [ - { - "text": "In ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "href": "https://go.dev/doc/go1.16", - "target": "_blank" - }, - "file": "fs.md", - "nodes": [ - [ - { - "atom": "code", - "file": "fs.md", - "nodes": [ - { - "text": "go1.16", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://go.dev/doc/go1.16" - } - ], - { - "text": " the Go team wanted to introduce a long requested feature, the ability to embed files into a Go binary. There had been a variety of third-party tools that did this, but none of them were able to do it without a lot of work.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "fs.md", - "nodes": [ - { - "text": "A lot of these tools behaved in a similar way; if the file was found in their in-memory store, they would return it. If their store was empty, or didn't contain the file, the assumption was the file was in the filesystem, and they would read it from there. The Go team liked this approached as it was very friendly to developers. Using ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "fs.md", - "nodes": [ - { - "text": "go run", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ", to start you local web server, for example, would read HTML templates from disk, allowing for live updates. But, if built with ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "fs.md", - "nodes": [ - { - "text": "go build", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ", the binary would contain all of the HTML templates in memory, and the developer would have to manually update the binary to see file changes.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "fs.md", - "nodes": [ - { - "text": "In order to enable this feature, the Go team had to introduce a new set of interfaces for working with the filesystem. For this, they introduced the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "fs", - "href": "https://pkg.go.dev/fs", - "target": "_blank" - }, - "file": "fs.md", - "nodes": [ - { - "atom": "code", - "file": "fs.md", - "nodes": [ - { - "text": "fs", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/fs" - } - ], - { - "text": " package, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-57" - }, - "file": "fs.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-57" - }, - "nodes": [ - { - "text": "Listing 1.57", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-57" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ". While this package was introduced to help enable the new embedding feature, it provides a common interface for working with ", - "type": "hype.Text" - }, - { - "atom": "strong", - "file": "fs.md", - "nodes": [ - { - "text": "read-only", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " file systems. This allows us, as developers, to mock out the file system for testing or create our own file system implementations. For example, we can implement the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "io/fs#FS", - "href": "https://pkg.go.dev/io/fs#FS", - "target": "_blank" - }, - "file": "fs.md", - "nodes": [ - { - "atom": "code", - "file": "fs.md", - "nodes": [ - { - "text": "fs.FS", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/io/fs#FS" - } - ], - { - "text": " interface to create an Amazon S3 file system that is a drop-in replacement for the standard file system.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-57", - "type": "listing" - }, - "file": "fs.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "doc", - "fs" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "doc": "fs", - "exec": "go doc fs" - }, - "expected_exit": 0, - "file": "fs", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc fs\n\npackage fs // import \u0026#34;io/fs\u0026#34;\n\nPackage fs defines basic interfaces to a file system. A file system can be\nprovided by the host operating system but also by other packages.\n\nvar ErrInvalid = errInvalid() ...\nvar SkipAll = errors.New(\u0026#34;skip everything and stop the walk\u0026#34;)\nvar SkipDir = errors.New(\u0026#34;skip this directory\u0026#34;)\nfunc FormatDirEntry(dir DirEntry) string\nfunc FormatFileInfo(info FileInfo) string\nfunc Glob(fsys FS, pattern string) (matches []string, err error)\nfunc ReadFile(fsys FS, name string) ([]byte, error)\nfunc ValidPath(name string) bool\nfunc WalkDir(fsys FS, root string, fn WalkDirFunc) error\ntype DirEntry interface{ ... }\n func FileInfoToDirEntry(info FileInfo) DirEntry\n func ReadDir(fsys FS, name string) ([]DirEntry, error)\ntype FS interface{ ... }\n func Sub(fsys FS, dir string) (FS, error)\ntype File interface{ ... }\ntype FileInfo interface{ ... }\n func Stat(fsys FS, name string) (FileInfo, error)\ntype FileMode uint32\n const ModeDir FileMode = 1 \u0026lt;\u0026lt; (32 - 1 - iota) ...\ntype GlobFS interface{ ... }\ntype PathError struct{ ... }\ntype ReadDirFS interface{ ... }\ntype ReadDirFile interface{ ... }\ntype ReadFileFS interface{ ... }\ntype StatFS interface{ ... }\ntype SubFS interface{ ... }\ntype WalkDirFunc func(path string, d DirEntry, err error) error", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "fs" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBmcyAvLyBpbXBvcnQgImlvL2ZzIgoKUGFja2FnZSBmcyBkZWZpbmVzIGJhc2ljIGludGVyZmFjZXMgdG8gYSBmaWxlIHN5c3RlbS4gQSBmaWxlIHN5c3RlbSBjYW4gYmUKcHJvdmlkZWQgYnkgdGhlIGhvc3Qgb3BlcmF0aW5nIHN5c3RlbSBidXQgYWxzbyBieSBvdGhlciBwYWNrYWdlcy4KCnZhciBFcnJJbnZhbGlkID0gZXJySW52YWxpZCgpIC4uLgp2YXIgU2tpcEFsbCA9IGVycm9ycy5OZXcoInNraXAgZXZlcnl0aGluZyBhbmQgc3RvcCB0aGUgd2FsayIpCnZhciBTa2lwRGlyID0gZXJyb3JzLk5ldygic2tpcCB0aGlzIGRpcmVjdG9yeSIpCmZ1bmMgRm9ybWF0RGlyRW50cnkoZGlyIERpckVudHJ5KSBzdHJpbmcKZnVuYyBGb3JtYXRGaWxlSW5mbyhpbmZvIEZpbGVJbmZvKSBzdHJpbmcKZnVuYyBHbG9iKGZzeXMgRlMsIHBhdHRlcm4gc3RyaW5nKSAobWF0Y2hlcyBbXXN0cmluZywgZXJyIGVycm9yKQpmdW5jIFJlYWRGaWxlKGZzeXMgRlMsIG5hbWUgc3RyaW5nKSAoW11ieXRlLCBlcnJvcikKZnVuYyBWYWxpZFBhdGgobmFtZSBzdHJpbmcpIGJvb2wKZnVuYyBXYWxrRGlyKGZzeXMgRlMsIHJvb3Qgc3RyaW5nLCBmbiBXYWxrRGlyRnVuYykgZXJyb3IKdHlwZSBEaXJFbnRyeSBpbnRlcmZhY2V7IC4uLiB9CiAgICBmdW5jIEZpbGVJbmZvVG9EaXJFbnRyeShpbmZvIEZpbGVJbmZvKSBEaXJFbnRyeQogICAgZnVuYyBSZWFkRGlyKGZzeXMgRlMsIG5hbWUgc3RyaW5nKSAoW11EaXJFbnRyeSwgZXJyb3IpCnR5cGUgRlMgaW50ZXJmYWNleyAuLi4gfQogICAgZnVuYyBTdWIoZnN5cyBGUywgZGlyIHN0cmluZykgKEZTLCBlcnJvcikKdHlwZSBGaWxlIGludGVyZmFjZXsgLi4uIH0KdHlwZSBGaWxlSW5mbyBpbnRlcmZhY2V7IC4uLiB9CiAgICBmdW5jIFN0YXQoZnN5cyBGUywgbmFtZSBzdHJpbmcpIChGaWxlSW5mbywgZXJyb3IpCnR5cGUgRmlsZU1vZGUgdWludDMyCiAgICBjb25zdCBNb2RlRGlyIEZpbGVNb2RlID0gMSA8PCAoMzIgLSAxIC0gaW90YSkgLi4uCnR5cGUgR2xvYkZTIGludGVyZmFjZXsgLi4uIH0KdHlwZSBQYXRoRXJyb3Igc3RydWN0eyAuLi4gfQp0eXBlIFJlYWREaXJGUyBpbnRlcmZhY2V7IC4uLiB9CnR5cGUgUmVhZERpckZpbGUgaW50ZXJmYWNleyAuLi4gfQp0eXBlIFJlYWRGaWxlRlMgaW50ZXJmYWNleyAuLi4gfQp0eXBlIFN0YXRGUyBpbnRlcmZhY2V7IC4uLiB9CnR5cGUgU3ViRlMgaW50ZXJmYWNleyAuLi4gfQp0eXBlIFdhbGtEaXJGdW5jIGZ1bmMocGF0aCBzdHJpbmcsIGQgRGlyRW50cnksIGVyciBlcnJvcikgZXJyb3I=", - "duration": 1233820500, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc fs\n\npackage fs // import \u0026#34;io/fs\u0026#34;\n\nPackage fs defines basic interfaces to a file system. A file system can be\nprovided by the host operating system but also by other packages.\n\nvar ErrInvalid = errInvalid() ...\nvar SkipAll = errors.New(\u0026#34;skip everything and stop the walk\u0026#34;)\nvar SkipDir = errors.New(\u0026#34;skip this directory\u0026#34;)\nfunc FormatDirEntry(dir DirEntry) string\nfunc FormatFileInfo(info FileInfo) string\nfunc Glob(fsys FS, pattern string) (matches []string, err error)\nfunc ReadFile(fsys FS, name string) ([]byte, error)\nfunc ValidPath(name string) bool\nfunc WalkDir(fsys FS, root string, fn WalkDirFunc) error\ntype DirEntry interface{ ... }\n func FileInfoToDirEntry(info FileInfo) DirEntry\n func ReadDir(fsys FS, name string) ([]DirEntry, error)\ntype FS interface{ ... }\n func Sub(fsys FS, dir string) (FS, error)\ntype File interface{ ... }\ntype FileInfo interface{ ... }\n func Stat(fsys FS, name string) (FileInfo, error)\ntype FileMode uint32\n const ModeDir FileMode = 1 \u0026lt;\u0026lt; (32 - 1 - iota) ...\ntype GlobFS interface{ ... }\ntype PathError struct{ ... }\ntype ReadDirFS interface{ ... }\ntype ReadDirFile interface{ ... }\ntype ReadFileFS interface{ ... }\ntype StatFS interface{ ... }\ntype SubFS interface{ ... }\ntype WalkDirFunc func(path string, d DirEntry, err error) error", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "fs" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBmcyAvLyBpbXBvcnQgImlvL2ZzIgoKUGFja2FnZSBmcyBkZWZpbmVzIGJhc2ljIGludGVyZmFjZXMgdG8gYSBmaWxlIHN5c3RlbS4gQSBmaWxlIHN5c3RlbSBjYW4gYmUKcHJvdmlkZWQgYnkgdGhlIGhvc3Qgb3BlcmF0aW5nIHN5c3RlbSBidXQgYWxzbyBieSBvdGhlciBwYWNrYWdlcy4KCnZhciBFcnJJbnZhbGlkID0gZXJySW52YWxpZCgpIC4uLgp2YXIgU2tpcEFsbCA9IGVycm9ycy5OZXcoInNraXAgZXZlcnl0aGluZyBhbmQgc3RvcCB0aGUgd2FsayIpCnZhciBTa2lwRGlyID0gZXJyb3JzLk5ldygic2tpcCB0aGlzIGRpcmVjdG9yeSIpCmZ1bmMgRm9ybWF0RGlyRW50cnkoZGlyIERpckVudHJ5KSBzdHJpbmcKZnVuYyBGb3JtYXRGaWxlSW5mbyhpbmZvIEZpbGVJbmZvKSBzdHJpbmcKZnVuYyBHbG9iKGZzeXMgRlMsIHBhdHRlcm4gc3RyaW5nKSAobWF0Y2hlcyBbXXN0cmluZywgZXJyIGVycm9yKQpmdW5jIFJlYWRGaWxlKGZzeXMgRlMsIG5hbWUgc3RyaW5nKSAoW11ieXRlLCBlcnJvcikKZnVuYyBWYWxpZFBhdGgobmFtZSBzdHJpbmcpIGJvb2wKZnVuYyBXYWxrRGlyKGZzeXMgRlMsIHJvb3Qgc3RyaW5nLCBmbiBXYWxrRGlyRnVuYykgZXJyb3IKdHlwZSBEaXJFbnRyeSBpbnRlcmZhY2V7IC4uLiB9CiAgICBmdW5jIEZpbGVJbmZvVG9EaXJFbnRyeShpbmZvIEZpbGVJbmZvKSBEaXJFbnRyeQogICAgZnVuYyBSZWFkRGlyKGZzeXMgRlMsIG5hbWUgc3RyaW5nKSAoW11EaXJFbnRyeSwgZXJyb3IpCnR5cGUgRlMgaW50ZXJmYWNleyAuLi4gfQogICAgZnVuYyBTdWIoZnN5cyBGUywgZGlyIHN0cmluZykgKEZTLCBlcnJvcikKdHlwZSBGaWxlIGludGVyZmFjZXsgLi4uIH0KdHlwZSBGaWxlSW5mbyBpbnRlcmZhY2V7IC4uLiB9CiAgICBmdW5jIFN0YXQoZnN5cyBGUywgbmFtZSBzdHJpbmcpIChGaWxlSW5mbywgZXJyb3IpCnR5cGUgRmlsZU1vZGUgdWludDMyCiAgICBjb25zdCBNb2RlRGlyIEZpbGVNb2RlID0gMSA8PCAoMzIgLSAxIC0gaW90YSkgLi4uCnR5cGUgR2xvYkZTIGludGVyZmFjZXsgLi4uIH0KdHlwZSBQYXRoRXJyb3Igc3RydWN0eyAuLi4gfQp0eXBlIFJlYWREaXJGUyBpbnRlcmZhY2V7IC4uLiB9CnR5cGUgUmVhZERpckZpbGUgaW50ZXJmYWNleyAuLi4gfQp0eXBlIFJlYWRGaWxlRlMgaW50ZXJmYWNleyAuLi4gfQp0eXBlIFN0YXRGUyBpbnRlcmZhY2V7IC4uLiB9CnR5cGUgU3ViRlMgaW50ZXJmYWNleyAuLi4gfQp0eXBlIFdhbGtEaXJGdW5jIGZ1bmMocGF0aCBzdHJpbmcsIGQgRGlyRW50cnksIGVyciBlcnJvcikgZXJyb3I=", - "duration": 1233820500, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "fs", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.57:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "fs", - "href": "https://pkg.go.dev/fs", - "target": "_blank" - }, - "file": "fs", - "nodes": [ - [ - { - "atom": "code", - "file": "fs", - "nodes": [ - { - "text": "fs", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/fs" - } - ], - { - "text": " package.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 57, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - { - "atom": "blockquote", - "file": "fs.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "fs.md", - "nodes": [ - { - "text": "Note: The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "fs", - "href": "https://pkg.go.dev/fs", - "target": "_blank" - }, - "file": "fs.md", - "nodes": [ - { - "atom": "code", - "file": "fs.md", - "nodes": [ - { - "text": "fs", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/fs" - } - ], - { - "text": " package is for working with a \"read-only\" file system. It does not provide any methods for writing to the file system. You continue to use the previously discuss methods for creating files and directories.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "fs.md", - "level": 2, - "nodes": [ - { - "text": "The FS Interface", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "fs.md", - "nodes": [ - { - "text": "At the core of the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "fs", - "href": "https://pkg.go.dev/fs", - "target": "_blank" - }, - "file": "fs.md", - "nodes": [ - { - "atom": "code", - "file": "fs.md", - "nodes": [ - { - "text": "fs", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/fs" - } - ], - { - "text": " package are two interfaces; the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "io/fs#FS", - "href": "https://pkg.go.dev/io/fs#FS", - "target": "_blank" - }, - "file": "fs.md", - "nodes": [ - { - "atom": "code", - "file": "fs.md", - "nodes": [ - { - "text": "fs.FS", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/io/fs#FS" - } - ], - { - "text": " interface and the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "io/fs#File", - "href": "https://pkg.go.dev/io/fs#File", - "target": "_blank" - }, - "file": "fs.md", - "nodes": [ - { - "atom": "code", - "file": "fs.md", - "nodes": [ - { - "text": "fs.File", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/io/fs#File" - } - ], - { - "text": " interface.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "fs.md", - "nodes": [ - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "io/fs#FS", - "href": "https://pkg.go.dev/io/fs#FS", - "target": "_blank" - }, - "file": "fs.md", - "nodes": [ - { - "atom": "code", - "file": "fs.md", - "nodes": [ - { - "text": "fs.FS", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/io/fs#FS" - } - ], - { - "text": " interface is used to define a file system, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-58" - }, - "file": "fs.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-58" - }, - "nodes": [ - { - "text": "Listing 1.58", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-58" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ". To implement this interface you must define a method, named ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "fs.md", - "nodes": [ - { - "text": "Open", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " that accepts a path and returns a ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "io/fs#File", - "href": "https://pkg.go.dev/io/fs#File", - "target": "_blank" - }, - "file": "fs.md", - "nodes": [ - { - "atom": "code", - "file": "fs.md", - "nodes": [ - { - "text": "fs.File", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/io/fs#File" - } - ], - { - "text": " interface and a potential error.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-58", - "type": "listing" - }, - "file": "fs.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "doc", - "fs.FS" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "doc": "fs.FS", - "exec": "go doc fs.FS" - }, - "expected_exit": 0, - "file": "fs", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc fs.FS\n\npackage fs // import \u0026#34;io/fs\u0026#34;\n\ntype FS interface {\n\t// Open opens the named file.\n\t//\n\t// When Open returns an error, it should be of type *PathError\n\t// with the Op field set to \u0026#34;open\u0026#34;, the Path field set to name,\n\t// and the Err field describing the problem.\n\t//\n\t// Open should reject attempts to open names that do not satisfy\n\t// ValidPath(name), returning a *PathError with Err set to\n\t// ErrInvalid or ErrNotExist.\n\tOpen(name string) (File, error)\n}\n An FS provides access to a hierarchical file system.\n\n The FS interface is the minimum implementation required of the file system.\n A file system may implement additional interfaces, such as ReadFileFS,\n to provide additional or optimized functionality.\n\nfunc Sub(fsys FS, dir string) (FS, error)", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "fs.FS" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBmcyAvLyBpbXBvcnQgImlvL2ZzIgoKdHlwZSBGUyBpbnRlcmZhY2UgewoJLy8gT3BlbiBvcGVucyB0aGUgbmFtZWQgZmlsZS4KCS8vCgkvLyBXaGVuIE9wZW4gcmV0dXJucyBhbiBlcnJvciwgaXQgc2hvdWxkIGJlIG9mIHR5cGUgKlBhdGhFcnJvcgoJLy8gd2l0aCB0aGUgT3AgZmllbGQgc2V0IHRvICJvcGVuIiwgdGhlIFBhdGggZmllbGQgc2V0IHRvIG5hbWUsCgkvLyBhbmQgdGhlIEVyciBmaWVsZCBkZXNjcmliaW5nIHRoZSBwcm9ibGVtLgoJLy8KCS8vIE9wZW4gc2hvdWxkIHJlamVjdCBhdHRlbXB0cyB0byBvcGVuIG5hbWVzIHRoYXQgZG8gbm90IHNhdGlzZnkKCS8vIFZhbGlkUGF0aChuYW1lKSwgcmV0dXJuaW5nIGEgKlBhdGhFcnJvciB3aXRoIEVyciBzZXQgdG8KCS8vIEVyckludmFsaWQgb3IgRXJyTm90RXhpc3QuCglPcGVuKG5hbWUgc3RyaW5nKSAoRmlsZSwgZXJyb3IpCn0KICAgIEFuIEZTIHByb3ZpZGVzIGFjY2VzcyB0byBhIGhpZXJhcmNoaWNhbCBmaWxlIHN5c3RlbS4KCiAgICBUaGUgRlMgaW50ZXJmYWNlIGlzIHRoZSBtaW5pbXVtIGltcGxlbWVudGF0aW9uIHJlcXVpcmVkIG9mIHRoZSBmaWxlIHN5c3RlbS4KICAgIEEgZmlsZSBzeXN0ZW0gbWF5IGltcGxlbWVudCBhZGRpdGlvbmFsIGludGVyZmFjZXMsIHN1Y2ggYXMgUmVhZEZpbGVGUywKICAgIHRvIHByb3ZpZGUgYWRkaXRpb25hbCBvciBvcHRpbWl6ZWQgZnVuY3Rpb25hbGl0eS4KCmZ1bmMgU3ViKGZzeXMgRlMsIGRpciBzdHJpbmcpIChGUywgZXJyb3Ip", - "duration": 266678291, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc fs.FS\n\npackage fs // import \u0026#34;io/fs\u0026#34;\n\ntype FS interface {\n\t// Open opens the named file.\n\t//\n\t// When Open returns an error, it should be of type *PathError\n\t// with the Op field set to \u0026#34;open\u0026#34;, the Path field set to name,\n\t// and the Err field describing the problem.\n\t//\n\t// Open should reject attempts to open names that do not satisfy\n\t// ValidPath(name), returning a *PathError with Err set to\n\t// ErrInvalid or ErrNotExist.\n\tOpen(name string) (File, error)\n}\n An FS provides access to a hierarchical file system.\n\n The FS interface is the minimum implementation required of the file system.\n A file system may implement additional interfaces, such as ReadFileFS,\n to provide additional or optimized functionality.\n\nfunc Sub(fsys FS, dir string) (FS, error)", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "fs.FS" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBmcyAvLyBpbXBvcnQgImlvL2ZzIgoKdHlwZSBGUyBpbnRlcmZhY2UgewoJLy8gT3BlbiBvcGVucyB0aGUgbmFtZWQgZmlsZS4KCS8vCgkvLyBXaGVuIE9wZW4gcmV0dXJucyBhbiBlcnJvciwgaXQgc2hvdWxkIGJlIG9mIHR5cGUgKlBhdGhFcnJvcgoJLy8gd2l0aCB0aGUgT3AgZmllbGQgc2V0IHRvICJvcGVuIiwgdGhlIFBhdGggZmllbGQgc2V0IHRvIG5hbWUsCgkvLyBhbmQgdGhlIEVyciBmaWVsZCBkZXNjcmliaW5nIHRoZSBwcm9ibGVtLgoJLy8KCS8vIE9wZW4gc2hvdWxkIHJlamVjdCBhdHRlbXB0cyB0byBvcGVuIG5hbWVzIHRoYXQgZG8gbm90IHNhdGlzZnkKCS8vIFZhbGlkUGF0aChuYW1lKSwgcmV0dXJuaW5nIGEgKlBhdGhFcnJvciB3aXRoIEVyciBzZXQgdG8KCS8vIEVyckludmFsaWQgb3IgRXJyTm90RXhpc3QuCglPcGVuKG5hbWUgc3RyaW5nKSAoRmlsZSwgZXJyb3IpCn0KICAgIEFuIEZTIHByb3ZpZGVzIGFjY2VzcyB0byBhIGhpZXJhcmNoaWNhbCBmaWxlIHN5c3RlbS4KCiAgICBUaGUgRlMgaW50ZXJmYWNlIGlzIHRoZSBtaW5pbXVtIGltcGxlbWVudGF0aW9uIHJlcXVpcmVkIG9mIHRoZSBmaWxlIHN5c3RlbS4KICAgIEEgZmlsZSBzeXN0ZW0gbWF5IGltcGxlbWVudCBhZGRpdGlvbmFsIGludGVyZmFjZXMsIHN1Y2ggYXMgUmVhZEZpbGVGUywKICAgIHRvIHByb3ZpZGUgYWRkaXRpb25hbCBvciBvcHRpbWl6ZWQgZnVuY3Rpb25hbGl0eS4KCmZ1bmMgU3ViKGZzeXMgRlMsIGRpciBzdHJpbmcpIChGUywgZXJyb3Ip", - "duration": 266678291, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "fs", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.58:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "io/fs#FS", - "href": "https://pkg.go.dev/io/fs#FS", - "target": "_blank" - }, - "file": "fs", - "nodes": [ - [ - { - "atom": "code", - "file": "fs", - "nodes": [ - { - "text": "fs.FS", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/io/fs#FS" - } - ], - { - "text": " interface.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 58, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "fs.md", - "nodes": [ - { - "text": "There are already examples of the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "io/fs#FS", - "href": "https://pkg.go.dev/io/fs#FS", - "target": "_blank" - }, - "file": "fs.md", - "nodes": [ - { - "atom": "code", - "file": "fs.md", - "nodes": [ - { - "text": "fs.FS", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/io/fs#FS" - } - ], - { - "text": " interface in the standard library already, such as ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "os#DirFS", - "href": "https://pkg.go.dev/os#DirFS", - "target": "_blank" - }, - "file": "fs.md", - "nodes": [ - { - "atom": "code", - "file": "fs.md", - "nodes": [ - { - "text": "os.DirFS", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/os#DirFS" - } - ], - { - "text": ", ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "testing/fstest#MapFS", - "href": "https://pkg.go.dev/testing/fstest#MapFS", - "target": "_blank" - }, - "file": "fs.md", - "nodes": [ - { - "atom": "code", - "file": "fs.md", - "nodes": [ - { - "text": "fstest.MapFS", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/testing/fstest#MapFS" - } - ], - { - "text": ", and ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "embed#FS", - "href": "https://pkg.go.dev/embed#FS", - "target": "_blank" - }, - "file": "fs.md", - "nodes": [ - { - "atom": "code", - "file": "fs.md", - "nodes": [ - { - "text": "embed.FS", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/embed#FS" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "fs.md", - "level": 2, - "nodes": [ - { - "text": "The File Interface", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "fs.md", - "nodes": [ - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "io/fs#File", - "href": "https://pkg.go.dev/io/fs#File", - "target": "_blank" - }, - "file": "fs.md", - "nodes": [ - { - "atom": "code", - "file": "fs.md", - "nodes": [ - { - "text": "fs.File", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/io/fs#File" - } - ], - { - "text": " interface is used to define a file, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-59" - }, - "file": "fs.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-59" - }, - "nodes": [ - { - "text": "Listing 1.59", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-59" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ". While the interface for ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "io/fs#FS", - "href": "https://pkg.go.dev/io/fs#FS", - "target": "_blank" - }, - "file": "fs.md", - "nodes": [ - { - "atom": "code", - "file": "fs.md", - "nodes": [ - { - "text": "fs.FS", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/io/fs#FS" - } - ], - { - "text": " is very simple, the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "io/fs#File", - "href": "https://pkg.go.dev/io/fs#File", - "target": "_blank" - }, - "file": "fs.md", - "nodes": [ - { - "atom": "code", - "file": "fs.md", - "nodes": [ - { - "text": "fs.File", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/io/fs#File" - } - ], - { - "text": " interface is more complex. A file needs to be able to be read, closed, and able to return its own ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "io/fs#FileInfo", - "href": "https://pkg.go.dev/io/fs#FileInfo", - "target": "_blank" - }, - "file": "fs.md", - "nodes": [ - { - "atom": "code", - "file": "fs.md", - "nodes": [ - { - "text": "fs.FileInfo", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/io/fs#FileInfo" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-59", - "type": "listing" - }, - "file": "fs.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "doc", - "fs.File" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "doc": "fs.File", - "exec": "go doc fs.File" - }, - "expected_exit": 0, - "file": "fs", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc fs.File\n\npackage fs // import \u0026#34;io/fs\u0026#34;\n\ntype File interface {\n\tStat() (FileInfo, error)\n\tRead([]byte) (int, error)\n\tClose() error\n}\n A File provides access to a single file. The File interface is the minimum\n implementation required of the file. Directory files should also implement\n ReadDirFile. A file may implement io.ReaderAt or io.Seeker as optimizations.", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "fs.File" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBmcyAvLyBpbXBvcnQgImlvL2ZzIgoKdHlwZSBGaWxlIGludGVyZmFjZSB7CglTdGF0KCkgKEZpbGVJbmZvLCBlcnJvcikKCVJlYWQoW11ieXRlKSAoaW50LCBlcnJvcikKCUNsb3NlKCkgZXJyb3IKfQogICAgQSBGaWxlIHByb3ZpZGVzIGFjY2VzcyB0byBhIHNpbmdsZSBmaWxlLiBUaGUgRmlsZSBpbnRlcmZhY2UgaXMgdGhlIG1pbmltdW0KICAgIGltcGxlbWVudGF0aW9uIHJlcXVpcmVkIG9mIHRoZSBmaWxlLiBEaXJlY3RvcnkgZmlsZXMgc2hvdWxkIGFsc28gaW1wbGVtZW50CiAgICBSZWFkRGlyRmlsZS4gQSBmaWxlIG1heSBpbXBsZW1lbnQgaW8uUmVhZGVyQXQgb3IgaW8uU2Vla2VyIGFzIG9wdGltaXphdGlvbnMu", - "duration": 966313042, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc fs.File\n\npackage fs // import \u0026#34;io/fs\u0026#34;\n\ntype File interface {\n\tStat() (FileInfo, error)\n\tRead([]byte) (int, error)\n\tClose() error\n}\n A File provides access to a single file. The File interface is the minimum\n implementation required of the file. Directory files should also implement\n ReadDirFile. A file may implement io.ReaderAt or io.Seeker as optimizations.", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "fs.File" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBmcyAvLyBpbXBvcnQgImlvL2ZzIgoKdHlwZSBGaWxlIGludGVyZmFjZSB7CglTdGF0KCkgKEZpbGVJbmZvLCBlcnJvcikKCVJlYWQoW11ieXRlKSAoaW50LCBlcnJvcikKCUNsb3NlKCkgZXJyb3IKfQogICAgQSBGaWxlIHByb3ZpZGVzIGFjY2VzcyB0byBhIHNpbmdsZSBmaWxlLiBUaGUgRmlsZSBpbnRlcmZhY2UgaXMgdGhlIG1pbmltdW0KICAgIGltcGxlbWVudGF0aW9uIHJlcXVpcmVkIG9mIHRoZSBmaWxlLiBEaXJlY3RvcnkgZmlsZXMgc2hvdWxkIGFsc28gaW1wbGVtZW50CiAgICBSZWFkRGlyRmlsZS4gQSBmaWxlIG1heSBpbXBsZW1lbnQgaW8uUmVhZGVyQXQgb3IgaW8uU2Vla2VyIGFzIG9wdGltaXphdGlvbnMu", - "duration": 966313042, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "fs", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.59:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "io/fs#File", - "href": "https://pkg.go.dev/io/fs#File", - "target": "_blank" - }, - "file": "fs", - "nodes": [ - [ - { - "atom": "code", - "file": "fs", - "nodes": [ - { - "text": "fs.File", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/io/fs#File" - } - ], - { - "text": " interface.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 59, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "fs.md", - "nodes": [ - { - "text": "There are examples of ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "io/fs#File", - "href": "https://pkg.go.dev/io/fs#File", - "target": "_blank" - }, - "file": "fs.md", - "nodes": [ - { - "atom": "code", - "file": "fs.md", - "nodes": [ - { - "text": "fs.File", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/io/fs#File" - } - ], - { - "text": " in the standard library already, such as ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "os#File", - "href": "https://pkg.go.dev/os#File", - "target": "_blank" - }, - "file": "fs.md", - "nodes": [ - { - "atom": "code", - "file": "fs.md", - "nodes": [ - { - "text": "os.File", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/os#File" - } - ], - { - "text": " and ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "testing/fstest#MapFile", - "href": "https://pkg.go.dev/testing/fstest#MapFile", - "target": "_blank" - }, - "file": "fs.md", - "nodes": [ - { - "atom": "code", - "file": "fs.md", - "nodes": [ - { - "text": "fstest.MapFile", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/testing/fstest#MapFile" - } - ], - { - "text": ", ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-60" - }, - "file": "fs.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-60" - }, - "nodes": [ - { - "text": "Listing 1.60", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-60" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-60", - "type": "listing" - }, - "file": "fs.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "doc", - "fstest.MapFile" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "doc": "fstest.MapFile", - "exec": "go doc fstest.MapFile" - }, - "expected_exit": 0, - "file": "fs", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc fstest.MapFile\n\npackage fstest // import \u0026#34;testing/fstest\u0026#34;\n\ntype MapFile struct {\n\tData []byte // file content\n\tMode fs.FileMode // FileInfo.Mode\n\tModTime time.Time // FileInfo.ModTime\n\tSys any // FileInfo.Sys\n}\n A MapFile describes a single file in a MapFS.", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "fstest.MapFile" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBmc3Rlc3QgLy8gaW1wb3J0ICJ0ZXN0aW5nL2ZzdGVzdCIKCnR5cGUgTWFwRmlsZSBzdHJ1Y3QgewoJRGF0YSAgICBbXWJ5dGUgICAgICAvLyBmaWxlIGNvbnRlbnQKCU1vZGUgICAgZnMuRmlsZU1vZGUgLy8gRmlsZUluZm8uTW9kZQoJTW9kVGltZSB0aW1lLlRpbWUgICAvLyBGaWxlSW5mby5Nb2RUaW1lCglTeXMgICAgIGFueSAgICAgICAgIC8vIEZpbGVJbmZvLlN5cwp9CiAgICBBIE1hcEZpbGUgZGVzY3JpYmVzIGEgc2luZ2xlIGZpbGUgaW4gYSBNYXBGUy4=", - "duration": 122787458, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc fstest.MapFile\n\npackage fstest // import \u0026#34;testing/fstest\u0026#34;\n\ntype MapFile struct {\n\tData []byte // file content\n\tMode fs.FileMode // FileInfo.Mode\n\tModTime time.Time // FileInfo.ModTime\n\tSys any // FileInfo.Sys\n}\n A MapFile describes a single file in a MapFS.", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "fstest.MapFile" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBmc3Rlc3QgLy8gaW1wb3J0ICJ0ZXN0aW5nL2ZzdGVzdCIKCnR5cGUgTWFwRmlsZSBzdHJ1Y3QgewoJRGF0YSAgICBbXWJ5dGUgICAgICAvLyBmaWxlIGNvbnRlbnQKCU1vZGUgICAgZnMuRmlsZU1vZGUgLy8gRmlsZUluZm8uTW9kZQoJTW9kVGltZSB0aW1lLlRpbWUgICAvLyBGaWxlSW5mby5Nb2RUaW1lCglTeXMgICAgIGFueSAgICAgICAgIC8vIEZpbGVJbmZvLlN5cwp9CiAgICBBIE1hcEZpbGUgZGVzY3JpYmVzIGEgc2luZ2xlIGZpbGUgaW4gYSBNYXBGUy4=", - "duration": 122787458, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "fs", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.60:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "testing/fstest#MapFile", - "href": "https://pkg.go.dev/testing/fstest#MapFile", - "target": "_blank" - }, - "file": "fs", - "nodes": [ - [ - { - "atom": "code", - "file": "fs", - "nodes": [ - { - "text": "fstest.MapFile", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/testing/fstest#MapFile" - } - ], - { - "text": " implements ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "io/fs#File", - "href": "https://pkg.go.dev/io/fs#File", - "target": "_blank" - }, - "file": "fs", - "nodes": [ - [ - { - "atom": "code", - "file": "fs", - "nodes": [ - { - "text": "fs.File", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/io/fs#File" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 60, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "title": "The FS Package", - "type": "*hype.Page" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "type": "*hype.Include" - } - ], - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "include", - "attributes": { - "src": "fs/using.md" - }, - "dir": "fs", - "file": "module.md", - "nodes": [ - [ - { - "atom": "page", - "file": "fs/using.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "h1", - "file": "fs/using.md", - "level": 1, - "nodes": [ - { - "text": "Using the FS Interface", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "fs/using.md", - "nodes": [ - { - "text": "Previously, we had been using ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "filepath#WalkDir", - "href": "https://pkg.go.dev/filepath#WalkDir", - "target": "_blank" - }, - "file": "fs/using.md", - "nodes": [ - { - "atom": "code", - "file": "fs/using.md", - "nodes": [ - { - "text": "filepath.WalkDir", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/filepath#WalkDir" - } - ], - { - "text": " to walk the directory tree. This worked by walking the file system directly. As a result, we have to make sure that the file system is in the correct state before we can use it. As we have seen, this can cause a lot of setup work to be done. Either we have to keep a completely different folders for each test scenario we have, or we have to create all of the files and folders at the start of the test before we begin. This is a lot of work, and is often error prone.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-61", - "type": "listing" - }, - "file": "fs/using.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "doc", - "fs.WalkDir" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "doc": "fs.WalkDir", - "exec": "go doc fs.WalkDir" - }, - "expected_exit": 0, - "file": "fs", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc fs.WalkDir\n\npackage fs // import \u0026#34;io/fs\u0026#34;\n\nfunc WalkDir(fsys FS, root string, fn WalkDirFunc) error\n WalkDir walks the file tree rooted at root, calling fn for each file or\n directory in the tree, including root.\n\n All errors that arise visiting files and directories are filtered by fn:\n see the fs.WalkDirFunc documentation for details.\n\n The files are walked in lexical order, which makes the output deterministic\n but requires WalkDir to read an entire directory into memory before\n proceeding to walk that directory.\n\n WalkDir does not follow symbolic links found in directories, but if root\n itself is a symbolic link, its target will be walked.", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "fs.WalkDir" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBmcyAvLyBpbXBvcnQgImlvL2ZzIgoKZnVuYyBXYWxrRGlyKGZzeXMgRlMsIHJvb3Qgc3RyaW5nLCBmbiBXYWxrRGlyRnVuYykgZXJyb3IKICAgIFdhbGtEaXIgd2Fsa3MgdGhlIGZpbGUgdHJlZSByb290ZWQgYXQgcm9vdCwgY2FsbGluZyBmbiBmb3IgZWFjaCBmaWxlIG9yCiAgICBkaXJlY3RvcnkgaW4gdGhlIHRyZWUsIGluY2x1ZGluZyByb290LgoKICAgIEFsbCBlcnJvcnMgdGhhdCBhcmlzZSB2aXNpdGluZyBmaWxlcyBhbmQgZGlyZWN0b3JpZXMgYXJlIGZpbHRlcmVkIGJ5IGZuOgogICAgc2VlIHRoZSBmcy5XYWxrRGlyRnVuYyBkb2N1bWVudGF0aW9uIGZvciBkZXRhaWxzLgoKICAgIFRoZSBmaWxlcyBhcmUgd2Fsa2VkIGluIGxleGljYWwgb3JkZXIsIHdoaWNoIG1ha2VzIHRoZSBvdXRwdXQgZGV0ZXJtaW5pc3RpYwogICAgYnV0IHJlcXVpcmVzIFdhbGtEaXIgdG8gcmVhZCBhbiBlbnRpcmUgZGlyZWN0b3J5IGludG8gbWVtb3J5IGJlZm9yZQogICAgcHJvY2VlZGluZyB0byB3YWxrIHRoYXQgZGlyZWN0b3J5LgoKICAgIFdhbGtEaXIgZG9lcyBub3QgZm9sbG93IHN5bWJvbGljIGxpbmtzIGZvdW5kIGluIGRpcmVjdG9yaWVzLCBidXQgaWYgcm9vdAogICAgaXRzZWxmIGlzIGEgc3ltYm9saWMgbGluaywgaXRzIHRhcmdldCB3aWxsIGJlIHdhbGtlZC4=", - "duration": 188931750, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc fs.WalkDir\n\npackage fs // import \u0026#34;io/fs\u0026#34;\n\nfunc WalkDir(fsys FS, root string, fn WalkDirFunc) error\n WalkDir walks the file tree rooted at root, calling fn for each file or\n directory in the tree, including root.\n\n All errors that arise visiting files and directories are filtered by fn:\n see the fs.WalkDirFunc documentation for details.\n\n The files are walked in lexical order, which makes the output deterministic\n but requires WalkDir to read an entire directory into memory before\n proceeding to walk that directory.\n\n WalkDir does not follow symbolic links found in directories, but if root\n itself is a symbolic link, its target will be walked.", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "fs.WalkDir" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBmcyAvLyBpbXBvcnQgImlvL2ZzIgoKZnVuYyBXYWxrRGlyKGZzeXMgRlMsIHJvb3Qgc3RyaW5nLCBmbiBXYWxrRGlyRnVuYykgZXJyb3IKICAgIFdhbGtEaXIgd2Fsa3MgdGhlIGZpbGUgdHJlZSByb290ZWQgYXQgcm9vdCwgY2FsbGluZyBmbiBmb3IgZWFjaCBmaWxlIG9yCiAgICBkaXJlY3RvcnkgaW4gdGhlIHRyZWUsIGluY2x1ZGluZyByb290LgoKICAgIEFsbCBlcnJvcnMgdGhhdCBhcmlzZSB2aXNpdGluZyBmaWxlcyBhbmQgZGlyZWN0b3JpZXMgYXJlIGZpbHRlcmVkIGJ5IGZuOgogICAgc2VlIHRoZSBmcy5XYWxrRGlyRnVuYyBkb2N1bWVudGF0aW9uIGZvciBkZXRhaWxzLgoKICAgIFRoZSBmaWxlcyBhcmUgd2Fsa2VkIGluIGxleGljYWwgb3JkZXIsIHdoaWNoIG1ha2VzIHRoZSBvdXRwdXQgZGV0ZXJtaW5pc3RpYwogICAgYnV0IHJlcXVpcmVzIFdhbGtEaXIgdG8gcmVhZCBhbiBlbnRpcmUgZGlyZWN0b3J5IGludG8gbWVtb3J5IGJlZm9yZQogICAgcHJvY2VlZGluZyB0byB3YWxrIHRoYXQgZGlyZWN0b3J5LgoKICAgIFdhbGtEaXIgZG9lcyBub3QgZm9sbG93IHN5bWJvbGljIGxpbmtzIGZvdW5kIGluIGRpcmVjdG9yaWVzLCBidXQgaWYgcm9vdAogICAgaXRzZWxmIGlzIGEgc3ltYm9saWMgbGluaywgaXRzIHRhcmdldCB3aWxsIGJlIHdhbGtlZC4=", - "duration": 188931750, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "fs", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.61:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "io/fs#WalkDir", - "href": "https://pkg.go.dev/io/fs#WalkDir", - "target": "_blank" - }, - "file": "fs", - "nodes": [ - [ - { - "atom": "code", - "file": "fs", - "nodes": [ - { - "text": "fs.WalkDir", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/io/fs#WalkDir" - } - ], - { - "text": " function.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 61, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "fs/using.md", - "nodes": [ - { - "text": "If we use the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "io/fs#WalkDir", - "href": "https://pkg.go.dev/io/fs#WalkDir", - "target": "_blank" - }, - "file": "fs/using.md", - "nodes": [ - { - "atom": "code", - "file": "fs/using.md", - "nodes": [ - { - "text": "fs.WalkDir", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/io/fs#WalkDir" - } - ], - { - "text": " function, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-61" - }, - "file": "fs/using.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-61" - }, - "nodes": [ - { - "text": "Listing 1.61", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-61" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", instead, which takes, as its first argument, a ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "io/fs#FS", - "href": "https://pkg.go.dev/io/fs#FS", - "target": "_blank" - }, - "file": "fs/using.md", - "nodes": [ - { - "atom": "code", - "file": "fs/using.md", - "nodes": [ - { - "text": "fs.FS", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/io/fs#FS" - } - ], - { - "text": " implementation. Instead of walking the file system the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "io/fs#FS", - "href": "https://pkg.go.dev/io/fs#FS", - "target": "_blank" - }, - "file": "fs/using.md", - "nodes": [ - { - "atom": "code", - "file": "fs/using.md", - "nodes": [ - { - "text": "fs.FS", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/io/fs#FS" - } - ], - { - "text": " is walked instead.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-62", - "type": "listing" - }, - "file": "fs/using.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "fs", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "snippet": "walk", - "src": "fs/src/using/demo.go" - }, - "lang": "go", - "nodes": [ - { - "content": "func Walk(cab fs.FS) ([]string, error) {\n\tvar entries []string\n\n\terr := fs.WalkDir(cab, \".\", func(path string, d fs.DirEntry, err error) error {\n\n\t\t// if there was an error, return it\n\t\t// if there is an error, it is most likely\n\t\t// because an error was an encoutered trying\n\t\t// to read the top level directory\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\t// if the entry is a directory, handle it\n\t\tif d.IsDir() {\n\n\t\t\t// name of the file or directory\n\t\t\tname := d.Name()\n\n\t\t\t// if the directory is a dot return nil\n\t\t\t// this may be the root directory\n\t\t\tif name == \".\" || name == \"..\" {\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\t\t// if the directory name is \"testdata\"\n\t\t\t// or it starts with \".\"\n\t\t\t// or it starts with \"_\"\n\t\t\t// then return filepath.SkipDir\n\t\t\tif name == \"testdata\" || strings.HasPrefix(name, \".\") || strings.HasPrefix(name, \"_\") {\n\t\t\t\treturn fs.SkipDir\n\t\t\t}\n\n\t\t\treturn nil\n\t\t}\n\n\t\t// append the entry to the list\n\t\tentries = append(entries, path)\n\n\t\t// return nil to tell walk to continue\n\t\treturn nil\n\t})\n\n\treturn entries, err\n}", - "file": "fs/src/using/demo.go", - "lang": "go", - "name": "walk", - "start": 8, - "end": 57, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "fs", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.62:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Using the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "io/fs#WalkDir", - "href": "https://pkg.go.dev/io/fs#WalkDir", - "target": "_blank" - }, - "file": "fs", - "nodes": [ - [ - { - "atom": "code", - "file": "fs", - "nodes": [ - { - "text": "fs.WalkDir", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/io/fs#WalkDir" - } - ], - { - "text": " function.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 62, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "fs/using.md", - "nodes": [ - { - "text": "In ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-62" - }, - "file": "fs/using.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-62" - }, - "nodes": [ - { - "text": "Listing 1.62", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-62" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": " we can continue to use the same code inside of the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "io/fs#WalkFunc", - "href": "https://pkg.go.dev/io/fs#WalkFunc", - "target": "_blank" - }, - "file": "fs/using.md", - "nodes": [ - { - "atom": "code", - "file": "fs/using.md", - "nodes": [ - { - "text": "fs.WalkFunc", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/io/fs#WalkFunc" - } - ], - { - "text": " function as we did before. Our test code only needs two small changes now to make it work. The first is we an implementation of the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "io/fs#FS", - "href": "https://pkg.go.dev/io/fs#FS", - "target": "_blank" - }, - "file": "fs/using.md", - "nodes": [ - { - "atom": "code", - "file": "fs/using.md", - "nodes": [ - { - "text": "fs.FS", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/io/fs#FS" - } - ], - { - "text": " interface to pass to the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "fs/using.md", - "nodes": [ - { - "text": "Walk", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function. For now, we can use the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "os#DirFS", - "href": "https://pkg.go.dev/os#DirFS", - "target": "_blank" - }, - "file": "fs/using.md", - "nodes": [ - { - "atom": "code", - "file": "fs/using.md", - "nodes": [ - { - "text": "os.DirFS", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/os#DirFS" - } - ], - { - "text": " function, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-63" - }, - "file": "fs/using.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-63" - }, - "nodes": [ - { - "text": "Listing 1.63", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-63" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ". The implementation will be backed directly by the file system.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-63", - "type": "listing" - }, - "file": "fs/using.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "doc", - "os.DirFS" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "doc": "os.DirFS", - "exec": "go doc os.DirFS" - }, - "expected_exit": 0, - "file": "fs", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc os.DirFS\n\npackage os // import \u0026#34;os\u0026#34;\n\nfunc DirFS(dir string) fs.FS\n DirFS returns a file system (an fs.FS) for the tree of files rooted at the\n directory dir.\n\n Note that DirFS(\u0026#34;/prefix\u0026#34;) only guarantees that the Open calls\n it makes to the operating system will begin with \u0026#34;/prefix\u0026#34;:\n DirFS(\u0026#34;/prefix\u0026#34;).Open(\u0026#34;file\u0026#34;) is the same as os.Open(\u0026#34;/prefix/file\u0026#34;).\n So if /prefix/file is a symbolic link pointing outside the /prefix tree,\n then using DirFS does not stop the access any more than using os.Open does.\n Additionally, the root of the fs.FS returned for a relative path,\n DirFS(\u0026#34;prefix\u0026#34;), will be affected by later calls to Chdir. DirFS is\n therefore not a general substitute for a chroot-style security mechanism\n when the directory tree contains arbitrary content.\n\n The directory dir must not be \u0026#34;\u0026#34;.\n\n The result implements io/fs.StatFS, io/fs.ReadFileFS and io/fs.ReadDirFS.", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "os.DirFS" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBvcyAvLyBpbXBvcnQgIm9zIgoKZnVuYyBEaXJGUyhkaXIgc3RyaW5nKSBmcy5GUwogICAgRGlyRlMgcmV0dXJucyBhIGZpbGUgc3lzdGVtIChhbiBmcy5GUykgZm9yIHRoZSB0cmVlIG9mIGZpbGVzIHJvb3RlZCBhdCB0aGUKICAgIGRpcmVjdG9yeSBkaXIuCgogICAgTm90ZSB0aGF0IERpckZTKCIvcHJlZml4Iikgb25seSBndWFyYW50ZWVzIHRoYXQgdGhlIE9wZW4gY2FsbHMKICAgIGl0IG1ha2VzIHRvIHRoZSBvcGVyYXRpbmcgc3lzdGVtIHdpbGwgYmVnaW4gd2l0aCAiL3ByZWZpeCI6CiAgICBEaXJGUygiL3ByZWZpeCIpLk9wZW4oImZpbGUiKSBpcyB0aGUgc2FtZSBhcyBvcy5PcGVuKCIvcHJlZml4L2ZpbGUiKS4KICAgIFNvIGlmIC9wcmVmaXgvZmlsZSBpcyBhIHN5bWJvbGljIGxpbmsgcG9pbnRpbmcgb3V0c2lkZSB0aGUgL3ByZWZpeCB0cmVlLAogICAgdGhlbiB1c2luZyBEaXJGUyBkb2VzIG5vdCBzdG9wIHRoZSBhY2Nlc3MgYW55IG1vcmUgdGhhbiB1c2luZyBvcy5PcGVuIGRvZXMuCiAgICBBZGRpdGlvbmFsbHksIHRoZSByb290IG9mIHRoZSBmcy5GUyByZXR1cm5lZCBmb3IgYSByZWxhdGl2ZSBwYXRoLAogICAgRGlyRlMoInByZWZpeCIpLCB3aWxsIGJlIGFmZmVjdGVkIGJ5IGxhdGVyIGNhbGxzIHRvIENoZGlyLiBEaXJGUyBpcwogICAgdGhlcmVmb3JlIG5vdCBhIGdlbmVyYWwgc3Vic3RpdHV0ZSBmb3IgYSBjaHJvb3Qtc3R5bGUgc2VjdXJpdHkgbWVjaGFuaXNtCiAgICB3aGVuIHRoZSBkaXJlY3RvcnkgdHJlZSBjb250YWlucyBhcmJpdHJhcnkgY29udGVudC4KCiAgICBUaGUgZGlyZWN0b3J5IGRpciBtdXN0IG5vdCBiZSAiIi4KCiAgICBUaGUgcmVzdWx0IGltcGxlbWVudHMgaW8vZnMuU3RhdEZTLCBpby9mcy5SZWFkRmlsZUZTIGFuZCBpby9mcy5SZWFkRGlyRlMu", - "duration": 358128500, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc os.DirFS\n\npackage os // import \u0026#34;os\u0026#34;\n\nfunc DirFS(dir string) fs.FS\n DirFS returns a file system (an fs.FS) for the tree of files rooted at the\n directory dir.\n\n Note that DirFS(\u0026#34;/prefix\u0026#34;) only guarantees that the Open calls\n it makes to the operating system will begin with \u0026#34;/prefix\u0026#34;:\n DirFS(\u0026#34;/prefix\u0026#34;).Open(\u0026#34;file\u0026#34;) is the same as os.Open(\u0026#34;/prefix/file\u0026#34;).\n So if /prefix/file is a symbolic link pointing outside the /prefix tree,\n then using DirFS does not stop the access any more than using os.Open does.\n Additionally, the root of the fs.FS returned for a relative path,\n DirFS(\u0026#34;prefix\u0026#34;), will be affected by later calls to Chdir. DirFS is\n therefore not a general substitute for a chroot-style security mechanism\n when the directory tree contains arbitrary content.\n\n The directory dir must not be \u0026#34;\u0026#34;.\n\n The result implements io/fs.StatFS, io/fs.ReadFileFS and io/fs.ReadDirFS.", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "os.DirFS" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBvcyAvLyBpbXBvcnQgIm9zIgoKZnVuYyBEaXJGUyhkaXIgc3RyaW5nKSBmcy5GUwogICAgRGlyRlMgcmV0dXJucyBhIGZpbGUgc3lzdGVtIChhbiBmcy5GUykgZm9yIHRoZSB0cmVlIG9mIGZpbGVzIHJvb3RlZCBhdCB0aGUKICAgIGRpcmVjdG9yeSBkaXIuCgogICAgTm90ZSB0aGF0IERpckZTKCIvcHJlZml4Iikgb25seSBndWFyYW50ZWVzIHRoYXQgdGhlIE9wZW4gY2FsbHMKICAgIGl0IG1ha2VzIHRvIHRoZSBvcGVyYXRpbmcgc3lzdGVtIHdpbGwgYmVnaW4gd2l0aCAiL3ByZWZpeCI6CiAgICBEaXJGUygiL3ByZWZpeCIpLk9wZW4oImZpbGUiKSBpcyB0aGUgc2FtZSBhcyBvcy5PcGVuKCIvcHJlZml4L2ZpbGUiKS4KICAgIFNvIGlmIC9wcmVmaXgvZmlsZSBpcyBhIHN5bWJvbGljIGxpbmsgcG9pbnRpbmcgb3V0c2lkZSB0aGUgL3ByZWZpeCB0cmVlLAogICAgdGhlbiB1c2luZyBEaXJGUyBkb2VzIG5vdCBzdG9wIHRoZSBhY2Nlc3MgYW55IG1vcmUgdGhhbiB1c2luZyBvcy5PcGVuIGRvZXMuCiAgICBBZGRpdGlvbmFsbHksIHRoZSByb290IG9mIHRoZSBmcy5GUyByZXR1cm5lZCBmb3IgYSByZWxhdGl2ZSBwYXRoLAogICAgRGlyRlMoInByZWZpeCIpLCB3aWxsIGJlIGFmZmVjdGVkIGJ5IGxhdGVyIGNhbGxzIHRvIENoZGlyLiBEaXJGUyBpcwogICAgdGhlcmVmb3JlIG5vdCBhIGdlbmVyYWwgc3Vic3RpdHV0ZSBmb3IgYSBjaHJvb3Qtc3R5bGUgc2VjdXJpdHkgbWVjaGFuaXNtCiAgICB3aGVuIHRoZSBkaXJlY3RvcnkgdHJlZSBjb250YWlucyBhcmJpdHJhcnkgY29udGVudC4KCiAgICBUaGUgZGlyZWN0b3J5IGRpciBtdXN0IG5vdCBiZSAiIi4KCiAgICBUaGUgcmVzdWx0IGltcGxlbWVudHMgaW8vZnMuU3RhdEZTLCBpby9mcy5SZWFkRmlsZUZTIGFuZCBpby9mcy5SZWFkRGlyRlMu", - "duration": 358128500, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "fs", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.63:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "os#DirFS", - "href": "https://pkg.go.dev/os#DirFS", - "target": "_blank" - }, - "file": "fs", - "nodes": [ - [ - { - "atom": "code", - "file": "fs", - "nodes": [ - { - "text": "os.DirFS", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/os#DirFS" - } - ], - { - "text": " function.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 63, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "fs/using.md", - "level": 2, - "nodes": [ - { - "text": "File Paths", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "fs/using.md", - "nodes": [ - { - "text": "The other change we need to make is the expected paths. Before, we were expecting paths such as ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "fs/using.md", - "nodes": [ - { - "text": "/data/a.txt", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " returned from our ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "fs/using.md", - "nodes": [ - { - "text": "Walk", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function. However, when working with ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "io/fs#FS", - "href": "https://pkg.go.dev/io/fs#FS", - "target": "_blank" - }, - "file": "fs/using.md", - "nodes": [ - { - "atom": "code", - "file": "fs/using.md", - "nodes": [ - { - "text": "fs.FS", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/io/fs#FS" - } - ], - { - "text": " implementations, the paths returned are relative to the root of the implementation. In this case, we are using ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "fs/using.md", - "nodes": [ - { - "text": "os.DirFS(\"data\")", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " to create the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "io/fs#FS", - "href": "https://pkg.go.dev/io/fs#FS", - "target": "_blank" - }, - "file": "fs/using.md", - "nodes": [ - { - "atom": "code", - "file": "fs/using.md", - "nodes": [ - { - "text": "fs.FS", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/io/fs#FS" - } - ], - { - "text": " implementation. This places ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "fs/using.md", - "nodes": [ - { - "text": "data", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " at the root of the file system implementation and paths returned from the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "fs/using.md", - "nodes": [ - { - "text": "Walk", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function will be relative to this root.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - { - "atom": "blockquote", - "file": "fs/using.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "fs/using.md", - "nodes": [ - { - "text": "Note: Paths are expected to use ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "fs/using.md", - "nodes": [ - { - "text": "/", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " as the path separator, regardless of the operating system.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "fs/using.md", - "nodes": [ - { - "text": "We need to update our test code to for the relative paths, ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "fs/using.md", - "nodes": [ - { - "text": "a.txt", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ", to be returned instead of ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "fs/using.md", - "nodes": [ - { - "text": "/data/a.txt", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-64", - "type": "listing" - }, - "file": "fs/using.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "fs", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "fs/src/using/demo_test.go#test" - }, - "lang": "go", - "nodes": [ - { - "content": "func Test_Walk(t *testing.T) {\n\tt.Parallel()\n\n\texp := []string{\n\t\t\"a.txt\",\n\t\t\"b.txt\",\n\t\t\"e/f/g.txt\",\n\t\t\"e/f/h.txt\",\n\t\t\"e/j.txt\",\n\t}\n\n\tcab := os.DirFS(\"data\")\n\n\tact, err := Walk(cab)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\tes := strings.Join(exp, \", \")\n\tas := strings.Join(act, \", \")\n\n\tif es != as {\n\t\tt.Fatalf(\"expected %s, got %s\", es, as)\n\t}\n}", - "file": "fs/src/using/demo_test.go", - "lang": "go", - "name": "test", - "start": 9, - "end": 36, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "atom": "hr", - "file": "fs", - "type": "*hype.Element" - }, - [ - { - "args": [ - "go", - "test", - "-v" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go test -v", - "src": "fs/src/using", - "test": "-v" - }, - "expected_exit": 0, - "file": "fs", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go test -v\n\n=== RUN Test_Walk\n=== PAUSE Test_Walk\n=== CONT Test_Walk\n--- PASS: Test_Walk (0.00s)\nPASS\nok \tdemo\t0.673s", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "test", - "-v" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/14-files/fs/src/using", - "stdout": "PT09IFJVTiAgIFRlc3RfV2Fsawo9PT0gUEFVU0UgVGVzdF9XYWxrCj09PSBDT05UICBUZXN0X1dhbGsKLS0tIFBBU1M6IFRlc3RfV2FsayAoMC4wMHMpClBBU1MKb2sgIAlkZW1vCTAuNjczcw==", - "duration": 2137029334, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go test -v\n\n=== RUN Test_Walk\n=== PAUSE Test_Walk\n=== CONT Test_Walk\n--- PASS: Test_Walk (0.00s)\nPASS\nok \tdemo\t0.673s", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "test", - "-v" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/14-files/fs/src/using", - "stdout": "PT09IFJVTiAgIFRlc3RfV2Fsawo9PT0gUEFVU0UgVGVzdF9XYWxrCj09PSBDT05UICBUZXN0X1dhbGsKLS0tIFBBU1M6IFRlc3RfV2FsayAoMC4wMHMpClBBU1MKb2sgIAlkZW1vCTAuNjczcw==", - "duration": 2137029334, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "fs", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.64:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Testing the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "fs", - "nodes": [ - { - "text": "Walk", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 64, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "fs/using.md", - "nodes": [ - { - "text": "As we can see from the test output in ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-64" - }, - "file": "fs/using.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-64" - }, - "nodes": [ - { - "text": "Listing 1.64", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-64" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", we have successfully updated our code to use the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "io/fs#FS", - "href": "https://pkg.go.dev/io/fs#FS", - "target": "_blank" - }, - "file": "fs/using.md", - "nodes": [ - { - "atom": "code", - "file": "fs/using.md", - "nodes": [ - { - "text": "fs.FS", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/io/fs#FS" - } - ], - { - "text": " interface.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "title": "Using the FS Interface", - "type": "*hype.Page" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "type": "*hype.Include" - } - ], - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "include", - "attributes": { - "src": "fs/mock.md" - }, - "dir": "fs", - "file": "module.md", - "nodes": [ - [ - { - "atom": "page", - "file": "fs/mock.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "h1", - "file": "fs/mock.md", - "level": 1, - "nodes": [ - { - "text": "Mocking a File System", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "fs/mock.md", - "nodes": [ - { - "text": "One of the biggest advantages of now having interfaces for the file system is that it allows us to mock it out for testing. We no longer need to either have the files already on disk or have to create them before we can test our code. Instead, we just need to provide an interface that has that information already in it.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "fs/mock.md", - "nodes": [ - { - "text": "To help make testing easier, we can use the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "fstest", - "href": "https://pkg.go.dev/fstest", - "target": "_blank" - }, - "file": "fs/mock.md", - "nodes": [ - { - "atom": "code", - "file": "fs/mock.md", - "nodes": [ - { - "text": "fstest", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/fstest" - } - ], - { - "text": " package. In particular, we can use the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "testing/fstest#MapFS", - "href": "https://pkg.go.dev/testing/fstest#MapFS", - "target": "_blank" - }, - "file": "fs/mock.md", - "nodes": [ - { - "atom": "code", - "file": "fs/mock.md", - "nodes": [ - { - "text": "fstest.MapFS", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/testing/fstest#MapFS" - } - ], - { - "text": " type, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-65" - }, - "file": "fs/mock.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-65" - }, - "nodes": [ - { - "text": "Listing 1.65", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-65" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", to mock out a file system using a map.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-65", - "type": "listing" - }, - "file": "fs/mock.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "doc", - "fstest.MapFS" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "doc": "fstest.MapFS", - "exec": "go doc fstest.MapFS" - }, - "expected_exit": 0, - "file": "fs", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc fstest.MapFS\n\npackage fstest // import \u0026#34;testing/fstest\u0026#34;\n\ntype MapFS map[string]*MapFile\n A MapFS is a simple in-memory file system for use in tests, represented as\n a map from path names (arguments to Open) to information about the files or\n directories they represent.\n\n The map need not include parent directories for files contained in the map;\n those will be synthesized if needed. But a directory can still be included\n by setting the MapFile.Mode\u0026#39;s ModeDir bit; this may be necessary for\n detailed control over the directory\u0026#39;s FileInfo or to create an empty\n directory.\n\n File system operations read directly from the map, so that the file system\n can be changed by editing the map as needed. An implication is that file\n system operations must not run concurrently with changes to the map, which\n would be a race. Another implication is that opening or reading a directory\n requires iterating over the entire map, so a MapFS should typically be used\n with not more than a few hundred entries or directory reads.\n\nfunc (fsys MapFS) Glob(pattern string) ([]string, error)\nfunc (fsys MapFS) Open(name string) (fs.File, error)\nfunc (fsys MapFS) ReadDir(name string) ([]fs.DirEntry, error)\nfunc (fsys MapFS) ReadFile(name string) ([]byte, error)\nfunc (fsys MapFS) Stat(name string) (fs.FileInfo, error)\nfunc (fsys MapFS) Sub(dir string) (fs.FS, error)", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "fstest.MapFS" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBmc3Rlc3QgLy8gaW1wb3J0ICJ0ZXN0aW5nL2ZzdGVzdCIKCnR5cGUgTWFwRlMgbWFwW3N0cmluZ10qTWFwRmlsZQogICAgQSBNYXBGUyBpcyBhIHNpbXBsZSBpbi1tZW1vcnkgZmlsZSBzeXN0ZW0gZm9yIHVzZSBpbiB0ZXN0cywgcmVwcmVzZW50ZWQgYXMKICAgIGEgbWFwIGZyb20gcGF0aCBuYW1lcyAoYXJndW1lbnRzIHRvIE9wZW4pIHRvIGluZm9ybWF0aW9uIGFib3V0IHRoZSBmaWxlcyBvcgogICAgZGlyZWN0b3JpZXMgdGhleSByZXByZXNlbnQuCgogICAgVGhlIG1hcCBuZWVkIG5vdCBpbmNsdWRlIHBhcmVudCBkaXJlY3RvcmllcyBmb3IgZmlsZXMgY29udGFpbmVkIGluIHRoZSBtYXA7CiAgICB0aG9zZSB3aWxsIGJlIHN5bnRoZXNpemVkIGlmIG5lZWRlZC4gQnV0IGEgZGlyZWN0b3J5IGNhbiBzdGlsbCBiZSBpbmNsdWRlZAogICAgYnkgc2V0dGluZyB0aGUgTWFwRmlsZS5Nb2RlJ3MgTW9kZURpciBiaXQ7IHRoaXMgbWF5IGJlIG5lY2Vzc2FyeSBmb3IKICAgIGRldGFpbGVkIGNvbnRyb2wgb3ZlciB0aGUgZGlyZWN0b3J5J3MgRmlsZUluZm8gb3IgdG8gY3JlYXRlIGFuIGVtcHR5CiAgICBkaXJlY3RvcnkuCgogICAgRmlsZSBzeXN0ZW0gb3BlcmF0aW9ucyByZWFkIGRpcmVjdGx5IGZyb20gdGhlIG1hcCwgc28gdGhhdCB0aGUgZmlsZSBzeXN0ZW0KICAgIGNhbiBiZSBjaGFuZ2VkIGJ5IGVkaXRpbmcgdGhlIG1hcCBhcyBuZWVkZWQuIEFuIGltcGxpY2F0aW9uIGlzIHRoYXQgZmlsZQogICAgc3lzdGVtIG9wZXJhdGlvbnMgbXVzdCBub3QgcnVuIGNvbmN1cnJlbnRseSB3aXRoIGNoYW5nZXMgdG8gdGhlIG1hcCwgd2hpY2gKICAgIHdvdWxkIGJlIGEgcmFjZS4gQW5vdGhlciBpbXBsaWNhdGlvbiBpcyB0aGF0IG9wZW5pbmcgb3IgcmVhZGluZyBhIGRpcmVjdG9yeQogICAgcmVxdWlyZXMgaXRlcmF0aW5nIG92ZXIgdGhlIGVudGlyZSBtYXAsIHNvIGEgTWFwRlMgc2hvdWxkIHR5cGljYWxseSBiZSB1c2VkCiAgICB3aXRoIG5vdCBtb3JlIHRoYW4gYSBmZXcgaHVuZHJlZCBlbnRyaWVzIG9yIGRpcmVjdG9yeSByZWFkcy4KCmZ1bmMgKGZzeXMgTWFwRlMpIEdsb2IocGF0dGVybiBzdHJpbmcpIChbXXN0cmluZywgZXJyb3IpCmZ1bmMgKGZzeXMgTWFwRlMpIE9wZW4obmFtZSBzdHJpbmcpIChmcy5GaWxlLCBlcnJvcikKZnVuYyAoZnN5cyBNYXBGUykgUmVhZERpcihuYW1lIHN0cmluZykgKFtdZnMuRGlyRW50cnksIGVycm9yKQpmdW5jIChmc3lzIE1hcEZTKSBSZWFkRmlsZShuYW1lIHN0cmluZykgKFtdYnl0ZSwgZXJyb3IpCmZ1bmMgKGZzeXMgTWFwRlMpIFN0YXQobmFtZSBzdHJpbmcpIChmcy5GaWxlSW5mbywgZXJyb3IpCmZ1bmMgKGZzeXMgTWFwRlMpIFN1YihkaXIgc3RyaW5nKSAoZnMuRlMsIGVycm9yKQ==", - "duration": 998349375, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc fstest.MapFS\n\npackage fstest // import \u0026#34;testing/fstest\u0026#34;\n\ntype MapFS map[string]*MapFile\n A MapFS is a simple in-memory file system for use in tests, represented as\n a map from path names (arguments to Open) to information about the files or\n directories they represent.\n\n The map need not include parent directories for files contained in the map;\n those will be synthesized if needed. But a directory can still be included\n by setting the MapFile.Mode\u0026#39;s ModeDir bit; this may be necessary for\n detailed control over the directory\u0026#39;s FileInfo or to create an empty\n directory.\n\n File system operations read directly from the map, so that the file system\n can be changed by editing the map as needed. An implication is that file\n system operations must not run concurrently with changes to the map, which\n would be a race. Another implication is that opening or reading a directory\n requires iterating over the entire map, so a MapFS should typically be used\n with not more than a few hundred entries or directory reads.\n\nfunc (fsys MapFS) Glob(pattern string) ([]string, error)\nfunc (fsys MapFS) Open(name string) (fs.File, error)\nfunc (fsys MapFS) ReadDir(name string) ([]fs.DirEntry, error)\nfunc (fsys MapFS) ReadFile(name string) ([]byte, error)\nfunc (fsys MapFS) Stat(name string) (fs.FileInfo, error)\nfunc (fsys MapFS) Sub(dir string) (fs.FS, error)", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "fstest.MapFS" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBmc3Rlc3QgLy8gaW1wb3J0ICJ0ZXN0aW5nL2ZzdGVzdCIKCnR5cGUgTWFwRlMgbWFwW3N0cmluZ10qTWFwRmlsZQogICAgQSBNYXBGUyBpcyBhIHNpbXBsZSBpbi1tZW1vcnkgZmlsZSBzeXN0ZW0gZm9yIHVzZSBpbiB0ZXN0cywgcmVwcmVzZW50ZWQgYXMKICAgIGEgbWFwIGZyb20gcGF0aCBuYW1lcyAoYXJndW1lbnRzIHRvIE9wZW4pIHRvIGluZm9ybWF0aW9uIGFib3V0IHRoZSBmaWxlcyBvcgogICAgZGlyZWN0b3JpZXMgdGhleSByZXByZXNlbnQuCgogICAgVGhlIG1hcCBuZWVkIG5vdCBpbmNsdWRlIHBhcmVudCBkaXJlY3RvcmllcyBmb3IgZmlsZXMgY29udGFpbmVkIGluIHRoZSBtYXA7CiAgICB0aG9zZSB3aWxsIGJlIHN5bnRoZXNpemVkIGlmIG5lZWRlZC4gQnV0IGEgZGlyZWN0b3J5IGNhbiBzdGlsbCBiZSBpbmNsdWRlZAogICAgYnkgc2V0dGluZyB0aGUgTWFwRmlsZS5Nb2RlJ3MgTW9kZURpciBiaXQ7IHRoaXMgbWF5IGJlIG5lY2Vzc2FyeSBmb3IKICAgIGRldGFpbGVkIGNvbnRyb2wgb3ZlciB0aGUgZGlyZWN0b3J5J3MgRmlsZUluZm8gb3IgdG8gY3JlYXRlIGFuIGVtcHR5CiAgICBkaXJlY3RvcnkuCgogICAgRmlsZSBzeXN0ZW0gb3BlcmF0aW9ucyByZWFkIGRpcmVjdGx5IGZyb20gdGhlIG1hcCwgc28gdGhhdCB0aGUgZmlsZSBzeXN0ZW0KICAgIGNhbiBiZSBjaGFuZ2VkIGJ5IGVkaXRpbmcgdGhlIG1hcCBhcyBuZWVkZWQuIEFuIGltcGxpY2F0aW9uIGlzIHRoYXQgZmlsZQogICAgc3lzdGVtIG9wZXJhdGlvbnMgbXVzdCBub3QgcnVuIGNvbmN1cnJlbnRseSB3aXRoIGNoYW5nZXMgdG8gdGhlIG1hcCwgd2hpY2gKICAgIHdvdWxkIGJlIGEgcmFjZS4gQW5vdGhlciBpbXBsaWNhdGlvbiBpcyB0aGF0IG9wZW5pbmcgb3IgcmVhZGluZyBhIGRpcmVjdG9yeQogICAgcmVxdWlyZXMgaXRlcmF0aW5nIG92ZXIgdGhlIGVudGlyZSBtYXAsIHNvIGEgTWFwRlMgc2hvdWxkIHR5cGljYWxseSBiZSB1c2VkCiAgICB3aXRoIG5vdCBtb3JlIHRoYW4gYSBmZXcgaHVuZHJlZCBlbnRyaWVzIG9yIGRpcmVjdG9yeSByZWFkcy4KCmZ1bmMgKGZzeXMgTWFwRlMpIEdsb2IocGF0dGVybiBzdHJpbmcpIChbXXN0cmluZywgZXJyb3IpCmZ1bmMgKGZzeXMgTWFwRlMpIE9wZW4obmFtZSBzdHJpbmcpIChmcy5GaWxlLCBlcnJvcikKZnVuYyAoZnN5cyBNYXBGUykgUmVhZERpcihuYW1lIHN0cmluZykgKFtdZnMuRGlyRW50cnksIGVycm9yKQpmdW5jIChmc3lzIE1hcEZTKSBSZWFkRmlsZShuYW1lIHN0cmluZykgKFtdYnl0ZSwgZXJyb3IpCmZ1bmMgKGZzeXMgTWFwRlMpIFN0YXQobmFtZSBzdHJpbmcpIChmcy5GaWxlSW5mbywgZXJyb3IpCmZ1bmMgKGZzeXMgTWFwRlMpIFN1YihkaXIgc3RyaW5nKSAoZnMuRlMsIGVycm9yKQ==", - "duration": 998349375, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "fs", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.65:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "testing/fstest#MapFS", - "href": "https://pkg.go.dev/testing/fstest#MapFS", - "target": "_blank" - }, - "file": "fs", - "nodes": [ - [ - { - "atom": "code", - "file": "fs", - "nodes": [ - { - "text": "fstest.MapFS", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/testing/fstest#MapFS" - } - ], - { - "text": " type.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 65, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "fs/mock.md", - "nodes": [ - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "testing/fstest#MapFile", - "href": "https://pkg.go.dev/testing/fstest#MapFile", - "target": "_blank" - }, - "file": "fs/mock.md", - "nodes": [ - { - "atom": "code", - "file": "fs/mock.md", - "nodes": [ - { - "text": "fstest.MapFile", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/testing/fstest#MapFile" - } - ], - { - "text": " type, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-66" - }, - "file": "fs/mock.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-66" - }, - "nodes": [ - { - "text": "Listing 1.66", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-66" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", is provided to help with creating files in memory and implementing the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "io/fs#File", - "href": "https://pkg.go.dev/io/fs#File", - "target": "_blank" - }, - "file": "fs/mock.md", - "nodes": [ - { - "atom": "code", - "file": "fs/mock.md", - "nodes": [ - { - "text": "fs.File", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/io/fs#File" - } - ], - { - "text": " interface.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-66", - "type": "listing" - }, - "file": "fs/mock.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "doc", - "fstest.MapFile" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "doc": "fstest.MapFile", - "exec": "go doc fstest.MapFile" - }, - "expected_exit": 0, - "file": "fs", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc fstest.MapFile\n\npackage fstest // import \u0026#34;testing/fstest\u0026#34;\n\ntype MapFile struct {\n\tData []byte // file content\n\tMode fs.FileMode // FileInfo.Mode\n\tModTime time.Time // FileInfo.ModTime\n\tSys any // FileInfo.Sys\n}\n A MapFile describes a single file in a MapFS.", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "fstest.MapFile" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBmc3Rlc3QgLy8gaW1wb3J0ICJ0ZXN0aW5nL2ZzdGVzdCIKCnR5cGUgTWFwRmlsZSBzdHJ1Y3QgewoJRGF0YSAgICBbXWJ5dGUgICAgICAvLyBmaWxlIGNvbnRlbnQKCU1vZGUgICAgZnMuRmlsZU1vZGUgLy8gRmlsZUluZm8uTW9kZQoJTW9kVGltZSB0aW1lLlRpbWUgICAvLyBGaWxlSW5mby5Nb2RUaW1lCglTeXMgICAgIGFueSAgICAgICAgIC8vIEZpbGVJbmZvLlN5cwp9CiAgICBBIE1hcEZpbGUgZGVzY3JpYmVzIGEgc2luZ2xlIGZpbGUgaW4gYSBNYXBGUy4=", - "duration": 1290460958, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc fstest.MapFile\n\npackage fstest // import \u0026#34;testing/fstest\u0026#34;\n\ntype MapFile struct {\n\tData []byte // file content\n\tMode fs.FileMode // FileInfo.Mode\n\tModTime time.Time // FileInfo.ModTime\n\tSys any // FileInfo.Sys\n}\n A MapFile describes a single file in a MapFS.", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "fstest.MapFile" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBmc3Rlc3QgLy8gaW1wb3J0ICJ0ZXN0aW5nL2ZzdGVzdCIKCnR5cGUgTWFwRmlsZSBzdHJ1Y3QgewoJRGF0YSAgICBbXWJ5dGUgICAgICAvLyBmaWxlIGNvbnRlbnQKCU1vZGUgICAgZnMuRmlsZU1vZGUgLy8gRmlsZUluZm8uTW9kZQoJTW9kVGltZSB0aW1lLlRpbWUgICAvLyBGaWxlSW5mby5Nb2RUaW1lCglTeXMgICAgIGFueSAgICAgICAgIC8vIEZpbGVJbmZvLlN5cwp9CiAgICBBIE1hcEZpbGUgZGVzY3JpYmVzIGEgc2luZ2xlIGZpbGUgaW4gYSBNYXBGUy4=", - "duration": 1290460958, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "fs", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.66:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "testing/fstest#MapFile", - "href": "https://pkg.go.dev/testing/fstest#MapFile", - "target": "_blank" - }, - "file": "fs", - "nodes": [ - [ - { - "atom": "code", - "file": "fs", - "nodes": [ - { - "text": "fstest.MapFile", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/testing/fstest#MapFile" - } - ], - { - "text": " type.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 66, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "fs/mock.md", - "level": 2, - "nodes": [ - { - "text": "Using MapFS", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "fs/mock.md", - "nodes": [ - { - "text": "Because the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "fs/mock.md", - "nodes": [ - { - "text": "Walk", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function already takes the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "io/fs#FS", - "href": "https://pkg.go.dev/io/fs#FS", - "target": "_blank" - }, - "file": "fs/mock.md", - "nodes": [ - { - "atom": "code", - "file": "fs/mock.md", - "nodes": [ - { - "text": "fs.FS", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/io/fs#FS" - } - ], - { - "text": " interface, we can use the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "testing/fstest#MapFS", - "href": "https://pkg.go.dev/testing/fstest#MapFS", - "target": "_blank" - }, - "file": "fs/mock.md", - "nodes": [ - { - "atom": "code", - "file": "fs/mock.md", - "nodes": [ - { - "text": "fstest.MapFS", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/testing/fstest#MapFS" - } - ], - { - "text": " type to create a file system that has the files we need for our test in it.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "fs/mock.md", - "nodes": [ - { - "text": "In ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-67" - }, - "file": "fs/mock.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-67" - }, - "nodes": [ - { - "text": "Listing 1.67", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-67" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": " we create a helper function that will create a new ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "testing/fstest#MapFS", - "href": "https://pkg.go.dev/testing/fstest#MapFS", - "target": "_blank" - }, - "file": "fs/mock.md", - "nodes": [ - { - "atom": "code", - "file": "fs/mock.md", - "nodes": [ - { - "text": "fstest.MapFS", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/testing/fstest#MapFS" - } - ], - { - "text": " type and fill it with the files we need.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-67", - "type": "listing" - }, - "file": "fs/mock.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "fs", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "fs/src/mock/demo_test.go#helper" - }, - "lang": "go", - "nodes": [ - { - "content": "func createTestFS(t testing.TB) fstest.MapFS {\n\tt.Helper()\n\n\tcab := fstest.MapFS{}\n\n\tfiles := []string{\n\t\t\".hidden/d.txt\",\n\t\t\"a.txt\",\n\t\t\"b.txt\",\n\t\t\"e/f/_ignore/i.txt\",\n\t\t\"e/f/g.txt\",\n\t\t\"e/f/h.txt\",\n\t\t\"e/j.txt\",\n\t\t\"testdata/c.txt\",\n\t}\n\n\tfor _, path := range files {\n\t\tcab[path] = \u0026fstest.MapFile{\n\t\t\tData: []byte(strings.ToUpper(path)),\n\t\t}\n\t}\n\treturn cab\n}", - "file": "fs/src/mock/demo_test.go", - "lang": "go", - "name": "helper", - "start": 9, - "end": 34, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "fs", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.67:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Creating a helper function to populate a ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "testing/fstest#MapFS", - "href": "https://pkg.go.dev/testing/fstest#MapFS", - "target": "_blank" - }, - "file": "fs", - "nodes": [ - [ - { - "atom": "code", - "file": "fs", - "nodes": [ - { - "text": "fstest.MapFS", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/testing/fstest#MapFS" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 67, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "fs/mock.md", - "nodes": [ - { - "text": "If we look at the file system directly, we can see that there are no additional files on disk for us to use in our tests. We are relying on the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "testing/fstest#MapFS", - "href": "https://pkg.go.dev/testing/fstest#MapFS", - "target": "_blank" - }, - "file": "fs/mock.md", - "nodes": [ - { - "atom": "code", - "file": "fs/mock.md", - "nodes": [ - { - "text": "fstest.MapFS", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/testing/fstest#MapFS" - } - ], - { - "text": " type to provide the files we need.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-68", - "type": "listing" - }, - "file": "fs/mock.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "tree", - "-a" - ], - "atom": "cmd", - "attributes": { - "exec": "tree -a", - "src": "fs/src/mock" - }, - "expected_exit": 0, - "file": "fs", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ tree -a\n\n.\n├── demo.go\n├── demo_test.go\n└── go.mod\n\n1 directory, 3 files", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "tree", - "-a" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/14-files/fs/src/mock", - "stdout": "LgrilJzilIDilIAgZGVtby5nbwrilJzilIDilIAgZGVtb190ZXN0LmdvCuKUlOKUgOKUgCBnby5tb2QKCjEgZGlyZWN0b3J5LCAzIGZpbGVz", - "duration": 75022666, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ tree -a\n\n.\n├── demo.go\n├── demo_test.go\n└── go.mod\n\n1 directory, 3 files", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "tree", - "-a" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/14-files/fs/src/mock", - "stdout": "LgrilJzilIDilIAgZGVtby5nbwrilJzilIDilIAgZGVtb190ZXN0LmdvCuKUlOKUgOKUgCBnby5tb2QKCjEgZGlyZWN0b3J5LCAzIGZpbGVz", - "duration": 75022666, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "fs", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.68:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "No additional test files are needed when using ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "testing/fstest#MapFS", - "href": "https://pkg.go.dev/testing/fstest#MapFS", - "target": "_blank" - }, - "file": "fs", - "nodes": [ - [ - { - "atom": "code", - "file": "fs", - "nodes": [ - { - "text": "fstest.MapFS", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/testing/fstest#MapFS" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 68, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "fs/mock.md", - "nodes": [ - { - "text": "Inside of the test itself, we can use the helper function to get the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "testing/fstest#MapFS", - "href": "https://pkg.go.dev/testing/fstest#MapFS", - "target": "_blank" - }, - "file": "fs/mock.md", - "nodes": [ - { - "atom": "code", - "file": "fs/mock.md", - "nodes": [ - { - "text": "fstest.MapFS", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/testing/fstest#MapFS" - } - ], - { - "text": " and pass that to the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "fs/mock.md", - "nodes": [ - { - "text": "Walk", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function, instead of the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "os#DirFS", - "href": "https://pkg.go.dev/os#DirFS", - "target": "_blank" - }, - "file": "fs/mock.md", - "nodes": [ - { - "atom": "code", - "file": "fs/mock.md", - "nodes": [ - { - "text": "os.DirFS", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/os#DirFS" - } - ], - { - "text": " implementation we were using before.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-69", - "type": "listing" - }, - "file": "fs/mock.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "fs", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "fs/src/mock/demo_test.go#test" - }, - "lang": "go", - "nodes": [ - { - "content": "func Test_Walk(t *testing.T) {\n\tt.Parallel()\n\n\tcab := createTestFS(t)\n\n\texp := []string{\n\t\t\"a.txt\",\n\t\t\"b.txt\",\n\t\t\"e/f/g.txt\",\n\t\t\"e/f/h.txt\",\n\t\t\"e/j.txt\",\n\t}\n\n\tact, err := Walk(cab)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\tes := strings.Join(exp, \", \")\n\tas := strings.Join(act, \", \")\n\n\tif es != as {\n\t\tt.Fatalf(\"expected %s, got %s\", es, as)\n\t}\n}", - "file": "fs/src/mock/demo_test.go", - "lang": "go", - "name": "test", - "start": 36, - "end": 63, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "atom": "hr", - "file": "fs", - "type": "*hype.Element" - }, - [ - { - "args": [ - "go", - "test", - "-v" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go test -v", - "src": "fs/src/mock", - "test": "-v" - }, - "expected_exit": 0, - "file": "fs", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go test -v\n\n=== RUN Test_Walk\n=== PAUSE Test_Walk\n=== CONT Test_Walk\n--- PASS: Test_Walk (0.00s)\nPASS\nok \tdemo\t0.733s", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "test", - "-v" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/14-files/fs/src/mock", - "stdout": "PT09IFJVTiAgIFRlc3RfV2Fsawo9PT0gUEFVU0UgVGVzdF9XYWxrCj09PSBDT05UICBUZXN0X1dhbGsKLS0tIFBBU1M6IFRlc3RfV2FsayAoMC4wMHMpClBBU1MKb2sgIAlkZW1vCTAuNzMzcw==", - "duration": 2218091792, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go test -v\n\n=== RUN Test_Walk\n=== PAUSE Test_Walk\n=== CONT Test_Walk\n--- PASS: Test_Walk (0.00s)\nPASS\nok \tdemo\t0.733s", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "test", - "-v" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/14-files/fs/src/mock", - "stdout": "PT09IFJVTiAgIFRlc3RfV2Fsawo9PT0gUEFVU0UgVGVzdF9XYWxrCj09PSBDT05UICBUZXN0X1dhbGsKLS0tIFBBU1M6IFRlc3RfV2FsayAoMC4wMHMpClBBU1MKb2sgIAlkZW1vCTAuNzMzcw==", - "duration": 2218091792, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "fs", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.69:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Using the helper function to get the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "testing/fstest#MapFS", - "href": "https://pkg.go.dev/testing/fstest#MapFS", - "target": "_blank" - }, - "file": "fs", - "nodes": [ - [ - { - "atom": "code", - "file": "fs", - "nodes": [ - { - "text": "fstest.MapFS", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/testing/fstest#MapFS" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 69, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "fs/mock.md", - "nodes": [ - { - "text": "As we can see from our test output, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-69" - }, - "file": "fs/mock.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-69" - }, - "nodes": [ - { - "text": "Listing 1.69", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-69" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", we are now able to test our code without having to worry about the files on disk.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "title": "Mocking a File System", - "type": "*hype.Page" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "type": "*hype.Include" - } - ], - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "include", - "attributes": { - "src": "fs/embed.md" - }, - "dir": "fs", - "file": "module.md", - "nodes": [ - [ - { - "atom": "page", - "file": "fs/embed.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "h1", - "file": "fs/embed.md", - "level": 1, - "nodes": [ - { - "text": "Embedding Files", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "fs/embed.md", - "nodes": [ - { - "text": "As was mentioned earlier, the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "fs", - "href": "https://pkg.go.dev/fs", - "target": "_blank" - }, - "file": "fs/embed.md", - "nodes": [ - { - "atom": "code", - "file": "fs/embed.md", - "nodes": [ - { - "text": "fs", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/fs" - } - ], - { - "text": " package, and the subsequent changes to the standard library, were added to allow for the embedding of files, such as HTML, JavaScript, and CSS, into the final binary.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "fs/embed.md", - "nodes": [ - { - "text": "To use this feature, we can use the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "embed", - "href": "https://pkg.go.dev/embed", - "target": "_blank" - }, - "file": "fs/embed.md", - "nodes": [ - { - "atom": "code", - "file": "fs/embed.md", - "nodes": [ - { - "text": "embed", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/embed" - } - ], - { - "text": " package and the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "fs/embed.md", - "nodes": [ - { - "text": "//go:embed", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " directive to define which file, or files, to embed, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-70" - }, - "file": "fs/embed.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-70" - }, - "nodes": [ - { - "text": "Listing 1.70", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-70" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-70", - "type": "listing" - }, - "file": "fs/embed.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "doc", - "embed" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "doc": "embed", - "exec": "go doc embed", - "truncate": "9" - }, - "expected_exit": 0, - "file": "fs", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc embed\n\npackage embed // import \u0026#34;embed\u0026#34;\n\nPackage embed provides access to files embedded in the running Go program.\n\nGo source files that import \u0026#34;embed\u0026#34; can use the //go:embed directive to\ninitialize a variable of type string, []byte, or FS with the contents of files\nread from the package directory or subdirectories at compile time.\n...", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "embed" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBlbWJlZCAvLyBpbXBvcnQgImVtYmVkIgoKUGFja2FnZSBlbWJlZCBwcm92aWRlcyBhY2Nlc3MgdG8gZmlsZXMgZW1iZWRkZWQgaW4gdGhlIHJ1bm5pbmcgR28gcHJvZ3JhbS4KCkdvIHNvdXJjZSBmaWxlcyB0aGF0IGltcG9ydCAiZW1iZWQiIGNhbiB1c2UgdGhlIC8vZ286ZW1iZWQgZGlyZWN0aXZlIHRvCmluaXRpYWxpemUgYSB2YXJpYWJsZSBvZiB0eXBlIHN0cmluZywgW11ieXRlLCBvciBGUyB3aXRoIHRoZSBjb250ZW50cyBvZiBmaWxlcwpyZWFkIGZyb20gdGhlIHBhY2thZ2UgZGlyZWN0b3J5IG9yIHN1YmRpcmVjdG9yaWVzIGF0IGNvbXBpbGUgdGltZS4KCkZvciBleGFtcGxlLCBoZXJlIGFyZSB0aHJlZSB3YXlzIHRvIGVtYmVkIGEgZmlsZSBuYW1lZCBoZWxsby50eHQgYW5kIHRoZW4gcHJpbnQKaXRzIGNvbnRlbnRzIGF0IHJ1biB0aW1lLgoKRW1iZWRkaW5nIG9uZSBmaWxlIGludG8gYSBzdHJpbmc6CgogICAgaW1wb3J0IF8gImVtYmVkIgoKICAgIC8vZ286ZW1iZWQgaGVsbG8udHh0CiAgICB2YXIgcyBzdHJpbmcKICAgIHByaW50KHMpCgpFbWJlZGRpbmcgb25lIGZpbGUgaW50byBhIHNsaWNlIG9mIGJ5dGVzOgoKICAgIGltcG9ydCBfICJlbWJlZCIKCiAgICAvL2dvOmVtYmVkIGhlbGxvLnR4dAogICAgdmFyIGIgW11ieXRlCiAgICBwcmludChzdHJpbmcoYikpCgpFbWJlZGRlZCBvbmUgb3IgbW9yZSBmaWxlcyBpbnRvIGEgZmlsZSBzeXN0ZW06CgogICAgaW1wb3J0ICJlbWJlZCIKCiAgICAvL2dvOmVtYmVkIGhlbGxvLnR4dAogICAgdmFyIGYgZW1iZWQuRlMKICAgIGRhdGEsIF8gOj0gZi5SZWFkRmlsZSgiaGVsbG8udHh0IikKICAgIHByaW50KHN0cmluZyhkYXRhKSkKCiMgRGlyZWN0aXZlcwoKQSAvL2dvOmVtYmVkIGRpcmVjdGl2ZSBhYm92ZSBhIHZhcmlhYmxlIGRlY2xhcmF0aW9uIHNwZWNpZmllcyB3aGljaCBmaWxlcyB0bwplbWJlZCwgdXNpbmcgb25lIG9yIG1vcmUgcGF0aC5NYXRjaCBwYXR0ZXJucy4KClRoZSBkaXJlY3RpdmUgbXVzdCBpbW1lZGlhdGVseSBwcmVjZWRlIGEgbGluZSBjb250YWluaW5nIHRoZSBkZWNsYXJhdGlvbiBvZiBhCnNpbmdsZSB2YXJpYWJsZS4gT25seSBibGFuayBsaW5lcyBhbmQg4oCYLy/igJkgbGluZSBjb21tZW50cyBhcmUgcGVybWl0dGVkIGJldHdlZW4KdGhlIGRpcmVjdGl2ZSBhbmQgdGhlIGRlY2xhcmF0aW9uLgoKVGhlIHR5cGUgb2YgdGhlIHZhcmlhYmxlIG11c3QgYmUgYSBzdHJpbmcgdHlwZSwgb3IgYSBzbGljZSBvZiBhIGJ5dGUgdHlwZSwKb3IgRlMgKG9yIGFuIGFsaWFzIG9mIEZTKS4KCkZvciBleGFtcGxlOgoKICAgIHBhY2thZ2Ugc2VydmVyCgogICAgaW1wb3J0ICJlbWJlZCIKCiAgICAvLyBjb250ZW50IGhvbGRzIG91ciBzdGF0aWMgd2ViIHNlcnZlciBjb250ZW50LgogICAgLy9nbzplbWJlZCBpbWFnZS8qIHRlbXBsYXRlLyoKICAgIC8vZ286ZW1iZWQgaHRtbC9pbmRleC5odG1sCiAgICB2YXIgY29udGVudCBlbWJlZC5GUwoKVGhlIEdvIGJ1aWxkIHN5c3RlbSB3aWxsIHJlY29nbml6ZSB0aGUgZGlyZWN0aXZlcyBhbmQgYXJyYW5nZSBmb3IgdGhlIGRlY2xhcmVkCnZhcmlhYmxlIChpbiB0aGUgZXhhbXBsZSBhYm92ZSwgY29udGVudCkgdG8gYmUgcG9wdWxhdGVkIHdpdGggdGhlIG1hdGNoaW5nIGZpbGVzCmZyb20gdGhlIGZpbGUgc3lzdGVtLgoKVGhlIC8vZ286ZW1iZWQgZGlyZWN0aXZlIGFjY2VwdHMgbXVsdGlwbGUgc3BhY2Utc2VwYXJhdGVkIHBhdHRlcm5zIGZvciBicmV2aXR5LApidXQgaXQgY2FuIGFsc28gYmUgcmVwZWF0ZWQsIHRvIGF2b2lkIHZlcnkgbG9uZyBsaW5lcyB3aGVuIHRoZXJlIGFyZSBtYW55CnBhdHRlcm5zLiBUaGUgcGF0dGVybnMgYXJlIGludGVycHJldGVkIHJlbGF0aXZlIHRvIHRoZSBwYWNrYWdlIGRpcmVjdG9yeQpjb250YWluaW5nIHRoZSBzb3VyY2UgZmlsZS4gVGhlIHBhdGggc2VwYXJhdG9yIGlzIGEgZm9yd2FyZCBzbGFzaCwgZXZlbiBvbgpXaW5kb3dzIHN5c3RlbXMuIFBhdHRlcm5zIG1heSBub3QgY29udGFpbiDigJgu4oCZIG9yIOKAmC4u4oCZIG9yIGVtcHR5IHBhdGggZWxlbWVudHMsCm5vciBtYXkgdGhleSBiZWdpbiBvciBlbmQgd2l0aCBhIHNsYXNoLiBUbyBtYXRjaCBldmVyeXRoaW5nIGluIHRoZSBjdXJyZW50CmRpcmVjdG9yeSwgdXNlIOKAmCrigJkgaW5zdGVhZCBvZiDigJgu4oCZLiBUbyBhbGxvdyBmb3IgbmFtaW5nIGZpbGVzIHdpdGggc3BhY2VzIGluCnRoZWlyIG5hbWVzLCBwYXR0ZXJucyBjYW4gYmUgd3JpdHRlbiBhcyBHbyBkb3VibGUtcXVvdGVkIG9yIGJhY2stcXVvdGVkIHN0cmluZwpsaXRlcmFscy4KCklmIGEgcGF0dGVybiBuYW1lcyBhIGRpcmVjdG9yeSwgYWxsIGZpbGVzIGluIHRoZSBzdWJ0cmVlIHJvb3RlZCBhdCB0aGF0CmRpcmVjdG9yeSBhcmUgZW1iZWRkZWQgKHJlY3Vyc2l2ZWx5KSwgZXhjZXB0IHRoYXQgZmlsZXMgd2l0aCBuYW1lcyBiZWdpbm5pbmcKd2l0aCDigJgu4oCZIG9yIOKAmF/igJkgYXJlIGV4Y2x1ZGVkLiBTbyB0aGUgdmFyaWFibGUgaW4gdGhlIGFib3ZlIGV4YW1wbGUgaXMgYWxtb3N0CmVxdWl2YWxlbnQgdG86CgogICAgLy8gY29udGVudCBpcyBvdXIgc3RhdGljIHdlYiBzZXJ2ZXIgY29udGVudC4KICAgIC8vZ286ZW1iZWQgaW1hZ2UgdGVtcGxhdGUgaHRtbC9pbmRleC5odG1sCiAgICB2YXIgY29udGVudCBlbWJlZC5GUwoKVGhlIGRpZmZlcmVuY2UgaXMgdGhhdCDigJhpbWFnZS8q4oCZIGVtYmVkcyDigJhpbWFnZS8udGVtcGZpbGXigJkgd2hpbGUg4oCYaW1hZ2XigJkgZG9lcwpub3QuIE5laXRoZXIgZW1iZWRzIOKAmGltYWdlL2Rpci8udGVtcGZpbGXigJkuCgpJZiBhIHBhdHRlcm4gYmVnaW5zIHdpdGggdGhlIHByZWZpeCDigJhhbGw64oCZLCB0aGVuIHRoZSBydWxlIGZvciB3YWxraW5nCmRpcmVjdG9yaWVzIGlzIGNoYW5nZWQgdG8gaW5jbHVkZSB0aG9zZSBmaWxlcyBiZWdpbm5pbmcgd2l0aCDigJgu4oCZIG9yIOKAmF/igJkuIEZvcgpleGFtcGxlLCDigJhhbGw6aW1hZ2XigJkgZW1iZWRzIGJvdGgg4oCYaW1hZ2UvLnRlbXBmaWxl4oCZIGFuZCDigJhpbWFnZS9kaXIvLnRlbXBmaWxl4oCZLgoKVGhlIC8vZ286ZW1iZWQgZGlyZWN0aXZlIGNhbiBiZSB1c2VkIHdpdGggYm90aCBleHBvcnRlZCBhbmQgdW5leHBvcnRlZAp2YXJpYWJsZXMsIGRlcGVuZGluZyBvbiB3aGV0aGVyIHRoZSBwYWNrYWdlIHdhbnRzIHRvIG1ha2UgdGhlIGRhdGEgYXZhaWxhYmxlIHRvCm90aGVyIHBhY2thZ2VzLiBJdCBjYW4gb25seSBiZSB1c2VkIHdpdGggdmFyaWFibGVzIGF0IHBhY2thZ2Ugc2NvcGUsIG5vdCB3aXRoCmxvY2FsIHZhcmlhYmxlcy4KClBhdHRlcm5zIG11c3Qgbm90IG1hdGNoIGZpbGVzIG91dHNpZGUgdGhlIHBhY2thZ2UncyBtb2R1bGUsIHN1Y2ggYXMg4oCYLmdpdC8q4oCZIG9yCnN5bWJvbGljIGxpbmtzLiBQYXR0ZXJucyBtdXN0IG5vdCBtYXRjaCBmaWxlcyB3aG9zZSBuYW1lcyBpbmNsdWRlIHRoZSBzcGVjaWFsCnB1bmN0dWF0aW9uIGNoYXJhY3RlcnMgIiAqIDwgPiA/IGAgJyB8IC8gXCBhbmQgOi4gTWF0Y2hlcyBmb3IgZW1wdHkgZGlyZWN0b3JpZXMKYXJlIGlnbm9yZWQuIEFmdGVyIHRoYXQsIGVhY2ggcGF0dGVybiBpbiBhIC8vZ286ZW1iZWQgbGluZSBtdXN0IG1hdGNoIGF0IGxlYXN0Cm9uZSBmaWxlIG9yIG5vbi1lbXB0eSBkaXJlY3RvcnkuCgpJZiBhbnkgcGF0dGVybnMgYXJlIGludmFsaWQgb3IgaGF2ZSBpbnZhbGlkIG1hdGNoZXMsIHRoZSBidWlsZCB3aWxsIGZhaWwuCgojIFN0cmluZ3MgYW5kIEJ5dGVzCgpUaGUgLy9nbzplbWJlZCBsaW5lIGZvciBhIHZhcmlhYmxlIG9mIHR5cGUgc3RyaW5nIG9yIFtdYnl0ZSBjYW4gaGF2ZSBvbmx5IGEKc2luZ2xlIHBhdHRlcm4sIGFuZCB0aGF0IHBhdHRlcm4gY2FuIG1hdGNoIG9ubHkgYSBzaW5nbGUgZmlsZS4gVGhlIHN0cmluZyBvcgpbXWJ5dGUgaXMgaW5pdGlhbGl6ZWQgd2l0aCB0aGUgY29udGVudHMgb2YgdGhhdCBmaWxlLgoKVGhlIC8vZ286ZW1iZWQgZGlyZWN0aXZlIHJlcXVpcmVzIGltcG9ydGluZyAiZW1iZWQiLCBldmVuIHdoZW4gdXNpbmcgYSBzdHJpbmcgb3IKW11ieXRlLiBJbiBzb3VyY2UgZmlsZXMgdGhhdCBkb24ndCByZWZlciB0byBlbWJlZC5GUywgdXNlIGEgYmxhbmsgaW1wb3J0IChpbXBvcnQKXyAiZW1iZWQiKS4KCiMgRmlsZSBTeXN0ZW1zCgpGb3IgZW1iZWRkaW5nIGEgc2luZ2xlIGZpbGUsIGEgdmFyaWFibGUgb2YgdHlwZSBzdHJpbmcgb3IgW11ieXRlIGlzIG9mdGVuIGJlc3QuClRoZSBGUyB0eXBlIGVuYWJsZXMgZW1iZWRkaW5nIGEgdHJlZSBvZiBmaWxlcywgc3VjaCBhcyBhIGRpcmVjdG9yeSBvZiBzdGF0aWMgd2ViCnNlcnZlciBjb250ZW50LCBhcyBpbiB0aGUgZXhhbXBsZSBhYm92ZS4KCkZTIGltcGxlbWVudHMgdGhlIGlvL2ZzIHBhY2thZ2UncyBGUyBpbnRlcmZhY2UsIHNvIGl0IGNhbiBiZSB1c2VkIHdpdGggYW55CnBhY2thZ2UgdGhhdCB1bmRlcnN0YW5kcyBmaWxlIHN5c3RlbXMsIGluY2x1ZGluZyBuZXQvaHR0cCwgdGV4dC90ZW1wbGF0ZSwKYW5kIGh0bWwvdGVtcGxhdGUuCgpGb3IgZXhhbXBsZSwgZ2l2ZW4gdGhlIGNvbnRlbnQgdmFyaWFibGUgaW4gdGhlIGV4YW1wbGUgYWJvdmUsIHdlIGNhbiB3cml0ZToKCiAgICBodHRwLkhhbmRsZSgiL3N0YXRpYy8iLCBodHRwLlN0cmlwUHJlZml4KCIvc3RhdGljLyIsIGh0dHAuRmlsZVNlcnZlcihodHRwLkZTKGNvbnRlbnQpKSkpCgogICAgdGVtcGxhdGUuUGFyc2VGUyhjb250ZW50LCAiKi50bXBsIikKCiMgVG9vbHMKClRvIHN1cHBvcnQgdG9vbHMgdGhhdCBhbmFseXplIEdvIHBhY2thZ2VzLCB0aGUgcGF0dGVybnMgZm91bmQgaW4KLy9nbzplbWJlZCBsaW5lcyBhcmUgYXZhaWxhYmxlIGluIOKAnGdvIGxpc3TigJ0gb3V0cHV0LiBTZWUgdGhlIEVtYmVkUGF0dGVybnMsClRlc3RFbWJlZFBhdHRlcm5zLCBhbmQgWFRlc3RFbWJlZFBhdHRlcm5zIGZpZWxkcyBpbiB0aGUg4oCcZ28gaGVscCBsaXN04oCdIG91dHB1dC4KCnR5cGUgRlMgc3RydWN0eyAuLi4gfQ==", - "duration": 1128002667, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc embed\n\npackage embed // import \u0026#34;embed\u0026#34;\n\nPackage embed provides access to files embedded in the running Go program.\n\nGo source files that import \u0026#34;embed\u0026#34; can use the //go:embed directive to\ninitialize a variable of type string, []byte, or FS with the contents of files\nread from the package directory or subdirectories at compile time.\n...", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "embed" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBlbWJlZCAvLyBpbXBvcnQgImVtYmVkIgoKUGFja2FnZSBlbWJlZCBwcm92aWRlcyBhY2Nlc3MgdG8gZmlsZXMgZW1iZWRkZWQgaW4gdGhlIHJ1bm5pbmcgR28gcHJvZ3JhbS4KCkdvIHNvdXJjZSBmaWxlcyB0aGF0IGltcG9ydCAiZW1iZWQiIGNhbiB1c2UgdGhlIC8vZ286ZW1iZWQgZGlyZWN0aXZlIHRvCmluaXRpYWxpemUgYSB2YXJpYWJsZSBvZiB0eXBlIHN0cmluZywgW11ieXRlLCBvciBGUyB3aXRoIHRoZSBjb250ZW50cyBvZiBmaWxlcwpyZWFkIGZyb20gdGhlIHBhY2thZ2UgZGlyZWN0b3J5IG9yIHN1YmRpcmVjdG9yaWVzIGF0IGNvbXBpbGUgdGltZS4KCkZvciBleGFtcGxlLCBoZXJlIGFyZSB0aHJlZSB3YXlzIHRvIGVtYmVkIGEgZmlsZSBuYW1lZCBoZWxsby50eHQgYW5kIHRoZW4gcHJpbnQKaXRzIGNvbnRlbnRzIGF0IHJ1biB0aW1lLgoKRW1iZWRkaW5nIG9uZSBmaWxlIGludG8gYSBzdHJpbmc6CgogICAgaW1wb3J0IF8gImVtYmVkIgoKICAgIC8vZ286ZW1iZWQgaGVsbG8udHh0CiAgICB2YXIgcyBzdHJpbmcKICAgIHByaW50KHMpCgpFbWJlZGRpbmcgb25lIGZpbGUgaW50byBhIHNsaWNlIG9mIGJ5dGVzOgoKICAgIGltcG9ydCBfICJlbWJlZCIKCiAgICAvL2dvOmVtYmVkIGhlbGxvLnR4dAogICAgdmFyIGIgW11ieXRlCiAgICBwcmludChzdHJpbmcoYikpCgpFbWJlZGRlZCBvbmUgb3IgbW9yZSBmaWxlcyBpbnRvIGEgZmlsZSBzeXN0ZW06CgogICAgaW1wb3J0ICJlbWJlZCIKCiAgICAvL2dvOmVtYmVkIGhlbGxvLnR4dAogICAgdmFyIGYgZW1iZWQuRlMKICAgIGRhdGEsIF8gOj0gZi5SZWFkRmlsZSgiaGVsbG8udHh0IikKICAgIHByaW50KHN0cmluZyhkYXRhKSkKCiMgRGlyZWN0aXZlcwoKQSAvL2dvOmVtYmVkIGRpcmVjdGl2ZSBhYm92ZSBhIHZhcmlhYmxlIGRlY2xhcmF0aW9uIHNwZWNpZmllcyB3aGljaCBmaWxlcyB0bwplbWJlZCwgdXNpbmcgb25lIG9yIG1vcmUgcGF0aC5NYXRjaCBwYXR0ZXJucy4KClRoZSBkaXJlY3RpdmUgbXVzdCBpbW1lZGlhdGVseSBwcmVjZWRlIGEgbGluZSBjb250YWluaW5nIHRoZSBkZWNsYXJhdGlvbiBvZiBhCnNpbmdsZSB2YXJpYWJsZS4gT25seSBibGFuayBsaW5lcyBhbmQg4oCYLy/igJkgbGluZSBjb21tZW50cyBhcmUgcGVybWl0dGVkIGJldHdlZW4KdGhlIGRpcmVjdGl2ZSBhbmQgdGhlIGRlY2xhcmF0aW9uLgoKVGhlIHR5cGUgb2YgdGhlIHZhcmlhYmxlIG11c3QgYmUgYSBzdHJpbmcgdHlwZSwgb3IgYSBzbGljZSBvZiBhIGJ5dGUgdHlwZSwKb3IgRlMgKG9yIGFuIGFsaWFzIG9mIEZTKS4KCkZvciBleGFtcGxlOgoKICAgIHBhY2thZ2Ugc2VydmVyCgogICAgaW1wb3J0ICJlbWJlZCIKCiAgICAvLyBjb250ZW50IGhvbGRzIG91ciBzdGF0aWMgd2ViIHNlcnZlciBjb250ZW50LgogICAgLy9nbzplbWJlZCBpbWFnZS8qIHRlbXBsYXRlLyoKICAgIC8vZ286ZW1iZWQgaHRtbC9pbmRleC5odG1sCiAgICB2YXIgY29udGVudCBlbWJlZC5GUwoKVGhlIEdvIGJ1aWxkIHN5c3RlbSB3aWxsIHJlY29nbml6ZSB0aGUgZGlyZWN0aXZlcyBhbmQgYXJyYW5nZSBmb3IgdGhlIGRlY2xhcmVkCnZhcmlhYmxlIChpbiB0aGUgZXhhbXBsZSBhYm92ZSwgY29udGVudCkgdG8gYmUgcG9wdWxhdGVkIHdpdGggdGhlIG1hdGNoaW5nIGZpbGVzCmZyb20gdGhlIGZpbGUgc3lzdGVtLgoKVGhlIC8vZ286ZW1iZWQgZGlyZWN0aXZlIGFjY2VwdHMgbXVsdGlwbGUgc3BhY2Utc2VwYXJhdGVkIHBhdHRlcm5zIGZvciBicmV2aXR5LApidXQgaXQgY2FuIGFsc28gYmUgcmVwZWF0ZWQsIHRvIGF2b2lkIHZlcnkgbG9uZyBsaW5lcyB3aGVuIHRoZXJlIGFyZSBtYW55CnBhdHRlcm5zLiBUaGUgcGF0dGVybnMgYXJlIGludGVycHJldGVkIHJlbGF0aXZlIHRvIHRoZSBwYWNrYWdlIGRpcmVjdG9yeQpjb250YWluaW5nIHRoZSBzb3VyY2UgZmlsZS4gVGhlIHBhdGggc2VwYXJhdG9yIGlzIGEgZm9yd2FyZCBzbGFzaCwgZXZlbiBvbgpXaW5kb3dzIHN5c3RlbXMuIFBhdHRlcm5zIG1heSBub3QgY29udGFpbiDigJgu4oCZIG9yIOKAmC4u4oCZIG9yIGVtcHR5IHBhdGggZWxlbWVudHMsCm5vciBtYXkgdGhleSBiZWdpbiBvciBlbmQgd2l0aCBhIHNsYXNoLiBUbyBtYXRjaCBldmVyeXRoaW5nIGluIHRoZSBjdXJyZW50CmRpcmVjdG9yeSwgdXNlIOKAmCrigJkgaW5zdGVhZCBvZiDigJgu4oCZLiBUbyBhbGxvdyBmb3IgbmFtaW5nIGZpbGVzIHdpdGggc3BhY2VzIGluCnRoZWlyIG5hbWVzLCBwYXR0ZXJucyBjYW4gYmUgd3JpdHRlbiBhcyBHbyBkb3VibGUtcXVvdGVkIG9yIGJhY2stcXVvdGVkIHN0cmluZwpsaXRlcmFscy4KCklmIGEgcGF0dGVybiBuYW1lcyBhIGRpcmVjdG9yeSwgYWxsIGZpbGVzIGluIHRoZSBzdWJ0cmVlIHJvb3RlZCBhdCB0aGF0CmRpcmVjdG9yeSBhcmUgZW1iZWRkZWQgKHJlY3Vyc2l2ZWx5KSwgZXhjZXB0IHRoYXQgZmlsZXMgd2l0aCBuYW1lcyBiZWdpbm5pbmcKd2l0aCDigJgu4oCZIG9yIOKAmF/igJkgYXJlIGV4Y2x1ZGVkLiBTbyB0aGUgdmFyaWFibGUgaW4gdGhlIGFib3ZlIGV4YW1wbGUgaXMgYWxtb3N0CmVxdWl2YWxlbnQgdG86CgogICAgLy8gY29udGVudCBpcyBvdXIgc3RhdGljIHdlYiBzZXJ2ZXIgY29udGVudC4KICAgIC8vZ286ZW1iZWQgaW1hZ2UgdGVtcGxhdGUgaHRtbC9pbmRleC5odG1sCiAgICB2YXIgY29udGVudCBlbWJlZC5GUwoKVGhlIGRpZmZlcmVuY2UgaXMgdGhhdCDigJhpbWFnZS8q4oCZIGVtYmVkcyDigJhpbWFnZS8udGVtcGZpbGXigJkgd2hpbGUg4oCYaW1hZ2XigJkgZG9lcwpub3QuIE5laXRoZXIgZW1iZWRzIOKAmGltYWdlL2Rpci8udGVtcGZpbGXigJkuCgpJZiBhIHBhdHRlcm4gYmVnaW5zIHdpdGggdGhlIHByZWZpeCDigJhhbGw64oCZLCB0aGVuIHRoZSBydWxlIGZvciB3YWxraW5nCmRpcmVjdG9yaWVzIGlzIGNoYW5nZWQgdG8gaW5jbHVkZSB0aG9zZSBmaWxlcyBiZWdpbm5pbmcgd2l0aCDigJgu4oCZIG9yIOKAmF/igJkuIEZvcgpleGFtcGxlLCDigJhhbGw6aW1hZ2XigJkgZW1iZWRzIGJvdGgg4oCYaW1hZ2UvLnRlbXBmaWxl4oCZIGFuZCDigJhpbWFnZS9kaXIvLnRlbXBmaWxl4oCZLgoKVGhlIC8vZ286ZW1iZWQgZGlyZWN0aXZlIGNhbiBiZSB1c2VkIHdpdGggYm90aCBleHBvcnRlZCBhbmQgdW5leHBvcnRlZAp2YXJpYWJsZXMsIGRlcGVuZGluZyBvbiB3aGV0aGVyIHRoZSBwYWNrYWdlIHdhbnRzIHRvIG1ha2UgdGhlIGRhdGEgYXZhaWxhYmxlIHRvCm90aGVyIHBhY2thZ2VzLiBJdCBjYW4gb25seSBiZSB1c2VkIHdpdGggdmFyaWFibGVzIGF0IHBhY2thZ2Ugc2NvcGUsIG5vdCB3aXRoCmxvY2FsIHZhcmlhYmxlcy4KClBhdHRlcm5zIG11c3Qgbm90IG1hdGNoIGZpbGVzIG91dHNpZGUgdGhlIHBhY2thZ2UncyBtb2R1bGUsIHN1Y2ggYXMg4oCYLmdpdC8q4oCZIG9yCnN5bWJvbGljIGxpbmtzLiBQYXR0ZXJucyBtdXN0IG5vdCBtYXRjaCBmaWxlcyB3aG9zZSBuYW1lcyBpbmNsdWRlIHRoZSBzcGVjaWFsCnB1bmN0dWF0aW9uIGNoYXJhY3RlcnMgIiAqIDwgPiA/IGAgJyB8IC8gXCBhbmQgOi4gTWF0Y2hlcyBmb3IgZW1wdHkgZGlyZWN0b3JpZXMKYXJlIGlnbm9yZWQuIEFmdGVyIHRoYXQsIGVhY2ggcGF0dGVybiBpbiBhIC8vZ286ZW1iZWQgbGluZSBtdXN0IG1hdGNoIGF0IGxlYXN0Cm9uZSBmaWxlIG9yIG5vbi1lbXB0eSBkaXJlY3RvcnkuCgpJZiBhbnkgcGF0dGVybnMgYXJlIGludmFsaWQgb3IgaGF2ZSBpbnZhbGlkIG1hdGNoZXMsIHRoZSBidWlsZCB3aWxsIGZhaWwuCgojIFN0cmluZ3MgYW5kIEJ5dGVzCgpUaGUgLy9nbzplbWJlZCBsaW5lIGZvciBhIHZhcmlhYmxlIG9mIHR5cGUgc3RyaW5nIG9yIFtdYnl0ZSBjYW4gaGF2ZSBvbmx5IGEKc2luZ2xlIHBhdHRlcm4sIGFuZCB0aGF0IHBhdHRlcm4gY2FuIG1hdGNoIG9ubHkgYSBzaW5nbGUgZmlsZS4gVGhlIHN0cmluZyBvcgpbXWJ5dGUgaXMgaW5pdGlhbGl6ZWQgd2l0aCB0aGUgY29udGVudHMgb2YgdGhhdCBmaWxlLgoKVGhlIC8vZ286ZW1iZWQgZGlyZWN0aXZlIHJlcXVpcmVzIGltcG9ydGluZyAiZW1iZWQiLCBldmVuIHdoZW4gdXNpbmcgYSBzdHJpbmcgb3IKW11ieXRlLiBJbiBzb3VyY2UgZmlsZXMgdGhhdCBkb24ndCByZWZlciB0byBlbWJlZC5GUywgdXNlIGEgYmxhbmsgaW1wb3J0IChpbXBvcnQKXyAiZW1iZWQiKS4KCiMgRmlsZSBTeXN0ZW1zCgpGb3IgZW1iZWRkaW5nIGEgc2luZ2xlIGZpbGUsIGEgdmFyaWFibGUgb2YgdHlwZSBzdHJpbmcgb3IgW11ieXRlIGlzIG9mdGVuIGJlc3QuClRoZSBGUyB0eXBlIGVuYWJsZXMgZW1iZWRkaW5nIGEgdHJlZSBvZiBmaWxlcywgc3VjaCBhcyBhIGRpcmVjdG9yeSBvZiBzdGF0aWMgd2ViCnNlcnZlciBjb250ZW50LCBhcyBpbiB0aGUgZXhhbXBsZSBhYm92ZS4KCkZTIGltcGxlbWVudHMgdGhlIGlvL2ZzIHBhY2thZ2UncyBGUyBpbnRlcmZhY2UsIHNvIGl0IGNhbiBiZSB1c2VkIHdpdGggYW55CnBhY2thZ2UgdGhhdCB1bmRlcnN0YW5kcyBmaWxlIHN5c3RlbXMsIGluY2x1ZGluZyBuZXQvaHR0cCwgdGV4dC90ZW1wbGF0ZSwKYW5kIGh0bWwvdGVtcGxhdGUuCgpGb3IgZXhhbXBsZSwgZ2l2ZW4gdGhlIGNvbnRlbnQgdmFyaWFibGUgaW4gdGhlIGV4YW1wbGUgYWJvdmUsIHdlIGNhbiB3cml0ZToKCiAgICBodHRwLkhhbmRsZSgiL3N0YXRpYy8iLCBodHRwLlN0cmlwUHJlZml4KCIvc3RhdGljLyIsIGh0dHAuRmlsZVNlcnZlcihodHRwLkZTKGNvbnRlbnQpKSkpCgogICAgdGVtcGxhdGUuUGFyc2VGUyhjb250ZW50LCAiKi50bXBsIikKCiMgVG9vbHMKClRvIHN1cHBvcnQgdG9vbHMgdGhhdCBhbmFseXplIEdvIHBhY2thZ2VzLCB0aGUgcGF0dGVybnMgZm91bmQgaW4KLy9nbzplbWJlZCBsaW5lcyBhcmUgYXZhaWxhYmxlIGluIOKAnGdvIGxpc3TigJ0gb3V0cHV0LiBTZWUgdGhlIEVtYmVkUGF0dGVybnMsClRlc3RFbWJlZFBhdHRlcm5zLCBhbmQgWFRlc3RFbWJlZFBhdHRlcm5zIGZpZWxkcyBpbiB0aGUg4oCcZ28gaGVscCBsaXN04oCdIG91dHB1dC4KCnR5cGUgRlMgc3RydWN0eyAuLi4gfQ==", - "duration": 1128002667, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "fs", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.70:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "embed", - "href": "https://pkg.go.dev/embed", - "target": "_blank" - }, - "file": "fs", - "nodes": [ - [ - { - "atom": "code", - "file": "fs", - "nodes": [ - { - "text": "embed", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/embed" - } - ], - { - "text": " package.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 70, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "fs/embed.md", - "level": 2, - "nodes": [ - { - "text": "Using Embedded Files", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "fs/embed.md", - "nodes": [ - { - "text": "As per the documentation we can either embed a single file as either a ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "fs/embed.md", - "nodes": [ - { - "text": "string", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " or a ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "fs/embed.md", - "nodes": [ - { - "text": "[]byte", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ". For our purposes, and more often than not, we will be embedding multiple files, so we will need a ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "io/fs#FS", - "href": "https://pkg.go.dev/io/fs#FS", - "target": "_blank" - }, - "file": "fs/embed.md", - "nodes": [ - { - "atom": "code", - "file": "fs/embed.md", - "nodes": [ - { - "text": "fs.FS", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/io/fs#FS" - } - ], - { - "text": " implementation to hold the files. The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "embed#FS", - "href": "https://pkg.go.dev/embed#FS", - "target": "_blank" - }, - "file": "fs/embed.md", - "nodes": [ - { - "atom": "code", - "file": "fs/embed.md", - "nodes": [ - { - "text": "embed.FS", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/embed#FS" - } - ], - { - "text": " type, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-71" - }, - "file": "fs/embed.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-71" - }, - "nodes": [ - { - "text": "Listing 1.71", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-71" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", implements the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "io/fs#FS", - "href": "https://pkg.go.dev/io/fs#FS", - "target": "_blank" - }, - "file": "fs/embed.md", - "nodes": [ - { - "atom": "code", - "file": "fs/embed.md", - "nodes": [ - { - "text": "fs.FS", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/io/fs#FS" - } - ], - { - "text": " interface and provides a read-only file system for the embedded files.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-71", - "type": "listing" - }, - "file": "fs/embed.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "doc", - "embed.FS" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "doc": "embed.FS", - "exec": "go doc embed.FS" - }, - "expected_exit": 0, - "file": "fs", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc embed.FS\n\npackage embed // import \u0026#34;embed\u0026#34;\n\ntype FS struct {\n\t// Has unexported fields.\n}\n An FS is a read-only collection of files, usually initialized with a\n //go:embed directive. When declared without a //go:embed directive, an FS is\n an empty file system.\n\n An FS is a read-only value, so it is safe to use from multiple goroutines\n simultaneously and also safe to assign values of type FS to each other.\n\n FS implements fs.FS, so it can be used with any package that understands\n file system interfaces, including net/http, text/template, and\n html/template.\n\n See the package documentation for more details about initializing an FS.\n\nfunc (f FS) Open(name string) (fs.File, error)\nfunc (f FS) ReadDir(name string) ([]fs.DirEntry, error)\nfunc (f FS) ReadFile(name string) ([]byte, error)", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "embed.FS" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBlbWJlZCAvLyBpbXBvcnQgImVtYmVkIgoKdHlwZSBGUyBzdHJ1Y3QgewoJLy8gSGFzIHVuZXhwb3J0ZWQgZmllbGRzLgp9CiAgICBBbiBGUyBpcyBhIHJlYWQtb25seSBjb2xsZWN0aW9uIG9mIGZpbGVzLCB1c3VhbGx5IGluaXRpYWxpemVkIHdpdGggYQogICAgLy9nbzplbWJlZCBkaXJlY3RpdmUuIFdoZW4gZGVjbGFyZWQgd2l0aG91dCBhIC8vZ286ZW1iZWQgZGlyZWN0aXZlLCBhbiBGUyBpcwogICAgYW4gZW1wdHkgZmlsZSBzeXN0ZW0uCgogICAgQW4gRlMgaXMgYSByZWFkLW9ubHkgdmFsdWUsIHNvIGl0IGlzIHNhZmUgdG8gdXNlIGZyb20gbXVsdGlwbGUgZ29yb3V0aW5lcwogICAgc2ltdWx0YW5lb3VzbHkgYW5kIGFsc28gc2FmZSB0byBhc3NpZ24gdmFsdWVzIG9mIHR5cGUgRlMgdG8gZWFjaCBvdGhlci4KCiAgICBGUyBpbXBsZW1lbnRzIGZzLkZTLCBzbyBpdCBjYW4gYmUgdXNlZCB3aXRoIGFueSBwYWNrYWdlIHRoYXQgdW5kZXJzdGFuZHMKICAgIGZpbGUgc3lzdGVtIGludGVyZmFjZXMsIGluY2x1ZGluZyBuZXQvaHR0cCwgdGV4dC90ZW1wbGF0ZSwgYW5kCiAgICBodG1sL3RlbXBsYXRlLgoKICAgIFNlZSB0aGUgcGFja2FnZSBkb2N1bWVudGF0aW9uIGZvciBtb3JlIGRldGFpbHMgYWJvdXQgaW5pdGlhbGl6aW5nIGFuIEZTLgoKZnVuYyAoZiBGUykgT3BlbihuYW1lIHN0cmluZykgKGZzLkZpbGUsIGVycm9yKQpmdW5jIChmIEZTKSBSZWFkRGlyKG5hbWUgc3RyaW5nKSAoW11mcy5EaXJFbnRyeSwgZXJyb3IpCmZ1bmMgKGYgRlMpIFJlYWRGaWxlKG5hbWUgc3RyaW5nKSAoW11ieXRlLCBlcnJvcik=", - "duration": 1138884125, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc embed.FS\n\npackage embed // import \u0026#34;embed\u0026#34;\n\ntype FS struct {\n\t// Has unexported fields.\n}\n An FS is a read-only collection of files, usually initialized with a\n //go:embed directive. When declared without a //go:embed directive, an FS is\n an empty file system.\n\n An FS is a read-only value, so it is safe to use from multiple goroutines\n simultaneously and also safe to assign values of type FS to each other.\n\n FS implements fs.FS, so it can be used with any package that understands\n file system interfaces, including net/http, text/template, and\n html/template.\n\n See the package documentation for more details about initializing an FS.\n\nfunc (f FS) Open(name string) (fs.File, error)\nfunc (f FS) ReadDir(name string) ([]fs.DirEntry, error)\nfunc (f FS) ReadFile(name string) ([]byte, error)", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "embed.FS" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/hypeviewer", - "stdout": "cGFja2FnZSBlbWJlZCAvLyBpbXBvcnQgImVtYmVkIgoKdHlwZSBGUyBzdHJ1Y3QgewoJLy8gSGFzIHVuZXhwb3J0ZWQgZmllbGRzLgp9CiAgICBBbiBGUyBpcyBhIHJlYWQtb25seSBjb2xsZWN0aW9uIG9mIGZpbGVzLCB1c3VhbGx5IGluaXRpYWxpemVkIHdpdGggYQogICAgLy9nbzplbWJlZCBkaXJlY3RpdmUuIFdoZW4gZGVjbGFyZWQgd2l0aG91dCBhIC8vZ286ZW1iZWQgZGlyZWN0aXZlLCBhbiBGUyBpcwogICAgYW4gZW1wdHkgZmlsZSBzeXN0ZW0uCgogICAgQW4gRlMgaXMgYSByZWFkLW9ubHkgdmFsdWUsIHNvIGl0IGlzIHNhZmUgdG8gdXNlIGZyb20gbXVsdGlwbGUgZ29yb3V0aW5lcwogICAgc2ltdWx0YW5lb3VzbHkgYW5kIGFsc28gc2FmZSB0byBhc3NpZ24gdmFsdWVzIG9mIHR5cGUgRlMgdG8gZWFjaCBvdGhlci4KCiAgICBGUyBpbXBsZW1lbnRzIGZzLkZTLCBzbyBpdCBjYW4gYmUgdXNlZCB3aXRoIGFueSBwYWNrYWdlIHRoYXQgdW5kZXJzdGFuZHMKICAgIGZpbGUgc3lzdGVtIGludGVyZmFjZXMsIGluY2x1ZGluZyBuZXQvaHR0cCwgdGV4dC90ZW1wbGF0ZSwgYW5kCiAgICBodG1sL3RlbXBsYXRlLgoKICAgIFNlZSB0aGUgcGFja2FnZSBkb2N1bWVudGF0aW9uIGZvciBtb3JlIGRldGFpbHMgYWJvdXQgaW5pdGlhbGl6aW5nIGFuIEZTLgoKZnVuYyAoZiBGUykgT3BlbihuYW1lIHN0cmluZykgKGZzLkZpbGUsIGVycm9yKQpmdW5jIChmIEZTKSBSZWFkRGlyKG5hbWUgc3RyaW5nKSAoW11mcy5EaXJFbnRyeSwgZXJyb3IpCmZ1bmMgKGYgRlMpIFJlYWRGaWxlKG5hbWUgc3RyaW5nKSAoW11ieXRlLCBlcnJvcik=", - "duration": 1138884125, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "fs", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.71:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "embed#FS", - "href": "https://pkg.go.dev/embed#FS", - "target": "_blank" - }, - "file": "fs", - "nodes": [ - [ - { - "atom": "code", - "file": "fs", - "nodes": [ - { - "text": "embed.FS", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/embed#FS" - } - ], - { - "text": " type.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 71, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "fs/embed.md", - "nodes": [ - { - "text": "In ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-72" - }, - "file": "fs/embed.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-72" - }, - "nodes": [ - { - "text": "Listing 1.72", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-72" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": " we can define a global variable of type ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "embed#FS", - "href": "https://pkg.go.dev/embed#FS", - "target": "_blank" - }, - "file": "fs/embed.md", - "nodes": [ - { - "atom": "code", - "file": "fs/embed.md", - "nodes": [ - { - "text": "embed.FS", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/embed#FS" - } - ], - { - "text": " and use the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "fs/embed.md", - "nodes": [ - { - "text": "//go:embed", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " directive to define the directories and files to embed.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-72", - "type": "listing" - }, - "file": "fs/embed.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "fs", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "snippet": "embed", - "src": "fs/src/embed/demo.go" - }, - "lang": "go", - "nodes": [ - { - "content": "//go:embed data\nvar DataFS embed.FS", - "file": "fs/src/embed/demo.go", - "lang": "go", - "name": "embed", - "start": 9, - "end": 13, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "fs", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.72:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "fs", - "nodes": [ - { - "text": "//go:embed", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " directive.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 72, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "fs/embed.md", - "nodes": [ - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "fs/embed.md", - "nodes": [ - { - "text": "//go:embed data", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " directive tells Go to fill the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "fs/embed.md", - "nodes": [ - { - "text": "DataFS", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " variable with the contents of the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "fs/embed.md", - "nodes": [ - { - "text": "data", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " directory. Files beginning with ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "fs/embed.md", - "nodes": [ - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " and ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "fs/embed.md", - "nodes": [ - { - "text": "_", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " are ignored by the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "fs/embed.md", - "nodes": [ - { - "text": "//go:embed", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " directive.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "fs/embed.md", - "nodes": [ - { - "text": "In the tests, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-73" - }, - "file": "fs/embed.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-73" - }, - "nodes": [ - { - "text": "Listing 1.73", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-73" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", we can use the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "fs/embed.md", - "nodes": [ - { - "text": "DataFS", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " variable to pass to the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "fs/embed.md", - "nodes": [ - { - "text": "Walk", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-73", - "type": "listing" - }, - "file": "fs/embed.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "fs", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "snippet": "test", - "src": "fs/src/embed/demo_test.go" - }, - "lang": "go", - "nodes": [ - { - "content": "func Test_Walk(t *testing.T) {\n\tt.Parallel()\n\n\texp := []string{\n\t\t\"data/a.txt\",\n\t\t\"data/b.txt\",\n\t\t\"data/e/f/g.txt\",\n\t\t\"data/e/f/h.txt\",\n\t\t\"data/e/j.txt\",\n\t}\n\n\tact, err := Walk(DataFS)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\tes := strings.Join(exp, \", \")\n\tas := strings.Join(act, \", \")\n\n\tif es != as {\n\t\tt.Fatalf(\"expected %s, got %s\", es, as)\n\t}\n}", - "file": "fs/src/embed/demo_test.go", - "lang": "go", - "name": "test", - "start": 8, - "end": 33, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "fs", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.73:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Testing using the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "embed#FS", - "href": "https://pkg.go.dev/embed#FS", - "target": "_blank" - }, - "file": "fs", - "nodes": [ - [ - { - "atom": "code", - "file": "fs", - "nodes": [ - { - "text": "embed.FS", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/embed#FS" - } - ], - { - "text": " as a ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "io/fs#FS", - "href": "https://pkg.go.dev/io/fs#FS", - "target": "_blank" - }, - "file": "fs", - "nodes": [ - [ - { - "atom": "code", - "file": "fs", - "nodes": [ - { - "text": "fs.FS", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/io/fs#FS" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 73, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "fs/embed.md", - "nodes": [ - { - "text": "As we can see from the test output, the files we wanted were successfully embedded and added to the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "fs/embed.md", - "nodes": [ - { - "text": "DataFS", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " variable.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-74", - "type": "listing" - }, - "file": "fs/embed.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "test", - "-v" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go test -v", - "src": "fs/src/embed", - "test": "-v" - }, - "expected_exit": 0, - "file": "fs", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go test -v\n\n=== RUN Test_Walk\n=== PAUSE Test_Walk\n=== CONT Test_Walk\n--- PASS: Test_Walk (0.00s)\nPASS\nok \tdemo\t0.461s", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "test", - "-v" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/14-files/fs/src/embed", - "stdout": "PT09IFJVTiAgIFRlc3RfV2Fsawo9PT0gUEFVU0UgVGVzdF9XYWxrCj09PSBDT05UICBUZXN0X1dhbGsKLS0tIFBBU1M6IFRlc3RfV2FsayAoMC4wMHMpClBBU1MKb2sgIAlkZW1vCTAuNDYxcw==", - "duration": 1063115792, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go test -v\n\n=== RUN Test_Walk\n=== PAUSE Test_Walk\n=== CONT Test_Walk\n--- PASS: Test_Walk (0.00s)\nPASS\nok \tdemo\t0.461s", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "test", - "-v" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/14-files/fs/src/embed", - "stdout": "PT09IFJVTiAgIFRlc3RfV2Fsawo9PT0gUEFVU0UgVGVzdF9XYWxrCj09PSBDT05UICBUZXN0X1dhbGsKLS0tIFBBU1M6IFRlc3RfV2FsayAoMC4wMHMpClBBU1MKb2sgIAlkZW1vCTAuNDYxcw==", - "duration": 1063115792, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "fs", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.74:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Successful test output using an ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "embed#FS", - "href": "https://pkg.go.dev/embed#FS", - "target": "_blank" - }, - "file": "fs", - "nodes": [ - [ - { - "atom": "code", - "file": "fs", - "nodes": [ - { - "text": "embed.FS", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/embed#FS" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 74, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "fs/embed.md", - "level": 2, - "nodes": [ - { - "text": "Embedded Files in a Binary", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "fs/embed.md", - "nodes": [ - { - "text": "To see the embedding in action, we can write a small application that uses our application.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "fs/embed.md", - "nodes": [ - { - "text": "Consider ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-75" - }, - "file": "fs/embed.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-75" - }, - "nodes": [ - { - "text": "Listing 1.75", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-75" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ". We are calling our ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "fs/embed.md", - "nodes": [ - { - "text": "demo.Walk", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function from the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "fs/embed.md", - "nodes": [ - { - "text": "main", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function, using the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "fs/embed.md", - "nodes": [ - { - "text": "demo.DataFS", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " variable, which is an ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "embed#FS", - "href": "https://pkg.go.dev/embed#FS", - "target": "_blank" - }, - "file": "fs/embed.md", - "nodes": [ - { - "atom": "code", - "file": "fs/embed.md", - "nodes": [ - { - "text": "embed.FS", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/embed#FS" - } - ], - { - "text": " implementation. We then print out the results of the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "fs/embed.md", - "nodes": [ - { - "text": "Walk", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-75", - "type": "listing" - }, - "file": "fs/embed.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "fs", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "snippet": "main", - "src": "fs/src/embed/cmd/demo/main.go" - }, - "lang": "go", - "nodes": [ - { - "content": "func main() {\n\tfiles, err := demo.Walk(demo.DataFS)\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\n\tfor _, file := range files {\n\t\tfmt.Println(file)\n\t}\n}", - "file": "fs/src/embed/cmd/demo/main.go", - "lang": "go", - "name": "main", - "start": 9, - "end": 21, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "fs", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.75:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "fs", - "nodes": [ - { - "text": "main", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 75, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "fs/embed.md", - "nodes": [ - { - "text": "When we use ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "fs/embed.md", - "nodes": [ - { - "text": "go run", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " to run the application, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-76" - }, - "file": "fs/embed.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-76" - }, - "nodes": [ - { - "text": "Listing 1.76", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-76" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", we see that the output is as expected.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-76", - "type": "listing" - }, - "file": "fs/embed.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "run", - "." - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go run .", - "run": ".", - "src": "fs/src/embed/cmd/demo" - }, - "expected_exit": 0, - "file": "fs", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\ndata/a.txt\ndata/b.txt\ndata/e/f/g.txt\ndata/e/f/h.txt\ndata/e/j.txt", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/14-files/fs/src/embed/cmd/demo", - "stdout": "ZGF0YS9hLnR4dApkYXRhL2IudHh0CmRhdGEvZS9mL2cudHh0CmRhdGEvZS9mL2gudHh0CmRhdGEvZS9qLnR4dA==", - "duration": 1890138041, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go run .\n\ndata/a.txt\ndata/b.txt\ndata/e/f/g.txt\ndata/e/f/h.txt\ndata/e/j.txt", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "run", - "." - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/14-files/fs/src/embed/cmd/demo", - "stdout": "ZGF0YS9hLnR4dApkYXRhL2IudHh0CmRhdGEvZS9mL2cudHh0CmRhdGEvZS9mL2gudHh0CmRhdGEvZS9qLnR4dA==", - "duration": 1890138041, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "fs", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.76:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "fs", - "nodes": [ - { - "text": "go run", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " output.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 76, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "fs/embed.md", - "nodes": [ - { - "text": "Next, let's compile a binary of our application. We will use the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "fs/embed.md", - "nodes": [ - { - "text": "go build", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " command and output the binary to the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "fs/embed.md", - "nodes": [ - { - "text": "bin", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " directory.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-77", - "type": "listing" - }, - "file": "fs/embed.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "build", - "-o", - "bin/demo" - ], - "atom": "cmd", - "attributes": { - "build": "-o bin/demo", - "data-go-version": "go1.21.5", - "exec": "go build -o bin/demo", - "src": "fs/src/embed/cmd/demo" - }, - "expected_exit": 0, - "file": "fs", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go build -o bin/demo", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "build", - "-o", - "bin/demo" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/14-files/fs/src/embed/cmd/demo", - "duration": 1397606000, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go build -o bin/demo", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "build", - "-o", - "bin/demo" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/14-files/fs/src/embed/cmd/demo", - "duration": 1397606000, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "fs", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.77:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Building a binary with embedded files.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 77, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "fs/embed.md", - "nodes": [ - { - "text": "Finally, when we run the binary, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-78" - }, - "file": "fs/embed.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-78" - }, - "nodes": [ - { - "text": "Listing 1.78", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-78" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", we see that the output is as expected. Our application is able to successfully embed the files we defined. We now have a fully self-contained application that can contains, not just the necessary runtime needed to execute the binary on the desired ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "fs/embed.md", - "nodes": [ - { - "text": "GOOS", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " and ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "fs/embed.md", - "nodes": [ - { - "text": "GOARCH", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " combinations, but also the files we defined.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-78", - "type": "listing" - }, - "file": "fs/embed.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "bin/demo" - ], - "atom": "cmd", - "attributes": { - "exec": "bin/demo", - "src": "fs/src/embed/cmd/demo" - }, - "expected_exit": 0, - "file": "fs", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ bin/demo\n\ndata/a.txt\ndata/b.txt\ndata/e/f/g.txt\ndata/e/f/h.txt\ndata/e/j.txt", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "bin/demo" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/14-files/fs/src/embed/cmd/demo", - "stdout": "ZGF0YS9hLnR4dApkYXRhL2IudHh0CmRhdGEvZS9mL2cudHh0CmRhdGEvZS9mL2gudHh0CmRhdGEvZS9qLnR4dA==", - "duration": 574170709, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ bin/demo\n\ndata/a.txt\ndata/b.txt\ndata/e/f/g.txt\ndata/e/f/h.txt\ndata/e/j.txt", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "bin/demo" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/14-files/fs/src/embed/cmd/demo", - "stdout": "ZGF0YS9hLnR4dApkYXRhL2IudHh0CmRhdGEvZS9mL2cudHh0CmRhdGEvZS9mL2gudHh0CmRhdGEvZS9qLnR4dA==", - "duration": 574170709, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "fs", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.78:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Files are embedded in the binary.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 78, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "fs/embed.md", - "level": 2, - "nodes": [ - { - "text": "Modifying Embedded Files", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "fs/embed.md", - "nodes": [ - { - "text": "While we only needed to embed one directory, we can also embed multiple directories and files. We can do this by using the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "fs/embed.md", - "nodes": [ - { - "text": "//go:embed", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " directive multiple times.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-79", - "type": "listing" - }, - "file": "fs/embed.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "fs", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "snippet": "embed", - "src": "fs/src/embed-broken/demo.go" - }, - "lang": "go", - "nodes": [ - { - "content": "//go:embed data\n//go:embed cmd\n//go:embed go.mod\nvar DataFS embed.FS", - "file": "fs/src/embed-broken/demo.go", - "lang": "go", - "name": "embed", - "start": 9, - "end": 15, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "fs", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.79:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "fs", - "nodes": [ - { - "text": "//go:embed", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " directive.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 79, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "fs/embed.md", - "nodes": [ - { - "text": "As we can see from the test output, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-80" - }, - "file": "fs/embed.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-80" - }, - "nodes": [ - { - "text": "Listing 1.80", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-80" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", the extra ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "fs/embed.md", - "nodes": [ - { - "text": "//go:embed", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " directives embedded the files we did not want and as a result the test failed.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-80", - "type": "listing" - }, - "file": "fs/embed.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "test", - "-v" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go test -v", - "exit": "-1", - "src": "fs/src/embed-broken", - "test": "-v" - }, - "expected_exit": -1, - "file": "fs", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go test -v\n\n=== RUN Test_Walk\n=== PAUSE Test_Walk\n=== CONT Test_Walk\n demo_test.go:29: expected data/a.txt,\n data/b.txt,\n data/e/f/g.txt,\n data/e/f/h.txt,\n data/e/j.txt, got cmd/demo/main.go,\n data/a.txt,\n data/b.txt,\n data/e/f/g.txt,\n data/e/f/h.txt,\n data/e/j.txt,\n go.mod\n--- FAIL: Test_Walk (0.00s)\nFAIL\nexit status 1\nFAIL\tdemo\t0.394s", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "test", - "-v" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/14-files/fs/src/embed-broken", - "err": { - "Stderr": null - }, - "exit": 1, - "stdout": "PT09IFJVTiAgIFRlc3RfV2Fsawo9PT0gUEFVU0UgVGVzdF9XYWxrCj09PSBDT05UICBUZXN0X1dhbGsKICAgIGRlbW9fdGVzdC5nbzoyOTogZXhwZWN0ZWQgZGF0YS9hLnR4dCwKICAgICAgICBkYXRhL2IudHh0LAogICAgICAgIGRhdGEvZS9mL2cudHh0LAogICAgICAgIGRhdGEvZS9mL2gudHh0LAogICAgICAgIGRhdGEvZS9qLnR4dCwgZ290IGNtZC9kZW1vL21haW4uZ28sCiAgICAgICAgZGF0YS9hLnR4dCwKICAgICAgICBkYXRhL2IudHh0LAogICAgICAgIGRhdGEvZS9mL2cudHh0LAogICAgICAgIGRhdGEvZS9mL2gudHh0LAogICAgICAgIGRhdGEvZS9qLnR4dCwKICAgICAgICBnby5tb2QKLS0tIEZBSUw6IFRlc3RfV2FsayAoMC4wMHMpCkZBSUwKZXhpdCBzdGF0dXMgMQpGQUlMCWRlbW8JMC4zOTRz", - "duration": 955859167, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go test -v\n\n=== RUN Test_Walk\n=== PAUSE Test_Walk\n=== CONT Test_Walk\n demo_test.go:29: expected data/a.txt,\n data/b.txt,\n data/e/f/g.txt,\n data/e/f/h.txt,\n data/e/j.txt, got cmd/demo/main.go,\n data/a.txt,\n data/b.txt,\n data/e/f/g.txt,\n data/e/f/h.txt,\n data/e/j.txt,\n go.mod\n--- FAIL: Test_Walk (0.00s)\nFAIL\nexit status 1\nFAIL\tdemo\t0.394s", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "test", - "-v" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/14-files/fs/src/embed-broken", - "err": { - "Stderr": null - }, - "exit": 1, - "stdout": "PT09IFJVTiAgIFRlc3RfV2Fsawo9PT0gUEFVU0UgVGVzdF9XYWxrCj09PSBDT05UICBUZXN0X1dhbGsKICAgIGRlbW9fdGVzdC5nbzoyOTogZXhwZWN0ZWQgZGF0YS9hLnR4dCwKICAgICAgICBkYXRhL2IudHh0LAogICAgICAgIGRhdGEvZS9mL2cudHh0LAogICAgICAgIGRhdGEvZS9mL2gudHh0LAogICAgICAgIGRhdGEvZS9qLnR4dCwgZ290IGNtZC9kZW1vL21haW4uZ28sCiAgICAgICAgZGF0YS9hLnR4dCwKICAgICAgICBkYXRhL2IudHh0LAogICAgICAgIGRhdGEvZS9mL2cudHh0LAogICAgICAgIGRhdGEvZS9mL2gudHh0LAogICAgICAgIGRhdGEvZS9qLnR4dCwKICAgICAgICBnby5tb2QKLS0tIEZBSUw6IFRlc3RfV2FsayAoMC4wMHMpCkZBSUwKZXhpdCBzdGF0dXMgMQpGQUlMCWRlbW8JMC4zOTRz", - "duration": 955859167, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "fs", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.80:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Using multiple ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "fs", - "nodes": [ - { - "text": "//go:embed", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " directives.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 80, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "fs/embed.md", - "level": 2, - "nodes": [ - { - "text": "Embedding Files as a String or Byte Slice", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "fs/embed.md", - "nodes": [ - { - "text": "In addition to embedding files, and directories, to a ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "embed#FS", - "href": "https://pkg.go.dev/embed#FS", - "target": "_blank" - }, - "file": "fs/embed.md", - "nodes": [ - { - "atom": "code", - "file": "fs/embed.md", - "nodes": [ - { - "text": "embed.FS", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/embed#FS" - } - ], - { - "text": ", we can also embed the contents of a file as a ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "fs/embed.md", - "nodes": [ - { - "text": "string", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " or ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "fs/embed.md", - "nodes": [ - { - "text": "[]byte", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ". This makes gaining access to the contents of a file easier.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-81", - "type": "listing" - }, - "file": "fs/embed.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "file": "fs", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "fs/src/strings/demo.go" - }, - "lang": "go", - "nodes": [ - { - "text": "package demo\n\nimport _ \u0026#34;embed\u0026#34;\n\n//go:embed data/LICENSE\nvar LICENSE string\n\n//go:embed data/LICENSE\nvar LICENSE_BYTES []byte\n", - "type": "hype.Text" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "fs", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.81:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "fs", - "nodes": [ - { - "text": "//go:embed", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " directive with a ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "fs", - "nodes": [ - { - "text": "string", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " and a ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "fs", - "nodes": [ - { - "text": "[]byte", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 81, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-82", - "type": "listing" - }, - "file": "fs/embed.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "test", - "-v" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go test -v", - "src": "fs/src/strings", - "test": "-v" - }, - "expected_exit": 0, - "file": "fs", - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go test -v\n\n=== RUN Test_Embed_String\n=== PAUSE Test_Embed_String\n=== RUN Test_Embed_Bytes\n=== PAUSE Test_Embed_Bytes\n=== CONT Test_Embed_String\n=== CONT Test_Embed_Bytes\n--- PASS: Test_Embed_String (0.00s)\n--- PASS: Test_Embed_Bytes (0.00s)\nPASS\nok \tdemo\t0.372s", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "test", - "-v" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/14-files/fs/src/strings", - "stdout": "PT09IFJVTiAgIFRlc3RfRW1iZWRfU3RyaW5nCj09PSBQQVVTRSBUZXN0X0VtYmVkX1N0cmluZwo9PT0gUlVOICAgVGVzdF9FbWJlZF9CeXRlcwo9PT0gUEFVU0UgVGVzdF9FbWJlZF9CeXRlcwo9PT0gQ09OVCAgVGVzdF9FbWJlZF9TdHJpbmcKPT09IENPTlQgIFRlc3RfRW1iZWRfQnl0ZXMKLS0tIFBBU1M6IFRlc3RfRW1iZWRfU3RyaW5nICgwLjAwcykKLS0tIFBBU1M6IFRlc3RfRW1iZWRfQnl0ZXMgKDAuMDBzKQpQQVNTCm9rICAJZGVtbwkwLjM3MnM=", - "duration": 1708282708, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go test -v\n\n=== RUN Test_Embed_String\n=== PAUSE Test_Embed_String\n=== RUN Test_Embed_Bytes\n=== PAUSE Test_Embed_Bytes\n=== CONT Test_Embed_String\n=== CONT Test_Embed_Bytes\n--- PASS: Test_Embed_String (0.00s)\n--- PASS: Test_Embed_Bytes (0.00s)\nPASS\nok \tdemo\t0.372s", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "test", - "-v" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/14-files/fs/src/strings", - "stdout": "PT09IFJVTiAgIFRlc3RfRW1iZWRfU3RyaW5nCj09PSBQQVVTRSBUZXN0X0VtYmVkX1N0cmluZwo9PT0gUlVOICAgVGVzdF9FbWJlZF9CeXRlcwo9PT0gUEFVU0UgVGVzdF9FbWJlZF9CeXRlcwo9PT0gQ09OVCAgVGVzdF9FbWJlZF9TdHJpbmcKPT09IENPTlQgIFRlc3RfRW1iZWRfQnl0ZXMKLS0tIFBBU1M6IFRlc3RfRW1iZWRfU3RyaW5nICgwLjAwcykKLS0tIFBBU1M6IFRlc3RfRW1iZWRfQnl0ZXMgKDAuMDBzKQpQQVNTCm9rICAJZGVtbwkwLjM3MnM=", - "duration": 1708282708, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "file": "fs", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.82:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Using ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "fs", - "nodes": [ - { - "text": "//go:embed", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " we can gain direct access to files as a ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "fs", - "nodes": [ - { - "text": "string", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " or ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "fs", - "nodes": [ - { - "text": "[]byte", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 82, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "title": "Embedding Files", - "type": "*hype.Page" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "type": "*hype.Include" - } - ], - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "page", - "file": "module.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "h1", - "file": "module.md", - "level": 1, - "nodes": [ - { - "text": "Summary", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "module.md", - "nodes": [ - { - "text": "In this ", - "type": "hype.Text" - }, - { - "atom": "binding", - "attributes": { - "part": "" - }, - "file": "module.md", - "type": "*hype.Element" - }, - { - "text": ", we delved deep into using files with Go. We learned how to create, read, and append to files. We learned about the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "io/fs#FS", - "href": "https://pkg.go.dev/io/fs#FS", - "target": "_blank" - }, - "file": "module.md", - "nodes": [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "fs.FS", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/io/fs#FS" - } - ], - { - "text": " and ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "io/fs#File", - "href": "https://pkg.go.dev/io/fs#File", - "target": "_blank" - }, - "file": "module.md", - "nodes": [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "fs.File", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/io/fs#File" - } - ], - { - "text": " interfaces that make working with readonly file systems easier. We learned how to mock out file systems for testing. We also learned to read and walk directories. Finally, we learned how to use the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "embed", - "href": "https://pkg.go.dev/embed", - "target": "_blank" - }, - "file": "module.md", - "nodes": [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "embed", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/embed" - } - ], - { - "text": " package to embed files into our Go binaries.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "title": "Summary", - "type": "*hype.Page" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "type": "*hype.Body" - } - ] - ], - "type": "*hype.Element" - } - ], - "type": "*hype.Element" - } - ], - "parser": { - "type": "*hype.Parser", - "root": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/14-files", - "section": 1, - "snippets": {} - }, - "root": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/14-files", - "section_id": 1, - "snippets": {}, - "title": "Working With Files", - "type": "*hype.Document", - "filename": "module.md" -} \ No newline at end of file diff --git a/src/testdata/generics.json b/src/testdata/generics.json deleted file mode 100644 index dfa046f..0000000 --- a/src/testdata/generics.json +++ /dev/null @@ -1,11721 +0,0 @@ -{ - "nodes": [ - { - "file": "module.md", - "nodes": [ - { - "atom": "html", - "file": "module.md", - "nodes": [ - { - "atom": "head", - "file": "module.md", - "type": "*hype.Element" - }, - [ - { - "atom": "body", - "file": "module.md", - "nodes": [ - [ - { - "atom": "page", - "file": "module.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "h1", - "file": "module.md", - "level": 1, - "nodes": [ - { - "text": "Generics", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "module.md", - "nodes": [ - [ - { - "atom": "a", - "attributes": { - "href": "https://en.wikipedia.org/wiki/Generic_programming", - "target": "_blank" - }, - "file": "module.md", - "nodes": [ - { - "text": "Generics", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "https://en.wikipedia.org/wiki/Generic_programming" - } - ], - { - "text": " were first introduced to Go with the release of ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "href": "https://go.dev/blog/intro-generics", - "target": "_blank" - }, - "file": "module.md", - "nodes": [ - { - "text": "Go 1.18", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "https://go.dev/blog/intro-generics" - } - ], - { - "text": ". Go 1.18 was release in March of 2022, during the writing of this ", - "type": "hype.Text" - }, - { - "atom": "binding", - "attributes": { - "whole": "" - }, - "file": "module.md", - "type": "*hype.Element" - }, - { - "text": ". We, like the Go team, have tried our best to present the current idioms and thoughts on the how, what, when, where, and why questions about generics in Go.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "module.md", - "level": 2, - "nodes": [ - { - "text": "What are Generics?", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "module.md", - "nodes": [ - { - "text": "Generic programming is a programming paradigm that allows us to stub out the implementation of a function with a type that will be provided later. This has benefits for both writing, and using, generic functions. With generics we can write functions that can work with multiple types directly, without having to write the same function multiple times, once for each type. When using generic functions, we can continue use our types as concrete types, instead of interface representations.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "module.md", - "level": 2, - "nodes": [ - { - "text": "The Problem with Interfaces", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "module.md", - "nodes": [ - { - "text": "Interfaces in Go are a powerful concept that allows developers to create flexible and reusable code. Interfaces allow us to define a set of methods that describe the behavior of a type. Any type that implements those methods, and behaviors, is considered to implement that interface.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "module.md", - "nodes": [ - { - "text": "We have already discussed the benefits and drawbacks of interfaces earlier in this ", - "type": "hype.Text" - }, - { - "atom": "binding", - "attributes": { - "whole": "" - }, - "file": "module.md", - "type": "*hype.Element" - }, - { - "text": " so we don't have to re-iterate the benefits of interfaces, but let's discuss some problems with interfaces. For example, consider the function defined in ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-1" - }, - "file": "module.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-1" - }, - "nodes": [ - { - "text": "Listing 1.1", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-1" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", and the problem of how to write a function that will return the keys for a given map.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-1", - "type": "listing" - }, - "file": "module.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "doc", - "-cmd", - "-u", - "-src", - "-short", - "Keys" - ], - "atom": "cmd", - "attributes": { - "exec": "go doc -cmd -u -src -short Keys", - "hide-cmd": "", - "language": "go", - "src": "src/keys/any", - "sym": "Keys" - }, - "expected_exit": 0, - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go" - }, - "lang": "go", - "nodes": [ - { - "text": "func Keys(m map[any]any) []any {\n\n\t// make a slice of the keys\n\tkeys := make([]any, 0, len(m))\n\n\t// iterate over the map\n\tfor k := range m {\n\n\t\t// add the key to the slice\n\t\tkeys = append(keys, k)\n\t}\n\n\t// return the keys\n\treturn keys\n}", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "-cmd", - "-u", - "-src", - "-short", - "Keys" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/10-generics/src/keys/any", - "stdout": "ZnVuYyBLZXlzKG0gbWFwW2FueV1hbnkpIFtdYW55IHsKCgkvLyBtYWtlIGEgc2xpY2Ugb2YgdGhlIGtleXMKCWtleXMgOj0gbWFrZShbXWFueSwgMCwgbGVuKG0pKQoKCS8vIGl0ZXJhdGUgb3ZlciB0aGUgbWFwCglmb3IgayA6PSByYW5nZSBtIHsKCgkJLy8gYWRkIHRoZSBrZXkgdG8gdGhlIHNsaWNlCgkJa2V5cyA9IGFwcGVuZChrZXlzLCBrKQoJfQoKCS8vIHJldHVybiB0aGUga2V5cwoJcmV0dXJuIGtleXMKfQ==", - "duration": 53894083, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go" - }, - "lang": "go", - "nodes": [ - { - "text": "func Keys(m map[any]any) []any {\n\n\t// make a slice of the keys\n\tkeys := make([]any, 0, len(m))\n\n\t// iterate over the map\n\tfor k := range m {\n\n\t\t// add the key to the slice\n\t\tkeys = append(keys, k)\n\t}\n\n\t// return the keys\n\treturn keys\n}", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "-cmd", - "-u", - "-src", - "-short", - "Keys" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/10-generics/src/keys/any", - "stdout": "ZnVuYyBLZXlzKG0gbWFwW2FueV1hbnkpIFtdYW55IHsKCgkvLyBtYWtlIGEgc2xpY2Ugb2YgdGhlIGtleXMKCWtleXMgOj0gbWFrZShbXWFueSwgMCwgbGVuKG0pKQoKCS8vIGl0ZXJhdGUgb3ZlciB0aGUgbWFwCglmb3IgayA6PSByYW5nZSBtIHsKCgkJLy8gYWRkIHRoZSBrZXkgdG8gdGhlIHNsaWNlCgkJa2V5cyA9IGFwcGVuZChrZXlzLCBrKQoJfQoKCS8vIHJldHVybiB0aGUga2V5cwoJcmV0dXJuIGtleXMKfQ==", - "duration": 53894083, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.1:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "A function that returns the keys of a map.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 1, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "module.md", - "nodes": [ - { - "text": "Go is a statically typed language and so we have to specify the type of the map that we want to get the keys from. A map needs to have both its key and value types specified. We also need to specify the type of slice this function will be returning. In order for this function to support all map types we need to use the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "any", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ", or empty interface, type which will match any type.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "module.md", - "nodes": [ - { - "text": "While this means we can write a function that we return a list of keys from a map, it also means that this function is difficult to use. Consider a test, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-2" - }, - "file": "module.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-2" - }, - "nodes": [ - { - "text": "Listing 1.2", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-2" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", that tries use a map that isn't of type ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "map[any]any", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ". This code fails to compile because the type of map in the test is not compatible with the type of map required by the function.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-2", - "type": "listing" - }, - "file": "module.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "src/keys/any/keys_test.go#example" - }, - "lang": "go", - "nodes": [ - { - "content": "func Test_Keys(t *testing.T) {\n\tt.Parallel()\n\n\t// create a map with some values\n\tm := map[int]string{\n\t\t1: \"one\",\n\t\t2: \"two\",\n\t\t3: \"three\",\n\t}\n\n\t// get the keys\n\tact := Keys(m)\n\n\t// sort the returned keys for comparison\n\tsort.Slice(act, func(i, j int) bool {\n\t\treturn act[i] \u003c act[j]\n\t})\n\n\t// set the expected values\n\texp := []int{1, 2, 3}\n\n\t// assert the length of the actual and expected values\n\tal := len(act)\n\tel := len(exp)\n\tif al != el {\n\t\tt.Fatalf(\"expected %d, but got %d\", el, al)\n\t}\n\n\t// loop through the expected values and\n\t// assert they are in the actual values\n\tfor i, v := range exp {\n\t\tif v != act[i] {\n\t\t\tt.Fatalf(\"expected %d, but got %d\", v, act[i])\n\t\t}\n\t}\n\n}", - "file": "src/keys/any/keys_test.go", - "lang": "go", - "name": "example", - "start": 8, - "end": 47, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "atom": "hr", - "type": "*hype.Element" - }, - [ - { - "args": [ - "go", - "test", - "-v" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go test -v", - "exit": "-1", - "src": "src/keys/any", - "test": "-v" - }, - "expected_exit": -1, - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go test -v\n\nFAIL\tdemo [build failed]\n\n# demo [demo.test]\n./keys_test.go:20:14: cannot use m (variable of type map[int]string) as map[any]any value in argument to Keys\n./keys_test.go:24:10: invalid operation: act[i] \u0026lt; act[j] (operator \u0026lt; not defined on interface)", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "test", - "-v" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/10-generics/src/keys/any", - "err": { - "Stderr": null - }, - "exit": 1, - "stderr": "IyBkZW1vIFtkZW1vLnRlc3RdCi4va2V5c190ZXN0LmdvOjIwOjE0OiBjYW5ub3QgdXNlIG0gKHZhcmlhYmxlIG9mIHR5cGUgbWFwW2ludF1zdHJpbmcpIGFzIG1hcFthbnldYW55IHZhbHVlIGluIGFyZ3VtZW50IHRvIEtleXMKLi9rZXlzX3Rlc3QuZ286MjQ6MTA6IGludmFsaWQgb3BlcmF0aW9uOiBhY3RbaV0gPCBhY3Rbal0gKG9wZXJhdG9yIDwgbm90IGRlZmluZWQgb24gaW50ZXJmYWNlKQ==", - "stdout": "RkFJTAlkZW1vIFtidWlsZCBmYWlsZWRd", - "duration": 258040375, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go test -v\n\nFAIL\tdemo [build failed]\n\n# demo [demo.test]\n./keys_test.go:20:14: cannot use m (variable of type map[int]string) as map[any]any value in argument to Keys\n./keys_test.go:24:10: invalid operation: act[i] \u0026lt; act[j] (operator \u0026lt; not defined on interface)", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "test", - "-v" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/10-generics/src/keys/any", - "err": { - "Stderr": null - }, - "exit": 1, - "stderr": "IyBkZW1vIFtkZW1vLnRlc3RdCi4va2V5c190ZXN0LmdvOjIwOjE0OiBjYW5ub3QgdXNlIG0gKHZhcmlhYmxlIG9mIHR5cGUgbWFwW2ludF1zdHJpbmcpIGFzIG1hcFthbnldYW55IHZhbHVlIGluIGFyZ3VtZW50IHRvIEtleXMKLi9rZXlzX3Rlc3QuZ286MjQ6MTA6IGludmFsaWQgb3BlcmF0aW9uOiBhY3RbaV0gPCBhY3Rbal0gKG9wZXJhdG9yIDwgbm90IGRlZmluZWQgb24gaW50ZXJmYWNlKQ==", - "stdout": "RkFJTAlkZW1vIFtidWlsZCBmYWlsZWRd", - "duration": 258040375, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.2:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Compilation error caused by a type mismatch.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 2, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "module.md", - "nodes": [ - { - "text": "In ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-3" - }, - "file": "module.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-3" - }, - "nodes": [ - { - "text": "Listing 1.3", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-3" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": " is an attempt to solve this problem. First, we need to create a new, interstitial map of the correct type, and copy all of the keys from the original map into the new map. The same is true of trying to handle the results. We need to loop through the returned slice of keys, asserts the keys are of the correct type, and then copy those values into a new slice of the correct type.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-3", - "type": "listing" - }, - "file": "module.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "src/keys/fixed/keys_test.go#example" - }, - "lang": "go", - "nodes": [ - { - "content": "func Test_Keys(t *testing.T) {\n\tt.Parallel()\n\n\t// create a map with some values\n\tm := map[int]string{\n\t\t1: \"one\",\n\t\t2: \"two\",\n\t\t3: \"three\",\n\t}\n\n\t// create an interstitial map to pass to the function\n\tim := map[any]any{}\n\n\t// copy the map into the interstitial map\n\tfor k, v := range m {\n\t\tim[k] = v\n\t}\n\n\t// get the keys\n\tkeys := Keys(im)\n\n\t// create a slice to hold the keys as\n\t// integers for comparison\n\tact := make([]int, 0, len(keys))\n\n\t// copy the keys into the integer slice\n\tfor _, k := range keys {\n\t\t// assert that the key is an int\n\t\ti, ok := k.(int)\n\t\tif !ok {\n\t\t\tt.Fatalf(\"expected type int, got %T\", k)\n\t\t}\n\n\t\tact = append(act, i)\n\t}\n\n\t// sort the returned keys for comparison\n\tsort.Slice(act, func(i, j int) bool {\n\t\treturn act[i] \u003c act[j]\n\t})\n\n\t// set the expected values\n\texp := []int{1, 2, 3}\n\n\t// assert the length of the actual and expected values\n\tal := len(act)\n\tel := len(exp)\n\tif al != el {\n\t\tt.Fatalf(\"expected %d, but got %d\", el, al)\n\t}\n\n\t// loop through the expected values and\n\t// assert they are in the actual values\n\tfor i, v := range exp {\n\t\tif v != act[i] {\n\t\t\tt.Fatalf(\"expected %d, but got %d\", v, act[i])\n\t\t}\n\t}\n\n}", - "file": "src/keys/fixed/keys_test.go", - "lang": "go", - "name": "example", - "start": 8, - "end": 70, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "atom": "hr", - "type": "*hype.Element" - }, - [ - { - "args": [ - "go", - "test", - "-v" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go test -v", - "src": "src/keys/fixed", - "test": "-v" - }, - "expected_exit": 0, - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go test -v\n\n=== RUN Test_Keys\n=== PAUSE Test_Keys\n=== CONT Test_Keys\n--- PASS: Test_Keys (0.00s)\nPASS\nok \tdemo\t0.405s", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "test", - "-v" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/10-generics/src/keys/fixed", - "stdout": "PT09IFJVTiAgIFRlc3RfS2V5cwo9PT0gUEFVU0UgVGVzdF9LZXlzCj09PSBDT05UICBUZXN0X0tleXMKLS0tIFBBU1M6IFRlc3RfS2V5cyAoMC4wMHMpClBBU1MKb2sgIAlkZW1vCTAuNDA1cw==", - "duration": 1482057375, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go test -v\n\n=== RUN Test_Keys\n=== PAUSE Test_Keys\n=== CONT Test_Keys\n--- PASS: Test_Keys (0.00s)\nPASS\nok \tdemo\t0.405s", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "test", - "-v" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/10-generics/src/keys/fixed", - "stdout": "PT09IFJVTiAgIFRlc3RfS2V5cwo9PT0gUEFVU0UgVGVzdF9LZXlzCj09PSBDT05UICBUZXN0X0tleXMKLS0tIFBBU1M6IFRlc3RfS2V5cyAoMC4wMHMpClBBU1MKb2sgIAlkZW1vCTAuNDA1cw==", - "duration": 1482057375, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.3:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Copying maps to satisfy a type constraint.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 3, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "module.md", - "nodes": [ - { - "text": "While ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-3" - }, - "file": "module.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-3" - }, - "nodes": [ - { - "text": "Listing 1.3", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-3" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": " fixes the tests, it is a very cumbersome way to work with a function such as this. Generics, were designed to help solve exactly this sort of problem.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "module.md", - "level": 2, - "nodes": [ - { - "text": "Type Constraints", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "module.md", - "nodes": [ - { - "text": "Generics in Go introduced a new concept to the language, called Type Constraints. Type Constraints allow us to specify that a type fits within a certain set of constraints. This is useful when we want to write a function that can work with multiple types, but we want to be able to specify that the function can only work with a specific type.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "module.md", - "nodes": [ - { - "text": "For example, so far have been using an ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "int", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " for the key type in a map, and ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "string", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " for the value type. This is fine, but we can use generics to make this more flexible. We may want to use an ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "int32", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " or a ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "float64", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " for the key type, and ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "any", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " value for the value type.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "module.md", - "nodes": [ - { - "text": "Generics allows us to specify those types as constraints when defining a function or a type. Constraints are added with ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "[]", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " after the name of the function or type, but before any parameters. ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-4" - }, - "file": "module.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-4" - }, - "nodes": [ - { - "text": "Listing 1.4", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-4" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": " lays out the anatomy of a generic function.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-4", - "type": "listing" - }, - "file": "module.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go" - }, - "lang": "go", - "nodes": [ - { - "text": "func Name[constraints](parameters) (returns) {\n\t// ...\n}\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.4:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Anatomy of a generic function.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 4, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "module.md", - "nodes": [ - { - "text": "For example, in ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-5" - }, - "file": "module.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-5" - }, - "nodes": [ - { - "text": "Listing 1.5", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-5" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", we define a ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "Slicer", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function that defines a constraint, type ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "T", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ", which can be of ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "any", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " type. That new ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "T", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " type can then be used in the function signature. In ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-5" - }, - "file": "module.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-5" - }, - "nodes": [ - { - "text": "Listing 1.5", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-5" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "Slicer", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function will return a slice of ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "T", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " values.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-5", - "type": "listing" - }, - "file": "module.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "doc", - "-cmd", - "-u", - "-src", - "-short", - "Slicer" - ], - "atom": "cmd", - "attributes": { - "exec": "go doc -cmd -u -src -short Slicer", - "hide-cmd": "", - "language": "go", - "src": "src/slicer", - "sym": "Slicer" - }, - "expected_exit": 0, - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go" - }, - "lang": "go", - "nodes": [ - { - "text": "func Slicer[T any](input T) []T {\n\treturn []T{input}\n}", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "-cmd", - "-u", - "-src", - "-short", - "Slicer" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/10-generics/src/slicer", - "stdout": "ZnVuYyBTbGljZXJbVCBhbnldKGlucHV0IFQpIFtdVCB7CglyZXR1cm4gW11Ue2lucHV0fQp9", - "duration": 365827792, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go" - }, - "lang": "go", - "nodes": [ - { - "text": "func Slicer[T any](input T) []T {\n\treturn []T{input}\n}", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "-cmd", - "-u", - "-src", - "-short", - "Slicer" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/10-generics/src/slicer", - "stdout": "ZnVuYyBTbGljZXJbVCBhbnldKGlucHV0IFQpIFtdVCB7CglyZXR1cm4gW11Ue2lucHV0fQp9", - "duration": 365827792, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.5:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "A generic function that returns a slice of values.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 5, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "module.md", - "nodes": [ - { - "text": "When calling the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "Slicer", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function, as seen in ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-6" - }, - "file": "module.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-6" - }, - "nodes": [ - { - "text": "Listing 1.6", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-6" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": " we can pass any type, and it returns a slice of that same type back.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-6", - "type": "listing" - }, - "file": "module.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "src/slicer/slicer_test.go#example" - }, - "lang": "go", - "nodes": [ - { - "content": "func Test_Slicer(t *testing.T) {\n\tt.Parallel()\n\n\t// create input string\n\tinput := \"Hello World\"\n\n\t// capture output []string\n\tact := Slicer(input)\n\n\texp := []string{input}\n\n\tif len(act) != len(exp) {\n\t\tt.Fatalf(\"expected %v, got %v\", exp, act)\n\t}\n\n\tfor i, v := range exp {\n\t\tif act[i] != v {\n\t\t\tt.Fatalf(\"expected %v, got %v\", exp, act)\n\t\t}\n\t}\n\n}", - "file": "src/slicer/slicer_test.go", - "lang": "go", - "name": "example", - "start": 7, - "end": 31, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "atom": "hr", - "type": "*hype.Element" - }, - [ - { - "args": [ - "go", - "test", - "-v" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go test -v", - "src": "src/slicer", - "test": "-v" - }, - "expected_exit": 0, - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go test -v\n\n=== RUN Test_Slicer\n=== PAUSE Test_Slicer\n=== CONT Test_Slicer\n--- PASS: Test_Slicer (0.00s)\nPASS\nok \tdemo\t0.300s", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "test", - "-v" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/10-generics/src/slicer", - "stdout": "PT09IFJVTiAgIFRlc3RfU2xpY2VyCj09PSBQQVVTRSBUZXN0X1NsaWNlcgo9PT0gQ09OVCAgVGVzdF9TbGljZXIKLS0tIFBBU1M6IFRlc3RfU2xpY2VyICgwLjAwcykKUEFTUwpvayAgCWRlbW8JMC4zMDBz", - "duration": 1660076000, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go test -v\n\n=== RUN Test_Slicer\n=== PAUSE Test_Slicer\n=== CONT Test_Slicer\n--- PASS: Test_Slicer (0.00s)\nPASS\nok \tdemo\t0.300s", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "test", - "-v" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/10-generics/src/slicer", - "stdout": "PT09IFJVTiAgIFRlc3RfU2xpY2VyCj09PSBQQVVTRSBUZXN0X1NsaWNlcgo9PT0gQ09OVCAgVGVzdF9TbGljZXIKLS0tIFBBU1M6IFRlc3RfU2xpY2VyICgwLjAwcykKUEFTUwpvayAgCWRlbW8JMC4zMDBz", - "duration": 1660076000, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.6:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Calling a generic function.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 6, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "module.md", - "nodes": [ - { - "text": "In our tests we passed a ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "string", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " type to the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "Slicer", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function. At compile time, sees that we are calling the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "Slicer", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function with a ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "string", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " type and then inserts a function with the appropriate typed signature. For example, by passing a ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "string", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " type to the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "Slicer", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function, the compiler generates a function that looks like ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-7" - }, - "file": "module.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-7" - }, - "nodes": [ - { - "text": "Listing 1.7", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-7" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-7", - "type": "listing" - }, - "file": "module.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "doc", - "-cmd", - "-u", - "-src", - "-short", - "Slicer" - ], - "atom": "cmd", - "attributes": { - "exec": "go doc -cmd -u -src -short Slicer", - "hide-cmd": "", - "language": "go", - "src": "src/slicer-static", - "sym": "Slicer" - }, - "expected_exit": 0, - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go" - }, - "lang": "go", - "nodes": [ - { - "text": "func Slicer(input string) []string {\n\treturn []string{input}\n}", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "-cmd", - "-u", - "-src", - "-short", - "Slicer" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/10-generics/src/slicer-static", - "stdout": "ZnVuYyBTbGljZXIoaW5wdXQgc3RyaW5nKSBbXXN0cmluZyB7CglyZXR1cm4gW11zdHJpbmd7aW5wdXR9Cn0=", - "duration": 311013500, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go" - }, - "lang": "go", - "nodes": [ - { - "text": "func Slicer(input string) []string {\n\treturn []string{input}\n}", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "-cmd", - "-u", - "-src", - "-short", - "Slicer" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/10-generics/src/slicer-static", - "stdout": "ZnVuYyBTbGljZXIoaW5wdXQgc3RyaW5nKSBbXXN0cmluZyB7CglyZXR1cm4gW11zdHJpbmd7aW5wdXR9Cn0=", - "duration": 311013500, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.7:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "A static function that returns a slice of strings.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 7, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "module.md", - "level": 2, - "nodes": [ - { - "text": "Multiple Generic Types", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "module.md", - "nodes": [ - { - "text": "With an understanding of the basics of generics, let's revisit the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "Keys", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function in ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-8" - }, - "file": "module.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-8" - }, - "nodes": [ - { - "text": "Listing 1.8", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-8" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", and update it to support generics.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-8", - "type": "listing" - }, - "file": "module.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "doc", - "-cmd", - "-u", - "-src", - "-short", - "Keys" - ], - "atom": "cmd", - "attributes": { - "exec": "go doc -cmd -u -src -short Keys", - "hide-cmd": "", - "language": "go", - "src": "src/keys/fixed", - "sym": "Keys" - }, - "expected_exit": 0, - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go" - }, - "lang": "go", - "nodes": [ - { - "text": "// snippet: def\nfunc Keys(m map[any]any) []any {\n\t// snippet: def\n\n\t// make a slice of the keys\n\tkeys := make([]any, 0, len(m))\n\n\t// iterate over the map\n\tfor k := range m {\n\n\t\t// add the key to the slice\n\t\tkeys = append(keys, k)\n\t}\n\n\t// return the keys\n\treturn keys\n}", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "-cmd", - "-u", - "-src", - "-short", - "Keys" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/10-generics/src/keys/fixed", - "stdout": "Ly8gc25pcHBldDogZGVmCmZ1bmMgS2V5cyhtIG1hcFthbnldYW55KSBbXWFueSB7CgkvLyBzbmlwcGV0OiBkZWYKCgkvLyBtYWtlIGEgc2xpY2Ugb2YgdGhlIGtleXMKCWtleXMgOj0gbWFrZShbXWFueSwgMCwgbGVuKG0pKQoKCS8vIGl0ZXJhdGUgb3ZlciB0aGUgbWFwCglmb3IgayA6PSByYW5nZSBtIHsKCgkJLy8gYWRkIHRoZSBrZXkgdG8gdGhlIHNsaWNlCgkJa2V5cyA9IGFwcGVuZChrZXlzLCBrKQoJfQoKCS8vIHJldHVybiB0aGUga2V5cwoJcmV0dXJuIGtleXMKfQ==", - "duration": 594976959, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go" - }, - "lang": "go", - "nodes": [ - { - "text": "// snippet: def\nfunc Keys(m map[any]any) []any {\n\t// snippet: def\n\n\t// make a slice of the keys\n\tkeys := make([]any, 0, len(m))\n\n\t// iterate over the map\n\tfor k := range m {\n\n\t\t// add the key to the slice\n\t\tkeys = append(keys, k)\n\t}\n\n\t// return the keys\n\treturn keys\n}", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "-cmd", - "-u", - "-src", - "-short", - "Keys" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/10-generics/src/keys/fixed", - "stdout": "Ly8gc25pcHBldDogZGVmCmZ1bmMgS2V5cyhtIG1hcFthbnldYW55KSBbXWFueSB7CgkvLyBzbmlwcGV0OiBkZWYKCgkvLyBtYWtlIGEgc2xpY2Ugb2YgdGhlIGtleXMKCWtleXMgOj0gbWFrZShbXWFueSwgMCwgbGVuKG0pKQoKCS8vIGl0ZXJhdGUgb3ZlciB0aGUgbWFwCglmb3IgayA6PSByYW5nZSBtIHsKCgkJLy8gYWRkIHRoZSBrZXkgdG8gdGhlIHNsaWNlCgkJa2V5cyA9IGFwcGVuZChrZXlzLCBrKQoJfQoKCS8vIHJldHVybiB0aGUga2V5cwoJcmV0dXJuIGtleXMKfQ==", - "duration": 594976959, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.8:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "nodes": [ - { - "text": "Keys", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function before generics.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 8, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "module.md", - "nodes": [ - { - "text": "A map has both a key and a value type. We can use generics to specify which types are allowed to be used for both. In ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-9" - }, - "file": "module.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-9" - }, - "nodes": [ - { - "text": "Listing 1.9", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-9" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", we can specify that the key type, ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "K", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ", must of a type ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "int", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ", but the value type, ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "V", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ", can be of any type.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-9", - "type": "listing" - }, - "file": "module.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "doc", - "-cmd", - "-u", - "-src", - "-short", - "Keys" - ], - "atom": "cmd", - "attributes": { - "exec": "go doc -cmd -u -src -short Keys", - "hide-cmd": "", - "language": "go", - "src": "src/keys/generic/start", - "sym": "Keys" - }, - "expected_exit": 0, - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go" - }, - "lang": "go", - "nodes": [ - { - "text": "// snippet: def\nfunc Keys[K int, V any](m map[K]V) []K {\n\t// snippet: def\n\n\t// make a slice of the keys\n\tkeys := make([]K, 0, len(m))\n\n\t// iterate over the map\n\tfor k := range m {\n\n\t\t// add the key to the slice\n\t\tkeys = append(keys, k)\n\t}\n\n\t// return the keys\n\treturn keys\n}", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "-cmd", - "-u", - "-src", - "-short", - "Keys" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/10-generics/src/keys/generic/start", - "stdout": "Ly8gc25pcHBldDogZGVmCmZ1bmMgS2V5c1tLIGludCwgViBhbnldKG0gbWFwW0tdVikgW11LIHsKCS8vIHNuaXBwZXQ6IGRlZgoKCS8vIG1ha2UgYSBzbGljZSBvZiB0aGUga2V5cwoJa2V5cyA6PSBtYWtlKFtdSywgMCwgbGVuKG0pKQoKCS8vIGl0ZXJhdGUgb3ZlciB0aGUgbWFwCglmb3IgayA6PSByYW5nZSBtIHsKCgkJLy8gYWRkIHRoZSBrZXkgdG8gdGhlIHNsaWNlCgkJa2V5cyA9IGFwcGVuZChrZXlzLCBrKQoJfQoKCS8vIHJldHVybiB0aGUga2V5cwoJcmV0dXJuIGtleXMKfQ==", - "duration": 368186542, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go" - }, - "lang": "go", - "nodes": [ - { - "text": "// snippet: def\nfunc Keys[K int, V any](m map[K]V) []K {\n\t// snippet: def\n\n\t// make a slice of the keys\n\tkeys := make([]K, 0, len(m))\n\n\t// iterate over the map\n\tfor k := range m {\n\n\t\t// add the key to the slice\n\t\tkeys = append(keys, k)\n\t}\n\n\t// return the keys\n\treturn keys\n}", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "-cmd", - "-u", - "-src", - "-short", - "Keys" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/10-generics/src/keys/generic/start", - "stdout": "Ly8gc25pcHBldDogZGVmCmZ1bmMgS2V5c1tLIGludCwgViBhbnldKG0gbWFwW0tdVikgW11LIHsKCS8vIHNuaXBwZXQ6IGRlZgoKCS8vIG1ha2UgYSBzbGljZSBvZiB0aGUga2V5cwoJa2V5cyA6PSBtYWtlKFtdSywgMCwgbGVuKG0pKQoKCS8vIGl0ZXJhdGUgb3ZlciB0aGUgbWFwCglmb3IgayA6PSByYW5nZSBtIHsKCgkJLy8gYWRkIHRoZSBrZXkgdG8gdGhlIHNsaWNlCgkJa2V5cyA9IGFwcGVuZChrZXlzLCBrKQoJfQoKCS8vIHJldHVybiB0aGUga2V5cwoJcmV0dXJuIGtleXMKfQ==", - "duration": 368186542, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.9:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "nodes": [ - { - "text": "Keys", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function after generics.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 9, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "module.md", - "nodes": [ - { - "text": "With the changes in ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-9" - }, - "file": "module.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-9" - }, - "nodes": [ - { - "text": "Listing 1.9", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-9" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": " we can pass a map of key type ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "int", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " and a value type of ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "string", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " to the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "Keys", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function and it will return a slice of ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "int", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " values.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-10", - "type": "listing" - }, - "file": "module.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "src/keys/generic/start/keys_test.go#example" - }, - "lang": "go", - "nodes": [ - { - "content": "func Test_Keys(t *testing.T) {\n\tt.Parallel()\n\n\t// create a map with some values\n\tm := map[int]string{\n\t\t1: \"one\",\n\t\t2: \"two\",\n\t\t3: \"three\",\n\t}\n\n\t// get the keys\n\tact := Keys(m)\n\n\t// sort the returned keys for comparison\n\tsort.Slice(act, func(i, j int) bool {\n\t\treturn act[i] \u003c act[j]\n\t})\n\n\t// set the expected values\n\texp := []int{1, 2, 3}\n\n\t// assert the length of the actual and expected values\n\tif len(exp) != len(act) {\n\t\tt.Fatalf(\"expected len(%d), but got len(%d)\", len(exp), len(act))\n\t}\n\n\t// assert the types of the actual and expected values\n\tat := fmt.Sprintf(\"%T\", act)\n\tet := fmt.Sprintf(\"%T\", exp)\n\n\tif at != et {\n\t\tt.Fatalf(\"expected type %s, but got type %s\", et, at)\n\t}\n\n\t// loop through the expected values and\n\t// assert they are in the actual values\n\tfor i, v := range exp {\n\t\tif v != act[i] {\n\t\t\tt.Fatalf(\"expected %d, but got %d\", v, act[i])\n\t\t}\n\t}\n\n}", - "file": "src/keys/generic/start/keys_test.go", - "lang": "go", - "name": "example", - "start": 9, - "end": 54, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "atom": "hr", - "type": "*hype.Element" - }, - [ - { - "args": [ - "go", - "test", - "-v" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go test -v", - "src": "src/keys/generic/start", - "test": "-v" - }, - "expected_exit": 0, - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go test -v\n\n=== RUN Test_Keys\n=== PAUSE Test_Keys\n=== CONT Test_Keys\n--- PASS: Test_Keys (0.00s)\nPASS\nok \tdemo\t0.123s", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "test", - "-v" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/10-generics/src/keys/generic/start", - "stdout": "PT09IFJVTiAgIFRlc3RfS2V5cwo9PT0gUEFVU0UgVGVzdF9LZXlzCj09PSBDT05UICBUZXN0X0tleXMKLS0tIFBBU1M6IFRlc3RfS2V5cyAoMC4wMHMpClBBU1MKb2sgIAlkZW1vCTAuMTIzcw==", - "duration": 896718625, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go test -v\n\n=== RUN Test_Keys\n=== PAUSE Test_Keys\n=== CONT Test_Keys\n--- PASS: Test_Keys (0.00s)\nPASS\nok \tdemo\t0.123s", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "test", - "-v" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/10-generics/src/keys/generic/start", - "stdout": "PT09IFJVTiAgIFRlc3RfS2V5cwo9PT0gUEFVU0UgVGVzdF9LZXlzCj09PSBDT05UICBUZXN0X0tleXMKLS0tIFBBU1M6IFRlc3RfS2V5cyAoMC4wMHMpClBBU1MKb2sgIAlkZW1vCTAuMTIzcw==", - "duration": 896718625, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.10:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Tests now passing after using generics in ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-9" - }, - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-9" - }, - "nodes": [ - { - "text": "Listing 1.9", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-9" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 10, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "module.md", - "nodes": [ - { - "text": "As ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-10" - }, - "file": "module.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-10" - }, - "nodes": [ - { - "text": "Listing 1.10", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-10" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": " shows, This however, doesn't work if we want to use a map key of type ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "string", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " or ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "float64", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ". To do this we will need to specify a bigger set of constraints for the key type.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "module.md", - "level": 2, - "nodes": [ - { - "text": "Instantiating Generic Functions", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "module.md", - "nodes": [ - { - "text": "When calling a generic function, or creating a new value of a generic type, the Go compiler needs to know which types are being provided for the generic parameters. So far, we have been letting the Go compiler infer the types of the generic parameters based on the types of the values passed in. In ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-11" - }, - "file": "module.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-11" - }, - "nodes": [ - { - "text": "Listing 1.11", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-11" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", a variable, ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "fn", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ", is being declared and initialized with the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "Keys", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function from ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-9" - }, - "file": "module.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-9" - }, - "nodes": [ - { - "text": "Listing 1.9", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-9" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ". When the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "fn", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " variable is called, the compiler is unable to infer the types of the generic parameters. The result is a compilation error.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-11", - "type": "listing" - }, - "file": "module.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "src/instantiation/broken/keys_test.go#example" - }, - "lang": "go", - "nodes": [ - { - "content": "// create a function variable pointing\n// to the Keys function\nfn := Keys\n\n// get the keys\nact := fn(m)", - "file": "src/instantiation/broken/keys_test.go", - "lang": "go", - "name": "example", - "start": 19, - "end": 26, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "atom": "hr", - "type": "*hype.Element" - }, - [ - { - "args": [ - "go", - "test", - "-v" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go test -v", - "exit": "-1", - "src": "src/instantiation/broken", - "test": "-v" - }, - "expected_exit": -1, - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go test -v\n\nFAIL\tdemo [build failed]\n\n# demo [demo.test]\n./keys_test.go:22:8: cannot use generic function Keys without instantiation", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "test", - "-v" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/10-generics/src/instantiation/broken", - "err": { - "Stderr": null - }, - "exit": 1, - "stderr": "IyBkZW1vIFtkZW1vLnRlc3RdCi4va2V5c190ZXN0LmdvOjIyOjg6IGNhbm5vdCB1c2UgZ2VuZXJpYyBmdW5jdGlvbiBLZXlzIHdpdGhvdXQgaW5zdGFudGlhdGlvbg==", - "stdout": "RkFJTAlkZW1vIFtidWlsZCBmYWlsZWRd", - "duration": 1887015625, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go test -v\n\nFAIL\tdemo [build failed]\n\n# demo [demo.test]\n./keys_test.go:22:8: cannot use generic function Keys without instantiation", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "test", - "-v" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/10-generics/src/instantiation/broken", - "err": { - "Stderr": null - }, - "exit": 1, - "stderr": "IyBkZW1vIFtkZW1vLnRlc3RdCi4va2V5c190ZXN0LmdvOjIyOjg6IGNhbm5vdCB1c2UgZ2VuZXJpYyBmdW5jdGlvbiBLZXlzIHdpdGhvdXQgaW5zdGFudGlhdGlvbg==", - "stdout": "RkFJTAlkZW1vIFtidWlsZCBmYWlsZWRd", - "duration": 1887015625, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.11:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "nodes": [ - { - "text": "Keys", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function before instantiation.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 11, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "module.md", - "nodes": [ - { - "text": "In these situations we need to provide the compiler with the types of the generic parameters. In ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-12" - }, - "file": "module.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-12" - }, - "nodes": [ - { - "text": "Listing 1.12", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-12" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": " The types, ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "int", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " and ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "string", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ", are being provided when grabbing a reference to the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "Keys", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function for the variable ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "fn", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-12", - "type": "listing" - }, - "file": "module.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "src/instantiation/fixed/keys_test.go#example" - }, - "lang": "go", - "nodes": [ - { - "content": "// create a function variable pointing\n// to the Keys function\nfn := Keys[int, string]\n\n// get the keys\nact := fn(m)", - "file": "src/instantiation/fixed/keys_test.go", - "lang": "go", - "name": "example", - "start": 19, - "end": 26, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "atom": "hr", - "type": "*hype.Element" - }, - [ - { - "args": [ - "go", - "test", - "-v" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go test -v", - "src": "src/instantiation/fixed", - "test": "-v" - }, - "expected_exit": 0, - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go test -v\n\n=== RUN Test_Keys\n=== PAUSE Test_Keys\n=== CONT Test_Keys\n--- PASS: Test_Keys (0.00s)\nPASS\nok \tdemo\t0.490s", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "test", - "-v" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/10-generics/src/instantiation/fixed", - "stdout": "PT09IFJVTiAgIFRlc3RfS2V5cwo9PT0gUEFVU0UgVGVzdF9LZXlzCj09PSBDT05UICBUZXN0X0tleXMKLS0tIFBBU1M6IFRlc3RfS2V5cyAoMC4wMHMpClBBU1MKb2sgIAlkZW1vCTAuNDkwcw==", - "duration": 2048584750, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go test -v\n\n=== RUN Test_Keys\n=== PAUSE Test_Keys\n=== CONT Test_Keys\n--- PASS: Test_Keys (0.00s)\nPASS\nok \tdemo\t0.490s", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "test", - "-v" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/10-generics/src/instantiation/fixed", - "stdout": "PT09IFJVTiAgIFRlc3RfS2V5cwo9PT0gUEFVU0UgVGVzdF9LZXlzCj09PSBDT05UICBUZXN0X0tleXMKLS0tIFBBU1M6IFRlc3RfS2V5cyAoMC4wMHMpClBBU1MKb2sgIAlkZW1vCTAuNDkwcw==", - "duration": 2048584750, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.12:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "nodes": [ - { - "text": "Keys", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function after instantiation.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 12, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "module.md", - "level": 2, - "nodes": [ - { - "text": "Defining Constraints", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "module.md", - "nodes": [ - { - "text": "So far we have been using pretty simple types, such as ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "int", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " and ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "any", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " for the key and value types. But what if we wanted to use more types than just these? To specify which types can be used for a generic parameter, we can use constraints. Constraints are defined in a similar way to interfaces, but instead of specifying a set of methods, we specify a set of types.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "module.md", - "nodes": [ - { - "text": "As a start we can define a constraint, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-13" - }, - "file": "module.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-13" - }, - "nodes": [ - { - "text": "Listing 1.13", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-13" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": " that requires the type to be an ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "int", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-13", - "type": "listing" - }, - "file": "module.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "doc", - "-cmd", - "-u", - "-src", - "-short", - "MapKey" - ], - "atom": "cmd", - "attributes": { - "exec": "go doc -cmd -u -src -short MapKey", - "hide-cmd": "", - "language": "go", - "src": "src/constraints/defining", - "sym": "MapKey" - }, - "expected_exit": 0, - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go" - }, - "lang": "go", - "nodes": [ - { - "text": "// MapKey is a set of a constraints\n// on types that can be used as map keys.\ntype MapKey interface {\n\tint\n}", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "-cmd", - "-u", - "-src", - "-short", - "MapKey" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/10-generics/src/constraints/defining", - "stdout": "Ly8gTWFwS2V5IGlzIGEgc2V0IG9mIGEgY29uc3RyYWludHMKLy8gb24gdHlwZXMgdGhhdCBjYW4gYmUgdXNlZCBhcyBtYXAga2V5cy4KdHlwZSBNYXBLZXkgaW50ZXJmYWNlIHsKCWludAp9", - "duration": 363749250, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go" - }, - "lang": "go", - "nodes": [ - { - "text": "// MapKey is a set of a constraints\n// on types that can be used as map keys.\ntype MapKey interface {\n\tint\n}", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "-cmd", - "-u", - "-src", - "-short", - "MapKey" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/10-generics/src/constraints/defining", - "stdout": "Ly8gTWFwS2V5IGlzIGEgc2V0IG9mIGEgY29uc3RyYWludHMKLy8gb24gdHlwZXMgdGhhdCBjYW4gYmUgdXNlZCBhcyBtYXAga2V5cy4KdHlwZSBNYXBLZXkgaW50ZXJmYWNlIHsKCWludAp9", - "duration": 363749250, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.13:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "A constraint that requires the type to be an ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "nodes": [ - { - "text": "int", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 13, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "module.md", - "nodes": [ - { - "text": "With the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "MapKey", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " constraint defined in ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-13" - }, - "file": "module.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-13" - }, - "nodes": [ - { - "text": "Listing 1.13", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-13" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", we can update the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "Keys", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function to use it instead of ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "int", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " in ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-14" - }, - "file": "module.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-14" - }, - "nodes": [ - { - "text": "Listing 1.14", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-14" - } - ], - "type": "*hype.Ref" - } - ] - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-14", - "type": "listing" - }, - "file": "module.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "src/constraints/defining/keys.go#def" - }, - "lang": "go", - "nodes": [ - { - "content": "func Keys[K MapKey, V any](m map[K]V) []K {\n\n\t// make a slice of the keys\n\tkeys := make([]K, 0, len(m))\n\n\t// iterate over the map\n\tfor k := range m {\n\n\t\t// add the key to the slice\n\t\tkeys = append(keys, k)\n\t}\n\n\t// return the keys\n\treturn keys\n}", - "file": "src/constraints/defining/keys.go", - "lang": "go", - "name": "def", - "start": 9, - "end": 26, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.14:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "nodes": [ - { - "text": "Keys", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function using the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "nodes": [ - { - "text": "MapKey", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " constraint.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 14, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "module.md", - "level": 2, - "nodes": [ - { - "text": "Multiple Type Constraints", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "module.md", - "nodes": [ - { - "text": "Currently, the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "MapKey", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " constraint only allows an ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "int", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " to be used for the key. In ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-15" - }, - "file": "module.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-15" - }, - "nodes": [ - { - "text": "Listing 1.15", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-15" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": "we to try and use the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "Keys", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function with a map using a key type of ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "float64", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ". The result is a compilation error.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-15", - "type": "listing" - }, - "file": "module.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "src/constraints/floats/keys_test.go#example" - }, - "lang": "go", - "nodes": [ - { - "content": "// create a map with some values\nm := map[float64]string{\n\t1.1: \"one\",\n\t2.2: \"two\",\n\t3.3: \"three\",\n}\n\n// get the keys\nact := Keys(m)\n\n// sort the returned keys for comparison\nsort.Slice(act, func(i, j int) bool {\n\treturn act[i] \u003c act[j]\n})\n\n// set the expected values\nexp := []float64{1.1, 2.2, 3.3}\n\n// assert the length of the actual and expected values\nif len(exp) != len(act) {\n\tt.Fatalf(\"expected len(%d), but got len(%d)\", len(exp), len(act))\n}\n\n// assert the types of the actual and expected values\nat := fmt.Sprintf(\"%T\", act)\net := fmt.Sprintf(\"%T\", exp)\n\nif at != et {\n\tt.Fatalf(\"expected type %s, but got type %s\", et, at)\n}\n\n// loop through the expected values and\n// assert they are in the actual values\nfor i, v := range exp {\n\tif v != act[i] {\n\t\tt.Fatalf(\"expected %d, but got %d\", v, act[i])\n\t}\n}", - "file": "src/constraints/floats/keys_test.go", - "lang": "go", - "name": "example", - "start": 12, - "end": 51, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "atom": "hr", - "type": "*hype.Element" - }, - [ - { - "args": [ - "go", - "test", - "-v" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go test -v", - "exit": "-1", - "src": "src/constraints/floats", - "test": "-v" - }, - "expected_exit": -1, - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go test -v\n\nFAIL\tdemo [build failed]\n\n# demo [demo.test]\n./keys_test.go:21:13: K (type float64) does not satisfy MapKey", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "test", - "-v" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/10-generics/src/constraints/floats", - "err": { - "Stderr": null - }, - "exit": 1, - "stderr": "IyBkZW1vIFtkZW1vLnRlc3RdCi4va2V5c190ZXN0LmdvOjIxOjEzOiBLICh0eXBlIGZsb2F0NjQpIGRvZXMgbm90IHNhdGlzZnkgTWFwS2V5", - "stdout": "RkFJTAlkZW1vIFtidWlsZCBmYWlsZWRd", - "duration": 412549042, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go test -v\n\nFAIL\tdemo [build failed]\n\n# demo [demo.test]\n./keys_test.go:21:13: K (type float64) does not satisfy MapKey", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "test", - "-v" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/10-generics/src/constraints/floats", - "err": { - "Stderr": null - }, - "exit": 1, - "stderr": "IyBkZW1vIFtkZW1vLnRlc3RdCi4va2V5c190ZXN0LmdvOjIxOjEzOiBLICh0eXBlIGZsb2F0NjQpIGRvZXMgbm90IHNhdGlzZnkgTWFwS2V5", - "stdout": "RkFJTAlkZW1vIFtidWlsZCBmYWlsZWRd", - "duration": 412549042, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.15:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "nodes": [ - { - "text": "Keys", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function with a ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "nodes": [ - { - "text": "float64", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " key.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 15, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "module.md", - "nodes": [ - { - "text": "When defining constraints we can use the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "|", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " operator to create an intersection of constraints. For example, in ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-16" - }, - "file": "module.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-16" - }, - "nodes": [ - { - "text": "Listing 1.16", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-16" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": " we define a constraint that requires the key type to be either ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "int", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " or ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "float64", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-16", - "type": "listing" - }, - "file": "module.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "doc", - "-cmd", - "-u", - "-src", - "-short", - "MapKey" - ], - "atom": "cmd", - "attributes": { - "exec": "go doc -cmd -u -src -short MapKey", - "hide-cmd": "", - "language": "go", - "src": "src/constraints/or", - "sym": "MapKey" - }, - "expected_exit": 0, - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go" - }, - "lang": "go", - "nodes": [ - { - "text": "// MapKey is a set of a constraints\n// on types that can be used as map keys.\ntype MapKey interface {\n\tint | float64\n}", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "-cmd", - "-u", - "-src", - "-short", - "MapKey" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/10-generics/src/constraints/or", - "stdout": "Ly8gTWFwS2V5IGlzIGEgc2V0IG9mIGEgY29uc3RyYWludHMKLy8gb24gdHlwZXMgdGhhdCBjYW4gYmUgdXNlZCBhcyBtYXAga2V5cy4KdHlwZSBNYXBLZXkgaW50ZXJmYWNlIHsKCWludCB8IGZsb2F0NjQKfQ==", - "duration": 518426833, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go" - }, - "lang": "go", - "nodes": [ - { - "text": "// MapKey is a set of a constraints\n// on types that can be used as map keys.\ntype MapKey interface {\n\tint | float64\n}", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "-cmd", - "-u", - "-src", - "-short", - "MapKey" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/10-generics/src/constraints/or", - "stdout": "Ly8gTWFwS2V5IGlzIGEgc2V0IG9mIGEgY29uc3RyYWludHMKLy8gb24gdHlwZXMgdGhhdCBjYW4gYmUgdXNlZCBhcyBtYXAga2V5cy4KdHlwZSBNYXBLZXkgaW50ZXJmYWNlIHsKCWludCB8IGZsb2F0NjQKfQ==", - "duration": 518426833, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.16:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "A constraint that requires the key type to be either ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "nodes": [ - { - "text": "int", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " or ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "nodes": [ - { - "text": "float64", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 16, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "module.md", - "nodes": [ - { - "text": "With the change to the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "MapKey", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " constraint in ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-16" - }, - "file": "module.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-16" - }, - "nodes": [ - { - "text": "Listing 1.16", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-16" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", we can use the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "Keys", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function with a map using a key type of ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "float64", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ". The tests in ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-17" - }, - "file": "module.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-17" - }, - "nodes": [ - { - "text": "Listing 1.17", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-17" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": " now pass.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-17", - "type": "listing" - }, - "file": "module.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "test", - "-v" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go test -v", - "src": "src/constraints/or", - "test": "-v" - }, - "expected_exit": 0, - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go test -v\n\n=== RUN Test_Keys\n=== PAUSE Test_Keys\n=== CONT Test_Keys\n--- PASS: Test_Keys (0.00s)\nPASS\nok \tdemo\t0.343s", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "test", - "-v" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/10-generics/src/constraints/or", - "stdout": "PT09IFJVTiAgIFRlc3RfS2V5cwo9PT0gUEFVU0UgVGVzdF9LZXlzCj09PSBDT05UICBUZXN0X0tleXMKLS0tIFBBU1M6IFRlc3RfS2V5cyAoMC4wMHMpClBBU1MKb2sgIAlkZW1vCTAuMzQzcw==", - "duration": 1326058958, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go test -v\n\n=== RUN Test_Keys\n=== PAUSE Test_Keys\n=== CONT Test_Keys\n--- PASS: Test_Keys (0.00s)\nPASS\nok \tdemo\t0.343s", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "test", - "-v" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/10-generics/src/constraints/or", - "stdout": "PT09IFJVTiAgIFRlc3RfS2V5cwo9PT0gUEFVU0UgVGVzdF9LZXlzCj09PSBDT05UICBUZXN0X0tleXMKLS0tIFBBU1M6IFRlc3RfS2V5cyAoMC4wMHMpClBBU1MKb2sgIAlkZW1vCTAuMzQzcw==", - "duration": 1326058958, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.17:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Tests now passing with the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "nodes": [ - { - "text": "MapKey", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " constraint.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 17, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "module.md", - "level": 2, - "nodes": [ - { - "text": "Underlying Type Constraints", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "module.md", - "nodes": [ - { - "text": "In Go, we are allowed to create new types based on other types. For example, we can create a new type, ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "MyInt", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ", that is based on the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "int", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " type.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-18", - "type": "listing" - }, - "file": "module.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "doc", - "-cmd", - "-u", - "-src", - "-short", - "MyInt" - ], - "atom": "cmd", - "attributes": { - "exec": "go doc -cmd -u -src -short MyInt", - "hide-cmd": "", - "language": "go", - "src": "src/constraints/underlying/broken", - "sym": "MyInt" - }, - "expected_exit": 0, - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go" - }, - "lang": "go", - "nodes": [ - { - "text": "type MyInt int", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "-cmd", - "-u", - "-src", - "-short", - "MyInt" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/10-generics/src/constraints/underlying/broken", - "stdout": "dHlwZSBNeUludCBpbnQ=", - "duration": 505509500, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go" - }, - "lang": "go", - "nodes": [ - { - "text": "type MyInt int", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "-cmd", - "-u", - "-src", - "-short", - "MyInt" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/10-generics/src/constraints/underlying/broken", - "stdout": "dHlwZSBNeUludCBpbnQ=", - "duration": 505509500, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.18:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "A new type based on the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "nodes": [ - { - "text": "int", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " type.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 18, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "module.md", - "nodes": [ - { - "text": "However, when we try to use the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "Keys", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function with a map using a key type of ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "MyInt", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " we will get a compile error.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-19", - "type": "listing" - }, - "file": "module.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "src/constraints/underlying/broken/keys_test.go#example" - }, - "lang": "go", - "nodes": [ - { - "content": "func Test_Keys(t *testing.T) {\n\tt.Parallel()\n\n\t// create a map with some values\n\tm := map[MyInt]string{\n\t\t1: \"one\",\n\t\t2: \"two\",\n\t\t3: \"three\",\n\t}\n\n\t// get the keys\n\tact := Keys(m)\n\n\t// sort the returned keys for comparison\n\tsort.Slice(act, func(i, j int) bool {\n\t\treturn act[i] \u003c act[j]\n\t})\n\n\t// set the expected values\n\texp := []MyInt{1, 2, 3}\n\n\t// assert the length of the actual and expected values\n\tif len(exp) != len(act) {\n\t\tt.Fatalf(\"expected len(%d), but got len(%d)\", len(exp), len(act))\n\t}\n\n\t// assert the types of the actual and expected values\n\tat := fmt.Sprintf(\"%T\", act)\n\tet := fmt.Sprintf(\"%T\", exp)\n\n\tif at != et {\n\t\tt.Fatalf(\"expected type %s, but got type %s\", et, at)\n\t}\n\n\t// loop through the expected values and\n\t// assert they are in the actual values\n\tfor i, v := range exp {\n\t\tif v != act[i] {\n\t\t\tt.Fatalf(\"expected %d, but got %d\", v, act[i])\n\t\t}\n\t}\n\n}", - "file": "src/constraints/underlying/broken/keys_test.go", - "lang": "go", - "name": "example", - "start": 9, - "end": 54, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "atom": "hr", - "type": "*hype.Element" - }, - [ - { - "args": [ - "go", - "test", - "-v" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go test -v", - "exit": "-1", - "src": "src/constraints/underlying/broken", - "test": "-v" - }, - "expected_exit": -1, - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go test -v\n\nFAIL\tdemo [build failed]\n\n# demo [demo.test]\n./keys_test.go:21:13: MyInt does not satisfy MapKey (possibly missing ~ for int in MapKey)", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "test", - "-v" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/10-generics/src/constraints/underlying/broken", - "err": { - "Stderr": null - }, - "exit": 1, - "stderr": "IyBkZW1vIFtkZW1vLnRlc3RdCi4va2V5c190ZXN0LmdvOjIxOjEzOiBNeUludCBkb2VzIG5vdCBzYXRpc2Z5IE1hcEtleSAocG9zc2libHkgbWlzc2luZyB+IGZvciBpbnQgaW4gTWFwS2V5KQ==", - "stdout": "RkFJTAlkZW1vIFtidWlsZCBmYWlsZWRd", - "duration": 846257500, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go test -v\n\nFAIL\tdemo [build failed]\n\n# demo [demo.test]\n./keys_test.go:21:13: MyInt does not satisfy MapKey (possibly missing ~ for int in MapKey)", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "test", - "-v" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/10-generics/src/constraints/underlying/broken", - "err": { - "Stderr": null - }, - "exit": 1, - "stderr": "IyBkZW1vIFtkZW1vLnRlc3RdCi4va2V5c190ZXN0LmdvOjIxOjEzOiBNeUludCBkb2VzIG5vdCBzYXRpc2Z5IE1hcEtleSAocG9zc2libHkgbWlzc2luZyB+IGZvciBpbnQgaW4gTWFwS2V5KQ==", - "stdout": "RkFJTAlkZW1vIFtidWlsZCBmYWlsZWRd", - "duration": 846257500, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.19:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "nodes": [ - { - "text": "MyInt", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " type does not meet the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "nodes": [ - { - "text": "int", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " constraint.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 19, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "module.md", - "nodes": [ - { - "text": "The reason for the compilation in ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-19" - }, - "file": "module.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-19" - }, - "nodes": [ - { - "text": "Listing 1.19", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-19" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", is that the type ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "MyInt", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ", while based on ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "int", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ", does not satisfy the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "MapKey", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " constraint because it is ", - "type": "hype.Text" - }, - { - "atom": "strong", - "file": "module.md", - "nodes": [ - { - "text": "not", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " an ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "int", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " itself. When writing constraints we, usually, are interested in the underlying type, not the type that is wrapped by the type. To express this in when defining a constraint we can use the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "~", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " operator.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-20", - "type": "listing" - }, - "file": "module.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "doc", - "-cmd", - "-u", - "-src", - "-short", - "MapKey" - ], - "atom": "cmd", - "attributes": { - "exec": "go doc -cmd -u -src -short MapKey", - "hide-cmd": "", - "language": "go", - "src": "src/constraints/underlying/fixed", - "sym": "MapKey" - }, - "expected_exit": 0, - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go" - }, - "lang": "go", - "nodes": [ - { - "text": "// MapKey is a set of a constraints\n// on types that can be used as map keys.\ntype MapKey interface {\n\t~int\n}", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "-cmd", - "-u", - "-src", - "-short", - "MapKey" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/10-generics/src/constraints/underlying/fixed", - "stdout": "Ly8gTWFwS2V5IGlzIGEgc2V0IG9mIGEgY29uc3RyYWludHMKLy8gb24gdHlwZXMgdGhhdCBjYW4gYmUgdXNlZCBhcyBtYXAga2V5cy4KdHlwZSBNYXBLZXkgaW50ZXJmYWNlIHsKCX5pbnQKfQ==", - "duration": 581698583, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go" - }, - "lang": "go", - "nodes": [ - { - "text": "// MapKey is a set of a constraints\n// on types that can be used as map keys.\ntype MapKey interface {\n\t~int\n}", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "-cmd", - "-u", - "-src", - "-short", - "MapKey" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/10-generics/src/constraints/underlying/fixed", - "stdout": "Ly8gTWFwS2V5IGlzIGEgc2V0IG9mIGEgY29uc3RyYWludHMKLy8gb24gdHlwZXMgdGhhdCBjYW4gYmUgdXNlZCBhcyBtYXAga2V5cy4KdHlwZSBNYXBLZXkgaW50ZXJmYWNlIHsKCX5pbnQKfQ==", - "duration": 581698583, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.20:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Using the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "nodes": [ - { - "text": "~", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " operator to allow for super-types.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 20, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "module.md", - "nodes": [ - { - "text": "By updating the constraint to use the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "~", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " operator, the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "Keys", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function will accept any type based on ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "int", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ". Because ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "MyInt", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " is based on ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "int", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ", we can now use the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "Keys", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function with a map using a key type of ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "MyInt", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-21", - "type": "listing" - }, - "file": "module.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "test", - "-v" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go test -v", - "src": "src/constraints/underlying/fixed", - "test": "-v" - }, - "expected_exit": 0, - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go test -v\n\n=== RUN Test_Keys\n=== PAUSE Test_Keys\n=== CONT Test_Keys\n--- PASS: Test_Keys (0.00s)\nPASS\nok \tdemo\t0.276s", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "test", - "-v" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/10-generics/src/constraints/underlying/fixed", - "stdout": "PT09IFJVTiAgIFRlc3RfS2V5cwo9PT0gUEFVU0UgVGVzdF9LZXlzCj09PSBDT05UICBUZXN0X0tleXMKLS0tIFBBU1M6IFRlc3RfS2V5cyAoMC4wMHMpClBBU1MKb2sgIAlkZW1vCTAuMjc2cw==", - "duration": 1463195583, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go test -v\n\n=== RUN Test_Keys\n=== PAUSE Test_Keys\n=== CONT Test_Keys\n--- PASS: Test_Keys (0.00s)\nPASS\nok \tdemo\t0.276s", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "test", - "-v" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/10-generics/src/constraints/underlying/fixed", - "stdout": "PT09IFJVTiAgIFRlc3RfS2V5cwo9PT0gUEFVU0UgVGVzdF9LZXlzCj09PSBDT05UICBUZXN0X0tleXMKLS0tIFBBU1M6IFRlc3RfS2V5cyAoMC4wMHMpClBBU1MKb2sgIAlkZW1vCTAuMjc2cw==", - "duration": 1463195583, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.21:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Tests now passing with the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "nodes": [ - { - "text": "~", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " constraint operator.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 21, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "module.md", - "level": 2, - "nodes": [ - { - "text": "The Constraints Package", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "module.md", - "nodes": [ - { - "text": "When generics were released in Go 1.18, the Go team, decided to be cautious and not update the standard library immediately to use them. They wanted to see how generics were being used before deciding to update the standard library. As a result of this, the Go team have create a series of packages in the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "golang.org/x/exp", - "href": "https://pkg.go.dev/golang.org/x/exp", - "target": "_blank" - }, - "file": "module.md", - "nodes": [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "golang.org/x/exp", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/golang.org/x/exp" - } - ], - { - "text": " namespace to experiment with generics. One of these packages is the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "golang.org/x/exp/constraints", - "href": "https://pkg.go.dev/golang.org/x/exp/constraints", - "target": "_blank" - }, - "file": "module.md", - "nodes": [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "golang.org/x/exp/constraints", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/golang.org/x/exp/constraints" - } - ], - { - "text": " package, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-22" - }, - "file": "module.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-22" - }, - "nodes": [ - { - "text": "Listing 1.22", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-22" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ". The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "golang.org/x/exp/constraints", - "href": "https://pkg.go.dev/golang.org/x/exp/constraints", - "target": "_blank" - }, - "file": "module.md", - "nodes": [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "golang.org/x/exp/constraints", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/golang.org/x/exp/constraints" - } - ], - { - "text": " package defines a set of constraints for all of the numerical, and comparable types in the language.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-22", - "type": "listing" - }, - "file": "module.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "doc", - "golang.org/x/exp/constraints" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "doc": "golang.org/x/exp/constraints", - "exec": "go doc golang.org/x/exp/constraints", - "src": "src/constraints/pkg" - }, - "expected_exit": 0, - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc golang.org/x/exp/constraints\n\npackage constraints // import \u0026#34;golang.org/x/exp/constraints\u0026#34;\n\nPackage constraints defines a set of useful constraints to be used with type\nparameters.\n\ntype Complex interface{ ... }\ntype Float interface{ ... }\ntype Integer interface{ ... }\ntype Ordered interface{ ... }\ntype Signed interface{ ... }\ntype Unsigned interface{ ... }", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "golang.org/x/exp/constraints" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/10-generics/src/constraints/pkg", - "stdout": "cGFja2FnZSBjb25zdHJhaW50cyAvLyBpbXBvcnQgImdvbGFuZy5vcmcveC9leHAvY29uc3RyYWludHMiCgpQYWNrYWdlIGNvbnN0cmFpbnRzIGRlZmluZXMgYSBzZXQgb2YgdXNlZnVsIGNvbnN0cmFpbnRzIHRvIGJlIHVzZWQgd2l0aCB0eXBlCnBhcmFtZXRlcnMuCgp0eXBlIENvbXBsZXggaW50ZXJmYWNleyAuLi4gfQp0eXBlIEZsb2F0IGludGVyZmFjZXsgLi4uIH0KdHlwZSBJbnRlZ2VyIGludGVyZmFjZXsgLi4uIH0KdHlwZSBPcmRlcmVkIGludGVyZmFjZXsgLi4uIH0KdHlwZSBTaWduZWQgaW50ZXJmYWNleyAuLi4gfQp0eXBlIFVuc2lnbmVkIGludGVyZmFjZXsgLi4uIH0=", - "duration": 532235042, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc golang.org/x/exp/constraints\n\npackage constraints // import \u0026#34;golang.org/x/exp/constraints\u0026#34;\n\nPackage constraints defines a set of useful constraints to be used with type\nparameters.\n\ntype Complex interface{ ... }\ntype Float interface{ ... }\ntype Integer interface{ ... }\ntype Ordered interface{ ... }\ntype Signed interface{ ... }\ntype Unsigned interface{ ... }", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "golang.org/x/exp/constraints" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/10-generics/src/constraints/pkg", - "stdout": "cGFja2FnZSBjb25zdHJhaW50cyAvLyBpbXBvcnQgImdvbGFuZy5vcmcveC9leHAvY29uc3RyYWludHMiCgpQYWNrYWdlIGNvbnN0cmFpbnRzIGRlZmluZXMgYSBzZXQgb2YgdXNlZnVsIGNvbnN0cmFpbnRzIHRvIGJlIHVzZWQgd2l0aCB0eXBlCnBhcmFtZXRlcnMuCgp0eXBlIENvbXBsZXggaW50ZXJmYWNleyAuLi4gfQp0eXBlIEZsb2F0IGludGVyZmFjZXsgLi4uIH0KdHlwZSBJbnRlZ2VyIGludGVyZmFjZXsgLi4uIH0KdHlwZSBPcmRlcmVkIGludGVyZmFjZXsgLi4uIH0KdHlwZSBTaWduZWQgaW50ZXJmYWNleyAuLi4gfQp0eXBlIFVuc2lnbmVkIGludGVyZmFjZXsgLi4uIH0=", - "duration": 532235042, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.22:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "golang.org/x/exp/constraints", - "href": "https://pkg.go.dev/golang.org/x/exp/constraints", - "target": "_blank" - }, - "nodes": [ - [ - { - "atom": "code", - "nodes": [ - { - "text": "golang.org/x/exp/constraints", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/golang.org/x/exp/constraints" - } - ], - { - "text": " package.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 22, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "module.md", - "nodes": [ - { - "text": "For example, consider the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "golang.org/x/exp/constraints#Signed", - "href": "https://pkg.go.dev/golang.org/x/exp/constraints#Signed", - "target": "_blank" - }, - "file": "module.md", - "nodes": [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "constraints.Signed", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/golang.org/x/exp/constraints#Signed" - } - ], - { - "text": " constraint, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-23" - }, - "file": "module.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-23" - }, - "nodes": [ - { - "text": "Listing 1.23", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-23" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ". This constraint requires that the type be any of the signed integer types, ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "+/-", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " defined in the Go language, such ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "int", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " and ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "int64", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ", and any types based on those types.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-23", - "type": "listing" - }, - "file": "module.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "doc", - "golang.org/x/exp/constraints.Signed" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "doc": "golang.org/x/exp/constraints.Signed", - "exec": "go doc golang.org/x/exp/constraints.Signed", - "src": "src/constraints/pkg" - }, - "expected_exit": 0, - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc golang.org/x/exp/constraints.Signed\n\npackage constraints // import \u0026#34;golang.org/x/exp/constraints\u0026#34;\n\ntype Signed interface {\n\t~int | ~int8 | ~int16 | ~int32 | ~int64\n}\n Signed is a constraint that permits any signed integer type. If future\n releases of Go add new predeclared signed integer types, this constraint\n will be modified to include them.", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "golang.org/x/exp/constraints.Signed" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/10-generics/src/constraints/pkg", - "stdout": "cGFja2FnZSBjb25zdHJhaW50cyAvLyBpbXBvcnQgImdvbGFuZy5vcmcveC9leHAvY29uc3RyYWludHMiCgp0eXBlIFNpZ25lZCBpbnRlcmZhY2UgewoJfmludCB8IH5pbnQ4IHwgfmludDE2IHwgfmludDMyIHwgfmludDY0Cn0KICAgIFNpZ25lZCBpcyBhIGNvbnN0cmFpbnQgdGhhdCBwZXJtaXRzIGFueSBzaWduZWQgaW50ZWdlciB0eXBlLiBJZiBmdXR1cmUKICAgIHJlbGVhc2VzIG9mIEdvIGFkZCBuZXcgcHJlZGVjbGFyZWQgc2lnbmVkIGludGVnZXIgdHlwZXMsIHRoaXMgY29uc3RyYWludAogICAgd2lsbCBiZSBtb2RpZmllZCB0byBpbmNsdWRlIHRoZW0u", - "duration": 532097250, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc golang.org/x/exp/constraints.Signed\n\npackage constraints // import \u0026#34;golang.org/x/exp/constraints\u0026#34;\n\ntype Signed interface {\n\t~int | ~int8 | ~int16 | ~int32 | ~int64\n}\n Signed is a constraint that permits any signed integer type. If future\n releases of Go add new predeclared signed integer types, this constraint\n will be modified to include them.", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "golang.org/x/exp/constraints.Signed" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/10-generics/src/constraints/pkg", - "stdout": "cGFja2FnZSBjb25zdHJhaW50cyAvLyBpbXBvcnQgImdvbGFuZy5vcmcveC9leHAvY29uc3RyYWludHMiCgp0eXBlIFNpZ25lZCBpbnRlcmZhY2UgewoJfmludCB8IH5pbnQ4IHwgfmludDE2IHwgfmludDMyIHwgfmludDY0Cn0KICAgIFNpZ25lZCBpcyBhIGNvbnN0cmFpbnQgdGhhdCBwZXJtaXRzIGFueSBzaWduZWQgaW50ZWdlciB0eXBlLiBJZiBmdXR1cmUKICAgIHJlbGVhc2VzIG9mIEdvIGFkZCBuZXcgcHJlZGVjbGFyZWQgc2lnbmVkIGludGVnZXIgdHlwZXMsIHRoaXMgY29uc3RyYWludAogICAgd2lsbCBiZSBtb2RpZmllZCB0byBpbmNsdWRlIHRoZW0u", - "duration": 532097250, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.23:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "golang.org/x/exp/constraints#Signed", - "href": "https://pkg.go.dev/golang.org/x/exp/constraints#Signed", - "target": "_blank" - }, - "nodes": [ - [ - { - "atom": "code", - "nodes": [ - { - "text": "constraints.Signed", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/golang.org/x/exp/constraints#Signed" - } - ], - { - "text": " constraint.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 23, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "module.md", - "nodes": [ - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "golang.org/x/exp/constraints#Integer", - "href": "https://pkg.go.dev/golang.org/x/exp/constraints#Integer", - "target": "_blank" - }, - "file": "module.md", - "nodes": [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "constraints.Integer", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/golang.org/x/exp/constraints#Integer" - } - ], - { - "text": " constraint, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-24" - }, - "file": "module.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-24" - }, - "nodes": [ - { - "text": "Listing 1.24", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-24" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", requires the type to be based on ", - "type": "hype.Text" - }, - { - "atom": "strong", - "file": "module.md", - "nodes": [ - { - "text": "any", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " integer type, signed or unsigned, such as ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "int", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ", ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "int64", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ", ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "uint", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ", ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "uint64", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ", etc.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-24", - "type": "listing" - }, - "file": "module.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "doc", - "golang.org/x/exp/constraints.Integer" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "doc": "golang.org/x/exp/constraints.Integer", - "exec": "go doc golang.org/x/exp/constraints.Integer", - "src": "src/constraints/pkg" - }, - "expected_exit": 0, - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc golang.org/x/exp/constraints.Integer\n\npackage constraints // import \u0026#34;golang.org/x/exp/constraints\u0026#34;\n\ntype Integer interface {\n\tSigned | Unsigned\n}\n Integer is a constraint that permits any integer type. If future releases\n of Go add new predeclared integer types, this constraint will be modified to\n include them.", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "golang.org/x/exp/constraints.Integer" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/10-generics/src/constraints/pkg", - "stdout": "cGFja2FnZSBjb25zdHJhaW50cyAvLyBpbXBvcnQgImdvbGFuZy5vcmcveC9leHAvY29uc3RyYWludHMiCgp0eXBlIEludGVnZXIgaW50ZXJmYWNlIHsKCVNpZ25lZCB8IFVuc2lnbmVkCn0KICAgIEludGVnZXIgaXMgYSBjb25zdHJhaW50IHRoYXQgcGVybWl0cyBhbnkgaW50ZWdlciB0eXBlLiBJZiBmdXR1cmUgcmVsZWFzZXMKICAgIG9mIEdvIGFkZCBuZXcgcHJlZGVjbGFyZWQgaW50ZWdlciB0eXBlcywgdGhpcyBjb25zdHJhaW50IHdpbGwgYmUgbW9kaWZpZWQgdG8KICAgIGluY2x1ZGUgdGhlbS4=", - "duration": 477341875, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc golang.org/x/exp/constraints.Integer\n\npackage constraints // import \u0026#34;golang.org/x/exp/constraints\u0026#34;\n\ntype Integer interface {\n\tSigned | Unsigned\n}\n Integer is a constraint that permits any integer type. If future releases\n of Go add new predeclared integer types, this constraint will be modified to\n include them.", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "golang.org/x/exp/constraints.Integer" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/10-generics/src/constraints/pkg", - "stdout": "cGFja2FnZSBjb25zdHJhaW50cyAvLyBpbXBvcnQgImdvbGFuZy5vcmcveC9leHAvY29uc3RyYWludHMiCgp0eXBlIEludGVnZXIgaW50ZXJmYWNlIHsKCVNpZ25lZCB8IFVuc2lnbmVkCn0KICAgIEludGVnZXIgaXMgYSBjb25zdHJhaW50IHRoYXQgcGVybWl0cyBhbnkgaW50ZWdlciB0eXBlLiBJZiBmdXR1cmUgcmVsZWFzZXMKICAgIG9mIEdvIGFkZCBuZXcgcHJlZGVjbGFyZWQgaW50ZWdlciB0eXBlcywgdGhpcyBjb25zdHJhaW50IHdpbGwgYmUgbW9kaWZpZWQgdG8KICAgIGluY2x1ZGUgdGhlbS4=", - "duration": 477341875, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.24:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "golang.org/x/exp/constraints#Integer", - "href": "https://pkg.go.dev/golang.org/x/exp/constraints#Integer", - "target": "_blank" - }, - "nodes": [ - [ - { - "atom": "code", - "nodes": [ - { - "text": "constraints.Integer", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/golang.org/x/exp/constraints#Integer" - } - ], - { - "text": " constraint.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 24, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h3", - "file": "module.md", - "level": 3, - "nodes": [ - { - "text": "The Ordered Constraint", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "module.md", - "nodes": [ - { - "text": "One of the most useful constraints defined in the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "golang.org/x/exp/constraints", - "href": "https://pkg.go.dev/golang.org/x/exp/constraints", - "target": "_blank" - }, - "file": "module.md", - "nodes": [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "golang.org/x/exp/constraints", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/golang.org/x/exp/constraints" - } - ], - { - "text": " package is the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "golang.org/x/exp/constraints#Ordered", - "href": "https://pkg.go.dev/golang.org/x/exp/constraints#Ordered", - "target": "_blank" - }, - "file": "module.md", - "nodes": [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "constraints.Ordered", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/golang.org/x/exp/constraints#Ordered" - } - ], - { - "text": " constraint, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-25" - }, - "file": "module.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-25" - }, - "nodes": [ - { - "text": "Listing 1.25", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-25" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ". This constraint list all of the comparable types in the language, and any types based on those types. The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "golang.org/x/exp/constraints#Ordered", - "href": "https://pkg.go.dev/golang.org/x/exp/constraints#Ordered", - "target": "_blank" - }, - "file": "module.md", - "nodes": [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "constraints.Ordered", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/golang.org/x/exp/constraints#Ordered" - } - ], - { - "text": " constraint covers all numerical types and strings.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-25", - "type": "listing" - }, - "file": "module.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "doc", - "golang.org/x/exp/constraints.Ordered" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "doc": "golang.org/x/exp/constraints.Ordered", - "exec": "go doc golang.org/x/exp/constraints.Ordered", - "src": "src/constraints/pkg" - }, - "expected_exit": 0, - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc golang.org/x/exp/constraints.Ordered\n\npackage constraints // import \u0026#34;golang.org/x/exp/constraints\u0026#34;\n\ntype Ordered interface {\n\tInteger | Float | ~string\n}\n Ordered is a constraint that permits any ordered type: any type that\n supports the operators \u0026lt; \u0026lt;= \u0026gt;= \u0026gt;. If future releases of Go add new ordered\n types, this constraint will be modified to include them.", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "golang.org/x/exp/constraints.Ordered" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/10-generics/src/constraints/pkg", - "stdout": "cGFja2FnZSBjb25zdHJhaW50cyAvLyBpbXBvcnQgImdvbGFuZy5vcmcveC9leHAvY29uc3RyYWludHMiCgp0eXBlIE9yZGVyZWQgaW50ZXJmYWNlIHsKCUludGVnZXIgfCBGbG9hdCB8IH5zdHJpbmcKfQogICAgT3JkZXJlZCBpcyBhIGNvbnN0cmFpbnQgdGhhdCBwZXJtaXRzIGFueSBvcmRlcmVkIHR5cGU6IGFueSB0eXBlIHRoYXQKICAgIHN1cHBvcnRzIHRoZSBvcGVyYXRvcnMgPCA8PSA+PSA+LiBJZiBmdXR1cmUgcmVsZWFzZXMgb2YgR28gYWRkIG5ldyBvcmRlcmVkCiAgICB0eXBlcywgdGhpcyBjb25zdHJhaW50IHdpbGwgYmUgbW9kaWZpZWQgdG8gaW5jbHVkZSB0aGVtLg==", - "duration": 667545875, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go doc golang.org/x/exp/constraints.Ordered\n\npackage constraints // import \u0026#34;golang.org/x/exp/constraints\u0026#34;\n\ntype Ordered interface {\n\tInteger | Float | ~string\n}\n Ordered is a constraint that permits any ordered type: any type that\n supports the operators \u0026lt; \u0026lt;= \u0026gt;= \u0026gt;. If future releases of Go add new ordered\n types, this constraint will be modified to include them.", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "golang.org/x/exp/constraints.Ordered" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/10-generics/src/constraints/pkg", - "stdout": "cGFja2FnZSBjb25zdHJhaW50cyAvLyBpbXBvcnQgImdvbGFuZy5vcmcveC9leHAvY29uc3RyYWludHMiCgp0eXBlIE9yZGVyZWQgaW50ZXJmYWNlIHsKCUludGVnZXIgfCBGbG9hdCB8IH5zdHJpbmcKfQogICAgT3JkZXJlZCBpcyBhIGNvbnN0cmFpbnQgdGhhdCBwZXJtaXRzIGFueSBvcmRlcmVkIHR5cGU6IGFueSB0eXBlIHRoYXQKICAgIHN1cHBvcnRzIHRoZSBvcGVyYXRvcnMgPCA8PSA+PSA+LiBJZiBmdXR1cmUgcmVsZWFzZXMgb2YgR28gYWRkIG5ldyBvcmRlcmVkCiAgICB0eXBlcywgdGhpcyBjb25zdHJhaW50IHdpbGwgYmUgbW9kaWZpZWQgdG8gaW5jbHVkZSB0aGVtLg==", - "duration": 667545875, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.25:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "golang.org/x/exp/constraints#Ordered", - "href": "https://pkg.go.dev/golang.org/x/exp/constraints#Ordered", - "target": "_blank" - }, - "nodes": [ - [ - { - "atom": "code", - "nodes": [ - { - "text": "constraints.Ordered", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ] - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/golang.org/x/exp/constraints#Ordered" - } - ], - { - "text": " constraint.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 25, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "module.md", - "nodes": [ - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "golang.org/x/exp/constraints#Ordered", - "href": "https://pkg.go.dev/golang.org/x/exp/constraints#Ordered", - "target": "_blank" - }, - "file": "module.md", - "nodes": [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "constraints.Ordered", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/golang.org/x/exp/constraints#Ordered" - } - ], - { - "text": " constraint is perfect for map keys because all of the types defined in the constraint are comparable. In ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-26" - }, - "file": "module.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-26" - }, - "nodes": [ - { - "text": "Listing 1.26", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-26" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "Keys", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function has been updated to use the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "golang.org/x/exp/constraints#Ordered", - "href": "https://pkg.go.dev/golang.org/x/exp/constraints#Ordered", - "target": "_blank" - }, - "file": "module.md", - "nodes": [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "constraints.Ordered", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/golang.org/x/exp/constraints#Ordered" - } - ], - { - "text": " constraint. We can now use the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "Keys", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function with a map using a key type of ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "string", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ", or any other type that is comparable.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-26", - "type": "listing" - }, - "file": "module.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "doc", - "-cmd", - "-u", - "-src", - "-short", - "Keys" - ], - "atom": "cmd", - "attributes": { - "exec": "go doc -cmd -u -src -short Keys", - "hide-cmd": "", - "language": "go", - "src": "src/constraints/pkg", - "sym": "Keys" - }, - "expected_exit": 0, - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go" - }, - "lang": "go", - "nodes": [ - { - "text": "func Keys[K constraints.Ordered, V any](m map[K]V) []K {\n\n\t// make a slice of the keys\n\tkeys := make([]K, 0, len(m))\n\n\t// iterate over the map\n\tfor k := range m {\n\n\t\t// add the key to the slice\n\t\tkeys = append(keys, k)\n\t}\n\n\t// return the keys\n\treturn keys\n}", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "-cmd", - "-u", - "-src", - "-short", - "Keys" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/10-generics/src/constraints/pkg", - "stdout": "ZnVuYyBLZXlzW0sgY29uc3RyYWludHMuT3JkZXJlZCwgViBhbnldKG0gbWFwW0tdVikgW11LIHsKCgkvLyBtYWtlIGEgc2xpY2Ugb2YgdGhlIGtleXMKCWtleXMgOj0gbWFrZShbXUssIDAsIGxlbihtKSkKCgkvLyBpdGVyYXRlIG92ZXIgdGhlIG1hcAoJZm9yIGsgOj0gcmFuZ2UgbSB7CgoJCS8vIGFkZCB0aGUga2V5IHRvIHRoZSBzbGljZQoJCWtleXMgPSBhcHBlbmQoa2V5cywgaykKCX0KCgkvLyByZXR1cm4gdGhlIGtleXMKCXJldHVybiBrZXlzCn0=", - "duration": 113455250, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go" - }, - "lang": "go", - "nodes": [ - { - "text": "func Keys[K constraints.Ordered, V any](m map[K]V) []K {\n\n\t// make a slice of the keys\n\tkeys := make([]K, 0, len(m))\n\n\t// iterate over the map\n\tfor k := range m {\n\n\t\t// add the key to the slice\n\t\tkeys = append(keys, k)\n\t}\n\n\t// return the keys\n\treturn keys\n}", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "-cmd", - "-u", - "-src", - "-short", - "Keys" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/10-generics/src/constraints/pkg", - "stdout": "ZnVuYyBLZXlzW0sgY29uc3RyYWludHMuT3JkZXJlZCwgViBhbnldKG0gbWFwW0tdVikgW11LIHsKCgkvLyBtYWtlIGEgc2xpY2Ugb2YgdGhlIGtleXMKCWtleXMgOj0gbWFrZShbXUssIDAsIGxlbihtKSkKCgkvLyBpdGVyYXRlIG92ZXIgdGhlIG1hcAoJZm9yIGsgOj0gcmFuZ2UgbSB7CgoJCS8vIGFkZCB0aGUga2V5IHRvIHRoZSBzbGljZQoJCWtleXMgPSBhcHBlbmQoa2V5cywgaykKCX0KCgkvLyByZXR1cm4gdGhlIGtleXMKCXJldHVybiBrZXlzCn0=", - "duration": 113455250, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.26:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "nodes": [ - { - "text": "Keys", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function definition.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 26, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "module.md", - "level": 2, - "nodes": [ - { - "text": "Type Assertions", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "module.md", - "nodes": [ - { - "text": "When using constraints that are based on types, and not on methods like interfaces, type assertions are not allowed. For example, in ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-27" - }, - "file": "module.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-27" - }, - "nodes": [ - { - "text": "Listing 1.27", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-27" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "Keys", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " functions tries to print each map key out to the console, but only if it implements the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "fmt#Stringer", - "href": "https://pkg.go.dev/fmt#Stringer", - "target": "_blank" - }, - "file": "module.md", - "nodes": [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "fmt.Stringer", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/fmt#Stringer" - } - ], - { - "text": " interface.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-27", - "type": "listing" - }, - "file": "module.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "doc", - "-cmd", - "-u", - "-src", - "-short", - "Keys" - ], - "atom": "cmd", - "attributes": { - "exec": "go doc -cmd -u -src -short Keys", - "hide-cmd": "", - "language": "go", - "src": "src/assertions/broken", - "sym": "Keys" - }, - "expected_exit": 0, - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go" - }, - "lang": "go", - "nodes": [ - { - "text": "func Keys[K constraints.Ordered, V any](m map[K]V) []K {\n\n\t// make a slice of the keys\n\tkeys := make([]K, 0, len(m))\n\n\t// iterate over the map\n\tfor k := range m {\n\n\t\t// if k implements fmt.Stringer,\n\t\t// print the string representation\n\t\tif st, ok := k.(fmt.Stringer); ok {\n\t\t\tfmt.Println(st.String())\n\t\t}\n\n\t\t// add the key to the slice\n\t\tkeys = append(keys, k)\n\t}\n\n\t// return the keys\n\treturn keys\n}", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "-cmd", - "-u", - "-src", - "-short", - "Keys" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/10-generics/src/assertions/broken", - "stdout": "ZnVuYyBLZXlzW0sgY29uc3RyYWludHMuT3JkZXJlZCwgViBhbnldKG0gbWFwW0tdVikgW11LIHsKCgkvLyBtYWtlIGEgc2xpY2Ugb2YgdGhlIGtleXMKCWtleXMgOj0gbWFrZShbXUssIDAsIGxlbihtKSkKCgkvLyBpdGVyYXRlIG92ZXIgdGhlIG1hcAoJZm9yIGsgOj0gcmFuZ2UgbSB7CgoJCS8vIGlmIGsgaW1wbGVtZW50cyBmbXQuU3RyaW5nZXIsCgkJLy8gcHJpbnQgdGhlIHN0cmluZyByZXByZXNlbnRhdGlvbgoJCWlmIHN0LCBvayA6PSBrLihmbXQuU3RyaW5nZXIpOyBvayB7CgkJCWZtdC5QcmludGxuKHN0LlN0cmluZygpKQoJCX0KCgkJLy8gYWRkIHRoZSBrZXkgdG8gdGhlIHNsaWNlCgkJa2V5cyA9IGFwcGVuZChrZXlzLCBrKQoJfQoKCS8vIHJldHVybiB0aGUga2V5cwoJcmV0dXJuIGtleXMKfQ==", - "duration": 561685459, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go" - }, - "lang": "go", - "nodes": [ - { - "text": "func Keys[K constraints.Ordered, V any](m map[K]V) []K {\n\n\t// make a slice of the keys\n\tkeys := make([]K, 0, len(m))\n\n\t// iterate over the map\n\tfor k := range m {\n\n\t\t// if k implements fmt.Stringer,\n\t\t// print the string representation\n\t\tif st, ok := k.(fmt.Stringer); ok {\n\t\t\tfmt.Println(st.String())\n\t\t}\n\n\t\t// add the key to the slice\n\t\tkeys = append(keys, k)\n\t}\n\n\t// return the keys\n\treturn keys\n}", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "-cmd", - "-u", - "-src", - "-short", - "Keys" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/10-generics/src/assertions/broken", - "stdout": "ZnVuYyBLZXlzW0sgY29uc3RyYWludHMuT3JkZXJlZCwgViBhbnldKG0gbWFwW0tdVikgW11LIHsKCgkvLyBtYWtlIGEgc2xpY2Ugb2YgdGhlIGtleXMKCWtleXMgOj0gbWFrZShbXUssIDAsIGxlbihtKSkKCgkvLyBpdGVyYXRlIG92ZXIgdGhlIG1hcAoJZm9yIGsgOj0gcmFuZ2UgbSB7CgoJCS8vIGlmIGsgaW1wbGVtZW50cyBmbXQuU3RyaW5nZXIsCgkJLy8gcHJpbnQgdGhlIHN0cmluZyByZXByZXNlbnRhdGlvbgoJCWlmIHN0LCBvayA6PSBrLihmbXQuU3RyaW5nZXIpOyBvayB7CgkJCWZtdC5QcmludGxuKHN0LlN0cmluZygpKQoJCX0KCgkJLy8gYWRkIHRoZSBrZXkgdG8gdGhlIHNsaWNlCgkJa2V5cyA9IGFwcGVuZChrZXlzLCBrKQoJfQoKCS8vIHJldHVybiB0aGUga2V5cwoJcmV0dXJuIGtleXMKfQ==", - "duration": 561685459, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.27:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "nodes": [ - { - "text": "Keys", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function with type assertions.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 27, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "module.md", - "nodes": [ - { - "text": "With method based interfaces this is possible, but with constraints we can't make this sort of assertion, ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-28" - }, - "file": "module.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-28" - }, - "nodes": [ - { - "text": "Listing 1.28", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-28" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-28", - "type": "listing" - }, - "file": "module.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "test", - "-v" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go test -v", - "exit": "-1", - "src": "src/assertions/broken", - "test": "-v" - }, - "expected_exit": -1, - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go test -v\n\nFAIL\tdemo [build failed]\n\n# demo [demo.test]\n./keys.go:19:16: invalid operation: cannot use type assertion on type parameter value k (variable of type K constrained by constraints.Ordered)", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "test", - "-v" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/10-generics/src/assertions/broken", - "err": { - "Stderr": null - }, - "exit": 1, - "stderr": "IyBkZW1vIFtkZW1vLnRlc3RdCi4va2V5cy5nbzoxOToxNjogaW52YWxpZCBvcGVyYXRpb246IGNhbm5vdCB1c2UgdHlwZSBhc3NlcnRpb24gb24gdHlwZSBwYXJhbWV0ZXIgdmFsdWUgayAodmFyaWFibGUgb2YgdHlwZSBLIGNvbnN0cmFpbmVkIGJ5IGNvbnN0cmFpbnRzLk9yZGVyZWQp", - "stdout": "RkFJTAlkZW1vIFtidWlsZCBmYWlsZWRd", - "duration": 1774246458, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go test -v\n\nFAIL\tdemo [build failed]\n\n# demo [demo.test]\n./keys.go:19:16: invalid operation: cannot use type assertion on type parameter value k (variable of type K constrained by constraints.Ordered)", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "test", - "-v" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/10-generics/src/assertions/broken", - "err": { - "Stderr": null - }, - "exit": 1, - "stderr": "IyBkZW1vIFtkZW1vLnRlc3RdCi4va2V5cy5nbzoxOToxNjogaW52YWxpZCBvcGVyYXRpb246IGNhbm5vdCB1c2UgdHlwZSBhc3NlcnRpb24gb24gdHlwZSBwYXJhbWV0ZXIgdmFsdWUgayAodmFyaWFibGUgb2YgdHlwZSBLIGNvbnN0cmFpbmVkIGJ5IGNvbnN0cmFpbnRzLk9yZGVyZWQp", - "stdout": "RkFJTAlkZW1vIFtidWlsZCBmYWlsZWRd", - "duration": 1774246458, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.28:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Compilation error making assertions on a constraint.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 28, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "module.md", - "nodes": [ - { - "text": "As mentioned previously, at compile time, generic function calls are replaced with their concrete types instead. The result is a ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "Keys", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function that takes a map of ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "string", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " to ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "int", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " and returns a ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "[]string", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ", ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-29" - }, - "file": "module.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-29" - }, - "nodes": [ - { - "text": "Listing 1.29", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-29" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-29", - "type": "listing" - }, - "file": "module.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "doc", - "-cmd", - "-u", - "-src", - "-short", - "Keys" - ], - "atom": "cmd", - "attributes": { - "exec": "go doc -cmd -u -src -short Keys", - "hide-cmd": "", - "language": "go", - "src": "src/assertions/static", - "sym": "Keys" - }, - "expected_exit": 0, - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go" - }, - "lang": "go", - "nodes": [ - { - "text": "func Keys(m map[string]int) []string {\n\n\t// make a slice of the keys\n\tkeys := make([]string, 0, len(m))\n\n\t// iterate over the map\n\tfor k := range m {\n\n\t\t// if k implements fmt.Stringer,\n\t\t// print the string representation\n\t\tif st, ok := k.(fmt.Stringer); ok {\n\t\t\tfmt.Println(st.String())\n\t\t}\n\n\t\t// add the key to the slice\n\t\tkeys = append(keys, k)\n\t}\n\n\t// return the keys\n\treturn keys\n}", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "-cmd", - "-u", - "-src", - "-short", - "Keys" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/10-generics/src/assertions/static", - "stdout": "ZnVuYyBLZXlzKG0gbWFwW3N0cmluZ11pbnQpIFtdc3RyaW5nIHsKCgkvLyBtYWtlIGEgc2xpY2Ugb2YgdGhlIGtleXMKCWtleXMgOj0gbWFrZShbXXN0cmluZywgMCwgbGVuKG0pKQoKCS8vIGl0ZXJhdGUgb3ZlciB0aGUgbWFwCglmb3IgayA6PSByYW5nZSBtIHsKCgkJLy8gaWYgayBpbXBsZW1lbnRzIGZtdC5TdHJpbmdlciwKCQkvLyBwcmludCB0aGUgc3RyaW5nIHJlcHJlc2VudGF0aW9uCgkJaWYgc3QsIG9rIDo9IGsuKGZtdC5TdHJpbmdlcik7IG9rIHsKCQkJZm10LlByaW50bG4oc3QuU3RyaW5nKCkpCgkJfQoKCQkvLyBhZGQgdGhlIGtleSB0byB0aGUgc2xpY2UKCQlrZXlzID0gYXBwZW5kKGtleXMsIGspCgl9CgoJLy8gcmV0dXJuIHRoZSBrZXlzCglyZXR1cm4ga2V5cwp9", - "duration": 476740583, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go" - }, - "lang": "go", - "nodes": [ - { - "text": "func Keys(m map[string]int) []string {\n\n\t// make a slice of the keys\n\tkeys := make([]string, 0, len(m))\n\n\t// iterate over the map\n\tfor k := range m {\n\n\t\t// if k implements fmt.Stringer,\n\t\t// print the string representation\n\t\tif st, ok := k.(fmt.Stringer); ok {\n\t\t\tfmt.Println(st.String())\n\t\t}\n\n\t\t// add the key to the slice\n\t\tkeys = append(keys, k)\n\t}\n\n\t// return the keys\n\treturn keys\n}", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "-cmd", - "-u", - "-src", - "-short", - "Keys" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/10-generics/src/assertions/static", - "stdout": "ZnVuYyBLZXlzKG0gbWFwW3N0cmluZ11pbnQpIFtdc3RyaW5nIHsKCgkvLyBtYWtlIGEgc2xpY2Ugb2YgdGhlIGtleXMKCWtleXMgOj0gbWFrZShbXXN0cmluZywgMCwgbGVuKG0pKQoKCS8vIGl0ZXJhdGUgb3ZlciB0aGUgbWFwCglmb3IgayA6PSByYW5nZSBtIHsKCgkJLy8gaWYgayBpbXBsZW1lbnRzIGZtdC5TdHJpbmdlciwKCQkvLyBwcmludCB0aGUgc3RyaW5nIHJlcHJlc2VudGF0aW9uCgkJaWYgc3QsIG9rIDo9IGsuKGZtdC5TdHJpbmdlcik7IG9rIHsKCQkJZm10LlByaW50bG4oc3QuU3RyaW5nKCkpCgkJfQoKCQkvLyBhZGQgdGhlIGtleSB0byB0aGUgc2xpY2UKCQlrZXlzID0gYXBwZW5kKGtleXMsIGspCgl9CgoJLy8gcmV0dXJuIHRoZSBrZXlzCglyZXR1cm4ga2V5cwp9", - "duration": 476740583, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.29:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The compiled output of a generic function.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 29, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "module.md", - "nodes": [ - { - "text": "When looking at the compilation error for \"concrete\" representation of the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "Keys", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " function the error is a little more clear.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-30", - "type": "listing" - }, - "file": "module.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "test", - "-v" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go test -v", - "exit": "-1", - "src": "src/assertions/static", - "test": "-v" - }, - "expected_exit": -1, - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go test -v\n\nFAIL\tdemo [build failed]\n\n# demo [demo.test]\n./keys.go:17:16: invalid operation: k (variable of type string) is not an interface", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "test", - "-v" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/10-generics/src/assertions/static", - "err": { - "Stderr": null - }, - "exit": 1, - "stderr": "IyBkZW1vIFtkZW1vLnRlc3RdCi4va2V5cy5nbzoxNzoxNjogaW52YWxpZCBvcGVyYXRpb246IGsgKHZhcmlhYmxlIG9mIHR5cGUgc3RyaW5nKSBpcyBub3QgYW4gaW50ZXJmYWNl", - "stdout": "RkFJTAlkZW1vIFtidWlsZCBmYWlsZWRd", - "duration": 1742717708, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go test -v\n\nFAIL\tdemo [build failed]\n\n# demo [demo.test]\n./keys.go:17:16: invalid operation: k (variable of type string) is not an interface", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "test", - "-v" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/10-generics/src/assertions/static", - "err": { - "Stderr": null - }, - "exit": 1, - "stderr": "IyBkZW1vIFtkZW1vLnRlc3RdCi4va2V5cy5nbzoxNzoxNjogaW52YWxpZCBvcGVyYXRpb246IGsgKHZhcmlhYmxlIG9mIHR5cGUgc3RyaW5nKSBpcyBub3QgYW4gaW50ZXJmYWNl", - "stdout": "RkFJTAlkZW1vIFtidWlsZCBmYWlsZWRd", - "duration": 1742717708, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.30:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Compilation error type asserting on a concrete type.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 30, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "module.md", - "nodes": [ - { - "text": "In Go type assertions, such as those in ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-29" - }, - "file": "module.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-29" - }, - "nodes": [ - { - "text": "Listing 1.29", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-29" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", against concrete types is not allowed. This is no reason to assert if ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "string", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " or ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "User", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " or another types implements the interface, because the compiler already if it can be done.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "module.md", - "level": 2, - "nodes": [ - { - "text": "Mixing Method and Type Constraints", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "module.md", - "nodes": [ - { - "text": "When defining constraints we have to choose between type based constraints and method based constraints. For example, in ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-31" - }, - "file": "module.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-31" - }, - "nodes": [ - { - "text": "Listing 1.31", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-31" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", we can can't define a constraint that is either ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "golang.org/x/exp/constraints#Ordered", - "href": "https://pkg.go.dev/golang.org/x/exp/constraints#Ordered", - "target": "_blank" - }, - "file": "module.md", - "nodes": [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "constraints.Ordered", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/golang.org/x/exp/constraints#Ordered" - } - ], - { - "text": " or ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "fmt#Stringer", - "href": "https://pkg.go.dev/fmt#Stringer", - "target": "_blank" - }, - "file": "module.md", - "nodes": [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "fmt.Stringer", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/fmt#Stringer" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-31", - "type": "listing" - }, - "file": "module.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "doc", - "-cmd", - "-u", - "-src", - "-short", - "MapKey" - ], - "atom": "cmd", - "attributes": { - "exec": "go doc -cmd -u -src -short MapKey", - "hide-cmd": "", - "language": "go", - "src": "src/assertions/mixed", - "sym": "MapKey" - }, - "expected_exit": 0, - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go" - }, - "lang": "go", - "nodes": [ - { - "text": "type MapKey interface {\n\tconstraints.Ordered | fmt.Stringer\n}", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "-cmd", - "-u", - "-src", - "-short", - "MapKey" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/10-generics/src/assertions/mixed", - "stdout": "dHlwZSBNYXBLZXkgaW50ZXJmYWNlIHsKCWNvbnN0cmFpbnRzLk9yZGVyZWQgfCBmbXQuU3RyaW5nZXIKfQ==", - "duration": 255071541, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go" - }, - "lang": "go", - "nodes": [ - { - "text": "type MapKey interface {\n\tconstraints.Ordered | fmt.Stringer\n}", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "-cmd", - "-u", - "-src", - "-short", - "MapKey" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/10-generics/src/assertions/mixed", - "stdout": "dHlwZSBNYXBLZXkgaW50ZXJmYWNlIHsKCWNvbnN0cmFpbnRzLk9yZGVyZWQgfCBmbXQuU3RyaW5nZXIKfQ==", - "duration": 255071541, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "doc", - "-cmd", - "-u", - "-src", - "-short", - "Keys" - ], - "atom": "cmd", - "attributes": { - "exec": "go doc -cmd -u -src -short Keys", - "hide-cmd": "", - "language": "go", - "src": "src/assertions/mixed", - "sym": "Keys" - }, - "expected_exit": 0, - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go" - }, - "lang": "go", - "nodes": [ - { - "text": "func Keys[K MapKey, V any](m map[K]V) []K {\n\n\t// make a slice of the keys\n\tkeys := make([]K, 0, len(m))\n\n\t// iterate over the map\n\tfor k := range m {\n\n\t\t// add the key to the slice\n\t\tkeys = append(keys, k)\n\t}\n\n\t// return the keys\n\treturn keys\n}", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "-cmd", - "-u", - "-src", - "-short", - "Keys" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/10-generics/src/assertions/mixed", - "stdout": "ZnVuYyBLZXlzW0sgTWFwS2V5LCBWIGFueV0obSBtYXBbS11WKSBbXUsgewoKCS8vIG1ha2UgYSBzbGljZSBvZiB0aGUga2V5cwoJa2V5cyA6PSBtYWtlKFtdSywgMCwgbGVuKG0pKQoKCS8vIGl0ZXJhdGUgb3ZlciB0aGUgbWFwCglmb3IgayA6PSByYW5nZSBtIHsKCgkJLy8gYWRkIHRoZSBrZXkgdG8gdGhlIHNsaWNlCgkJa2V5cyA9IGFwcGVuZChrZXlzLCBrKQoJfQoKCS8vIHJldHVybiB0aGUga2V5cwoJcmV0dXJuIGtleXMKfQ==", - "duration": 303404125, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go" - }, - "lang": "go", - "nodes": [ - { - "text": "func Keys[K MapKey, V any](m map[K]V) []K {\n\n\t// make a slice of the keys\n\tkeys := make([]K, 0, len(m))\n\n\t// iterate over the map\n\tfor k := range m {\n\n\t\t// add the key to the slice\n\t\tkeys = append(keys, k)\n\t}\n\n\t// return the keys\n\treturn keys\n}", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "-cmd", - "-u", - "-src", - "-short", - "Keys" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/10-generics/src/assertions/mixed", - "stdout": "ZnVuYyBLZXlzW0sgTWFwS2V5LCBWIGFueV0obSBtYXBbS11WKSBbXUsgewoKCS8vIG1ha2UgYSBzbGljZSBvZiB0aGUga2V5cwoJa2V5cyA6PSBtYWtlKFtdSywgMCwgbGVuKG0pKQoKCS8vIGl0ZXJhdGUgb3ZlciB0aGUgbWFwCglmb3IgayA6PSByYW5nZSBtIHsKCgkJLy8gYWRkIHRoZSBrZXkgdG8gdGhlIHNsaWNlCgkJa2V5cyA9IGFwcGVuZChrZXlzLCBrKQoJfQoKCS8vIHJldHVybiB0aGUga2V5cwoJcmV0dXJuIGtleXMKfQ==", - "duration": 303404125, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "test", - "-v" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go test -v", - "exit": "-1", - "src": "src/assertions/mixed", - "test": "-v" - }, - "expected_exit": -1, - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go test -v\n\nFAIL\tdemo [build failed]\n\n# demo [demo.test]\n./keys.go:10:24: cannot use fmt.Stringer in union (fmt.Stringer contains methods)\n./keys.go:13:34: invalid map key type K (missing comparable constraint)", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "test", - "-v" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/10-generics/src/assertions/mixed", - "err": { - "Stderr": null - }, - "exit": 1, - "stderr": "IyBkZW1vIFtkZW1vLnRlc3RdCi4va2V5cy5nbzoxMDoyNDogY2Fubm90IHVzZSBmbXQuU3RyaW5nZXIgaW4gdW5pb24gKGZtdC5TdHJpbmdlciBjb250YWlucyBtZXRob2RzKQouL2tleXMuZ286MTM6MzQ6IGludmFsaWQgbWFwIGtleSB0eXBlIEsgKG1pc3NpbmcgY29tcGFyYWJsZSBjb25zdHJhaW50KQ==", - "stdout": "RkFJTAlkZW1vIFtidWlsZCBmYWlsZWRd", - "duration": 898703125, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go test -v\n\nFAIL\tdemo [build failed]\n\n# demo [demo.test]\n./keys.go:10:24: cannot use fmt.Stringer in union (fmt.Stringer contains methods)\n./keys.go:13:34: invalid map key type K (missing comparable constraint)", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "test", - "-v" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/10-generics/src/assertions/mixed", - "err": { - "Stderr": null - }, - "exit": 1, - "stderr": "IyBkZW1vIFtkZW1vLnRlc3RdCi4va2V5cy5nbzoxMDoyNDogY2Fubm90IHVzZSBmbXQuU3RyaW5nZXIgaW4gdW5pb24gKGZtdC5TdHJpbmdlciBjb250YWlucyBtZXRob2RzKQouL2tleXMuZ286MTM6MzQ6IGludmFsaWQgbWFwIGtleSB0eXBlIEsgKG1pc3NpbmcgY29tcGFyYWJsZSBjb25zdHJhaW50KQ==", - "stdout": "RkFJTAlkZW1vIFtidWlsZCBmYWlsZWRd", - "duration": 898703125, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.31:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Compilation error mixing method and type constraints.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 31, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "h2", - "file": "module.md", - "level": 2, - "nodes": [ - { - "text": "Generic Types", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "module.md", - "nodes": [ - { - "text": "In addition to functions, types can also be generic. If we consider building a data store we might define a generic type to represent a \"model\". In ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-32" - }, - "file": "module.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-32" - }, - "nodes": [ - { - "text": "Listing 1.32", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-32" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": " we define a ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "Model", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " interface that defines a constraint that all implementations of the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "Model", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " interface must satisfy. The ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "Model", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " interface has a type constraint, ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "[T constraints.Ordered]", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ". This constraint is now available for use on the interface's methods.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-32", - "type": "listing" - }, - "file": "module.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "doc", - "-cmd", - "-u", - "-src", - "-short", - "Model" - ], - "atom": "cmd", - "attributes": { - "exec": "go doc -cmd -u -src -short Model", - "hide-cmd": "", - "language": "go", - "src": "src/store", - "sym": "Model" - }, - "expected_exit": 0, - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go" - }, - "lang": "go", - "nodes": [ - { - "text": "type Model[T constraints.Ordered] interface {\n\tID() T\n}", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "-cmd", - "-u", - "-src", - "-short", - "Model" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/10-generics/src/store", - "stdout": "dHlwZSBNb2RlbFtUIGNvbnN0cmFpbnRzLk9yZGVyZWRdIGludGVyZmFjZSB7CglJRCgpIFQKfQ==", - "duration": 614406000, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go" - }, - "lang": "go", - "nodes": [ - { - "text": "type Model[T constraints.Ordered] interface {\n\tID() T\n}", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "-cmd", - "-u", - "-src", - "-short", - "Model" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/10-generics/src/store", - "stdout": "dHlwZSBNb2RlbFtUIGNvbnN0cmFpbnRzLk9yZGVyZWRdIGludGVyZmFjZSB7CglJRCgpIFQKfQ==", - "duration": 614406000, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.32:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "nodes": [ - { - "text": "Model", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " interface with generics.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 32, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "module.md", - "nodes": [ - { - "text": "Now, in order to implement the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "Model", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " interface, in ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-32" - }, - "file": "module.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-32" - }, - "nodes": [ - { - "text": "Listing 1.32", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-32" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", a type needs a ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "ID()", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " method that returns a type listed in the ", - "type": "hype.Text" - }, - [ - { - "atom": "a", - "attributes": { - "for": "golang.org/x/exp/constraints#Ordered", - "href": "https://pkg.go.dev/golang.org/x/exp/constraints#Ordered", - "target": "_blank" - }, - "file": "module.md", - "nodes": [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "constraints.Ordered", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - "type": "*hype.Link", - "url": "https://pkg.go.dev/golang.org/x/exp/constraints#Ordered" - } - ], - { - "text": " constraint.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-33", - "type": "listing" - }, - "file": "module.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "doc", - "-cmd", - "-u", - "-src", - "-short", - "User" - ], - "atom": "cmd", - "attributes": { - "exec": "go doc -cmd -u -src -short User", - "hide-cmd": "", - "language": "go", - "src": "src/store", - "sym": "User" - }, - "expected_exit": 0, - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go" - }, - "lang": "go", - "nodes": [ - { - "text": "type User struct {\n\tEmail string\n}\n\nfunc (u User) ID() string", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "-cmd", - "-u", - "-src", - "-short", - "User" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/10-generics/src/store", - "stdout": "dHlwZSBVc2VyIHN0cnVjdCB7CglFbWFpbCBzdHJpbmcKfQoKZnVuYyAodSBVc2VyKSBJRCgpIHN0cmluZw==", - "duration": 614824625, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go" - }, - "lang": "go", - "nodes": [ - { - "text": "type User struct {\n\tEmail string\n}\n\nfunc (u User) ID() string", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "-cmd", - "-u", - "-src", - "-short", - "User" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/10-generics/src/store", - "stdout": "dHlwZSBVc2VyIHN0cnVjdCB7CglFbWFpbCBzdHJpbmcKfQoKZnVuYyAodSBVc2VyKSBJRCgpIHN0cmluZw==", - "duration": 614824625, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.33:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "A ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "nodes": [ - { - "text": "User", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " type that implements ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-32" - }, - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-32" - }, - "nodes": [ - { - "text": "Listing 1.32", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-32" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 33, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "module.md", - "nodes": [ - { - "text": "In ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-34" - }, - "file": "module.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-34" - }, - "nodes": [ - { - "text": "Listing 1.34", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-34" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": " we define a ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "Store", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " struct type that has two type constraints, ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "[K constraints.Ordered]", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " and ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "[M Model[K]]", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ". In this example we are using the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "K", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " constraint defined on the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "Store", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " type to define the constraint on the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "Model", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " type.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-34", - "type": "listing" - }, - "file": "module.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "doc", - "-cmd", - "-u", - "-src", - "-short", - "Store" - ], - "atom": "cmd", - "attributes": { - "exec": "go doc -cmd -u -src -short Store", - "hide-cmd": "", - "language": "go", - "src": "src/store", - "sym": "Store" - }, - "expected_exit": 0, - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go" - }, - "lang": "go", - "nodes": [ - { - "text": "// Store is a map of models where the map key is any\n// comparable type and the map value is any type that\n// implements the Model constraint.\ntype Store[K constraints.Ordered, M Model[K]] struct {\n\tdata map[K]M\n}\n\nfunc (s Store[K, M]) Find(id K) (M, error)\nfunc (s *Store[K, M]) Insert(m M) error", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "-cmd", - "-u", - "-src", - "-short", - "Store" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/10-generics/src/store", - "stdout": "Ly8gU3RvcmUgaXMgYSBtYXAgb2YgbW9kZWxzIHdoZXJlIHRoZSBtYXAga2V5IGlzIGFueQovLyBjb21wYXJhYmxlIHR5cGUgYW5kIHRoZSBtYXAgdmFsdWUgaXMgYW55IHR5cGUgdGhhdAovLyBpbXBsZW1lbnRzIHRoZSBNb2RlbCBjb25zdHJhaW50Lgp0eXBlIFN0b3JlW0sgY29uc3RyYWludHMuT3JkZXJlZCwgTSBNb2RlbFtLXV0gc3RydWN0IHsKCWRhdGEgbWFwW0tdTQp9CgpmdW5jIChzIFN0b3JlW0ssIE1dKSBGaW5kKGlkIEspIChNLCBlcnJvcikKZnVuYyAocyAqU3RvcmVbSywgTV0pIEluc2VydChtIE0pIGVycm9y", - "duration": 104121667, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go" - }, - "lang": "go", - "nodes": [ - { - "text": "// Store is a map of models where the map key is any\n// comparable type and the map value is any type that\n// implements the Model constraint.\ntype Store[K constraints.Ordered, M Model[K]] struct {\n\tdata map[K]M\n}\n\nfunc (s Store[K, M]) Find(id K) (M, error)\nfunc (s *Store[K, M]) Insert(m M) error", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "-cmd", - "-u", - "-src", - "-short", - "Store" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/10-generics/src/store", - "stdout": "Ly8gU3RvcmUgaXMgYSBtYXAgb2YgbW9kZWxzIHdoZXJlIHRoZSBtYXAga2V5IGlzIGFueQovLyBjb21wYXJhYmxlIHR5cGUgYW5kIHRoZSBtYXAgdmFsdWUgaXMgYW55IHR5cGUgdGhhdAovLyBpbXBsZW1lbnRzIHRoZSBNb2RlbCBjb25zdHJhaW50Lgp0eXBlIFN0b3JlW0sgY29uc3RyYWludHMuT3JkZXJlZCwgTSBNb2RlbFtLXV0gc3RydWN0IHsKCWRhdGEgbWFwW0tdTQp9CgpmdW5jIChzIFN0b3JlW0ssIE1dKSBGaW5kKGlkIEspIChNLCBlcnJvcikKZnVuYyAocyAqU3RvcmVbSywgTV0pIEluc2VydChtIE0pIGVycm9y", - "duration": 104121667, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.34:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "nodes": [ - { - "text": "Store", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " type with generics.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 34, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "module.md", - "nodes": [ - { - "text": "When defining methods on types that use generics, the receiver of the method needs to be instantiated with the appropriate concrete type or types. Consider the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "Find", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " method on the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "Store", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " type in ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-35" - }, - "file": "module.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-35" - }, - "nodes": [ - { - "text": "Listing 1.35", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-35" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ".", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-35", - "type": "listing" - }, - "file": "module.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "args": [ - "go", - "doc", - "-cmd", - "-u", - "-src", - "-short", - "Store.Find" - ], - "atom": "cmd", - "attributes": { - "exec": "go doc -cmd -u -src -short Store.Find", - "hide-cmd": "", - "language": "go", - "src": "src/store", - "sym": "Store.Find" - }, - "expected_exit": 0, - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go" - }, - "lang": "go", - "nodes": [ - { - "text": "func (s Store[K, M]) Find(id K) (M, error) {\n\tm, ok := s.data[id]\n\tif !ok {\n\t\treturn m, fmt.Errorf(\u0026#34;key not found %v\u0026#34;, id)\n\t}\n\n\treturn m, nil\n}", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "-cmd", - "-u", - "-src", - "-short", - "Store.Find" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/10-generics/src/store", - "stdout": "ZnVuYyAocyBTdG9yZVtLLCBNXSkgRmluZChpZCBLKSAoTSwgZXJyb3IpIHsKCW0sIG9rIDo9IHMuZGF0YVtpZF0KCWlmICFvayB7CgkJcmV0dXJuIG0sIGZtdC5FcnJvcmYoImtleSBub3QgZm91bmQgJXYiLCBpZCkKCX0KCglyZXR1cm4gbSwgbmlsCn0=", - "duration": 410640292, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go" - }, - "lang": "go", - "nodes": [ - { - "text": "func (s Store[K, M]) Find(id K) (M, error) {\n\tm, ok := s.data[id]\n\tif !ok {\n\t\treturn m, fmt.Errorf(\u0026#34;key not found %v\u0026#34;, id)\n\t}\n\n\treturn m, nil\n}", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "doc", - "-cmd", - "-u", - "-src", - "-short", - "Store.Find" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/10-generics/src/store", - "stdout": "ZnVuYyAocyBTdG9yZVtLLCBNXSkgRmluZChpZCBLKSAoTSwgZXJyb3IpIHsKCW0sIG9rIDo9IHMuZGF0YVtpZF0KCWlmICFvayB7CgkJcmV0dXJuIG0sIGZtdC5FcnJvcmYoImtleSBub3QgZm91bmQgJXYiLCBpZCkKCX0KCglyZXR1cm4gbSwgbmlsCn0=", - "duration": 410640292, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.35:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "The ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "nodes": [ - { - "text": "Find", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " method on the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "nodes": [ - { - "text": "Store", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " type.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 35, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "module.md", - "nodes": [ - { - "text": "The receiver, ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "(s Store[K, M])", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ", is instantiated with the concrete types that the ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "Store", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " type was instantiated with. Those types can also be used to define arguments and return values for these methods. In ", - "type": "hype.Text" - }, - [ - { - "atom": "ref", - "attributes": { - "id": "listing-1-36" - }, - "file": "module.md", - "nodes": [ - { - "atom": "a", - "attributes": { - "href": "#listing-1-36" - }, - "nodes": [ - { - "text": "Listing 1.36", - "type": "hype.Text" - } - ], - "type": "*hype.Link", - "url": "#listing-1-36" - } - ], - "type": "*hype.Ref" - } - ], - { - "text": ", we initialize a new ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "Store", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " type with the constraints of ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "string", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": " and ", - "type": "hype.Text" - }, - [ - { - "atom": "code", - "file": "module.md", - "nodes": [ - { - "text": "User", - "type": "hype.Text" - } - ], - "type": "*hype.InlineCode" - } - ], - { - "text": ". In the tests we are able to work with the original concrete types, instead of interfaces backed by unknown types.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figure", - "attributes": { - "id": "listing-1-36", - "type": "listing" - }, - "file": "module.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - { - "atom": "pre", - "nodes": [ - [ - { - "atom": "code", - "attributes": { - "class": "language-go", - "language": "go", - "src": "src/store/store_test.go#example" - }, - "lang": "go", - "nodes": [ - { - "content": "func Test_Store_Insert(t *testing.T) {\n\tt.Parallel()\n\n\t// create a store\n\ts := \u0026Store[string, User]{\n\t\tdata: map[string]User{},\n\t}\n\n\t// create a user\n\texp := User{Email: \"kurt@exampl.com\"}\n\n\t// insert the user\n\terr := s.Insert(exp)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\t// retreive the user\n\tact, err := s.Find(exp.Email)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\t// assert the returned user is the same as the inserted user\n\tif exp.Email != act.Email {\n\t\tt.Fatalf(\"expected %v, got %v\", exp, act)\n\t}\n\n}", - "file": "src/store/store_test.go", - "lang": "go", - "name": "example", - "start": 7, - "end": 38, - "type": "hype.Snippet" - } - ], - "type": "*hype.SourceCode" - } - ] - ], - "type": "*hype.Element" - }, - { - "atom": "hr", - "type": "*hype.Element" - }, - [ - { - "args": [ - "go", - "test", - "-v" - ], - "atom": "cmd", - "attributes": { - "data-go-version": "go1.21.5", - "exec": "go test -v", - "src": "src/store", - "test": "-v" - }, - "expected_exit": 0, - "nodes": [ - { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go test -v\n\n=== RUN Test_Store_Insert\n=== PAUSE Test_Store_Insert\n=== CONT Test_Store_Insert\n--- PASS: Test_Store_Insert (0.00s)\nPASS\nok \tdemo\t0.382s", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "test", - "-v" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/10-generics/src/store", - "stdout": "PT09IFJVTiAgIFRlc3RfU3RvcmVfSW5zZXJ0Cj09PSBQQVVTRSBUZXN0X1N0b3JlX0luc2VydAo9PT0gQ09OVCAgVGVzdF9TdG9yZV9JbnNlcnQKLS0tIFBBU1M6IFRlc3RfU3RvcmVfSW5zZXJ0ICgwLjAwcykKUEFTUwpvayAgCWRlbW8JMC4zODJz", - "duration": 1583265208, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - } - ], - "result": { - "atom": "result", - "nodes": [ - { - "atom": "pre", - "nodes": [ - { - "atom": "code", - "attributes": { - "class": "language-shell", - "language": "shell" - }, - "lang": "shell", - "nodes": [ - { - "text": "$ go test -v\n\n=== RUN Test_Store_Insert\n=== PAUSE Test_Store_Insert\n=== CONT Test_Store_Insert\n--- PASS: Test_Store_Insert (0.00s)\nPASS\nok \tdemo\t0.382s", - "type": "hype.Text" - }, - { - "text": "\n\n--------------------------------------------------------------------------------\nGo Version: go1.21.5\n", - "type": "hype.Text" - } - ], - "type": "*hype.FencedCode" - } - ], - "type": "*hype.Element" - } - ], - "result": { - "args": [ - "go", - "test", - "-v" - ], - "dir": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/10-generics/src/store", - "stdout": "PT09IFJVTiAgIFRlc3RfU3RvcmVfSW5zZXJ0Cj09PSBQQVVTRSBUZXN0X1N0b3JlX0luc2VydAo9PT0gQ09OVCAgVGVzdF9TdG9yZV9JbnNlcnQKLS0tIFBBU1M6IFRlc3RfU3RvcmVfSW5zZXJ0ICgwLjAwcykKUEFTUwpvayAgCWRlbW8JMC4zODJz", - "duration": 1583265208, - "type": "*clam.Result" - }, - "type": "*hype.CmdResult" - }, - "timeout": "30s", - "type": "*hype.Cmd" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "figcaption", - "nodes": [ - { - "atom": "em", - "attributes": { - "class": "figure-name" - }, - "nodes": [ - { - "text": "Listing 1.36:", - "type": "hype.Text" - } - ], - "type": "*hype.Element" - }, - { - "text": " ", - "type": "hype.Text" - }, - { - "text": "Testing the a type with constraints.", - "type": "hype.Text" - } - ], - "type": "*hype.Figcaption" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "pos": 36, - "section_id": 1, - "style": "listing", - "type": "*hype.Figure" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "title": "Generics", - "type": "*hype.Page" - } - ], - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "page", - "file": "module.md", - "nodes": [ - { - "text": "\n", - "type": "hype.Text" - }, - [ - { - "atom": "h1", - "file": "module.md", - "level": 1, - "nodes": [ - { - "text": "Summary", - "type": "hype.Text" - } - ], - "type": "hype.Heading" - } - ], - { - "text": "\n\n", - "type": "hype.Text" - }, - [ - { - "atom": "p", - "file": "module.md", - "nodes": [ - { - "text": "In this ", - "type": "hype.Text" - }, - { - "atom": "binding", - "attributes": { - "part": "" - }, - "file": "module.md", - "type": "*hype.Element" - }, - { - "text": " we covered the basics of generics in Go. We learned how to define constraints, how to use constraints on types, and how to use constraints on methods. Generics is still new to Go, but it is a powerful tool that can be used to make your code more expressive and maintainable.", - "type": "hype.Text" - } - ], - "type": "*hype.Paragraph" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "title": "Summary", - "type": "*hype.Page" - } - ], - { - "text": "\n", - "type": "hype.Text" - } - ], - "type": "*hype.Body" - } - ] - ], - "type": "*hype.Element" - } - ], - "type": "*hype.Element" - } - ], - "parser": { - "type": "*hype.Parser", - "root": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/10-generics", - "section": 1, - "snippets": {} - }, - "root": "/Users/markbates/Library/CloudStorage/Dropbox/dev/guides/content/book/chapters/10-generics", - "section_id": 1, - "snippets": {}, - "title": "Generics", - "type": "*hype.Document", - "filename": "module.md" -} \ No newline at end of file diff --git a/src/testdata/gotypes/body.json b/src/testdata/gotypes/body.json new file mode 100644 index 0000000..a4a6013 --- /dev/null +++ b/src/testdata/gotypes/body.json @@ -0,0 +1,20 @@ +{ + "atom": "body", + "attributes": {}, + "filename": "", + "html_node": { + "data": "body", + "data_atom": "body", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "hello", + "type": "hype.Text" + } + ], + "tag": "\u003cbody\u003e", + "type": "hype.Body" +} \ No newline at end of file diff --git a/src/testdata/gotypes/cmd.json b/src/testdata/gotypes/cmd.json new file mode 100644 index 0000000..7e252ff --- /dev/null +++ b/src/testdata/gotypes/cmd.json @@ -0,0 +1,50 @@ +{ + "args": [ + "echo", + "hello" + ], + "atom": "cmd", + "attributes": {}, + "env": [ + "FOO=bar", + "BAR=baz" + ], + "expected_exit": 1, + "filename": "", + "html_node": { + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [], + "result": { + "args": [ + "echo", + "hello" + ], + "atom": "result", + "attributes": {}, + "dir": "testdata/commands", + "duration": "1s", + "err": "this is an error", + "exit": 1, + "filename": "", + "html_node": { + "data": "result", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [], + "stderr": "this is stderr", + "stdout": "this is stdout", + "tag": "\u003cresult\u003e", + "type": "hype.CmdResult" + }, + "tag": "\u003ccmd\u003e", + "timeout": "1s", + "type": "hype.Cmd" +} \ No newline at end of file diff --git a/src/testdata/gotypes/cmd_error.json b/src/testdata/gotypes/cmd_error.json new file mode 100644 index 0000000..1ea5642 --- /dev/null +++ b/src/testdata/gotypes/cmd_error.json @@ -0,0 +1,12 @@ +{ + "args": [ + "echo", + "hello" + ], + "error": "EOF", + "exit": 1, + "filename": "foo.go", + "output": "foo\nbar\nbaz\n", + "root": "/tmp", + "type": "hype.CmdError" +} \ No newline at end of file diff --git a/src/testdata/gotypes/cmd_result.json b/src/testdata/gotypes/cmd_result.json new file mode 100644 index 0000000..9bf4d81 --- /dev/null +++ b/src/testdata/gotypes/cmd_result.json @@ -0,0 +1,25 @@ +{ + "args": [ + "echo", + "hello" + ], + "atom": "cmd", + "attributes": {}, + "dir": "/tmp", + "duration": "1s", + "err": "EOF", + "exit": 1, + "filename": "", + "html_node": { + "data": "cmd", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [], + "stderr": "nothing", + "stdout": "foo\nbar\nbaz\n", + "tag": "\u003ccmd\u003e", + "type": "hype.CmdResult" +} \ No newline at end of file diff --git a/src/testdata/gotypes/comment.json b/src/testdata/gotypes/comment.json new file mode 100644 index 0000000..c3e19c5 --- /dev/null +++ b/src/testdata/gotypes/comment.json @@ -0,0 +1,4 @@ +{ + "text": "hello", + "type": "hype.Comment" +} \ No newline at end of file diff --git a/src/testdata/gotypes/document.json b/src/testdata/gotypes/document.json new file mode 100644 index 0000000..f05bec4 --- /dev/null +++ b/src/testdata/gotypes/document.json @@ -0,0 +1,293 @@ +{ + "filename": "module.md", + "id": "1", + "nodes": [ + { + "atom": "", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "", + "data_atom": "", + "namespace": "", + "node_type": "html.DocumentNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "html", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "html", + "data_atom": "html", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "head", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "head", + "data_atom": "head", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [], + "tag": "\u003chead\u003e", + "type": "hype.Element" + }, + [ + { + "atom": "body", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "body", + "data_atom": "body", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + [ + { + "atom": "page", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "page", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "atom": "h1", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "h1", + "data_atom": "h1", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "level": 1, + "nodes": [ + { + "text": "Hello", + "type": "hype.Text" + } + ], + "tag": "\u003ch1\u003e", + "type": "hype.Heading" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "pre", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-ts", + "language": "ts", + "snippet": "class", + "src": "src/main.ts" + }, + "filename": "module.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/main.ts" + }, + { + "Namespace": "", + "Key": "snippet", + "Val": "class" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "ts", + "nodes": [ + { + "content": "export class Hype {\n constructor(parameters) {\n }\n}", + "file": "src/main.ts", + "lang": "ts", + "name": "class", + "start": 1, + "end": 8 + } + ], + "tag": "\u003ccode class=\"language-ts\" language=\"ts\" snippet=\"class\" src=\"src/main.ts\"\u003e", + "type": "hype.SourceCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "pre", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "pre", + "data_atom": "pre", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "atom": "code", + "attributes": { + "class": "language-ts", + "language": "ts", + "snippet": "constructor", + "src": "src/main.ts" + }, + "filename": "module.md", + "html_node": { + "attributes": [ + { + "Namespace": "", + "Key": "src", + "Val": "src/main.ts" + }, + { + "Namespace": "", + "Key": "snippet", + "Val": "constructor" + } + ], + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "ts", + "nodes": [ + { + "content": "constructor(parameters) {\n}", + "file": "src/main.ts", + "lang": "ts", + "name": "constructor", + "start": 3, + "end": 6 + } + ], + "tag": "\u003ccode class=\"language-ts\" language=\"ts\" snippet=\"constructor\" src=\"src/main.ts\"\u003e", + "type": "hype.SourceCode" + } + ], + "tag": "\u003cpre\u003e", + "type": "hype.Element" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "tag": "\u003cpage\u003e", + "title": "Hello", + "type": "hype.Page" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "tag": "\u003cbody\u003e", + "type": "hype.Body" + } + ] + ], + "tag": "\u003chtml\u003e", + "type": "hype.Element" + } + ], + "tag": "", + "type": "hype.Element" + } + ], + "parser": { + "type": "hype.Parser", + "root": "testdata/doc/snippets", + "section": 1, + "contents": "# Hello\n\n\u003ccode src=\"src/main.ts\" snippet=\"class\"\u003e\u003c/code\u003e\n\n\u003ccode src=\"src/main.ts\" snippet=\"constructor\"\u003e\u003c/code\u003e\n" + }, + "root": "testdata/doc/snippets", + "section_id": 1, + "snippets": { + "rules": { + ".go": "// %s", + ".html": "\u003c!-- %s --\u003e", + ".js": "// %s", + ".md": "\u003c!-- %s --\u003e", + ".rb": "# %s", + ".ts": "// %s" + }, + "snippets": { + "src/main.ts": { + "class": { + "content": "export class Hype {\n constructor(parameters) {\n }\n}", + "file": "src/main.ts", + "lang": "ts", + "name": "class", + "start": 1, + "end": 8 + }, + "constructor": { + "content": "constructor(parameters) {\n}", + "file": "src/main.ts", + "lang": "ts", + "name": "constructor", + "start": 3, + "end": 6 + } + } + } + }, + "title": "Hello", + "type": "hype.Document" +} \ No newline at end of file diff --git a/src/testdata/gotypes/element.json b/src/testdata/gotypes/element.json new file mode 100644 index 0000000..e501f8a --- /dev/null +++ b/src/testdata/gotypes/element.json @@ -0,0 +1,17 @@ +{ + "atom": "div", + "attributes": { + "class": "foo" + }, + "filename": "", + "html_node": { + "data": "div", + "data_atom": "div", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [], + "tag": "\u003cdiv class=\"foo\"\u003e", + "type": "hype.Element" +} \ No newline at end of file diff --git a/src/testdata/gotypes/execute_error.json b/src/testdata/gotypes/execute_error.json new file mode 100644 index 0000000..6023c86 --- /dev/null +++ b/src/testdata/gotypes/execute_error.json @@ -0,0 +1,12 @@ +{ + "contents": "foo", + "document": { + "snippets": {}, + "title": "My Title", + "type": "hype.Document" + }, + "error": "EOF", + "filename": "module.md", + "root": "testdata/parser/errors/execute", + "type": "hype.ExecuteError" +} \ No newline at end of file diff --git a/src/testdata/gotypes/fenced_code.json b/src/testdata/gotypes/fenced_code.json new file mode 100644 index 0000000..746885c --- /dev/null +++ b/src/testdata/gotypes/fenced_code.json @@ -0,0 +1,23 @@ +{ + "atom": "code", + "attributes": { + "language": "go" + }, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "lang": "go", + "nodes": [ + { + "text": "var x = 1", + "type": "hype.Text" + } + ], + "tag": "\u003ccode language=\"go\"\u003e", + "type": "hype.FencedCode" +} \ No newline at end of file diff --git a/src/testdata/gotypes/figcaption.json b/src/testdata/gotypes/figcaption.json new file mode 100644 index 0000000..a8b468d --- /dev/null +++ b/src/testdata/gotypes/figcaption.json @@ -0,0 +1,20 @@ +{ + "atom": "figcaption", + "attributes": {}, + "filename": "", + "html_node": { + "data": "figcaption", + "data_atom": "figcaption", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "This is a caption", + "type": "hype.Text" + } + ], + "tag": "\u003cfigcaption\u003e", + "type": "hype.Figcaption" +} \ No newline at end of file diff --git a/src/testdata/gotypes/figure.json b/src/testdata/gotypes/figure.json new file mode 100644 index 0000000..bc6cec5 --- /dev/null +++ b/src/testdata/gotypes/figure.json @@ -0,0 +1,23 @@ +{ + "atom": "figure", + "attributes": {}, + "filename": "", + "html_node": { + "data": "figure", + "data_atom": "figure", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "This is a figure", + "type": "hype.Text" + } + ], + "pos": 1, + "section_id": 2, + "style": "figure", + "tag": "\u003cfigure\u003e", + "type": "hype.Figure" +} \ No newline at end of file diff --git a/src/testdata/gotypes/heading.json b/src/testdata/gotypes/heading.json new file mode 100644 index 0000000..a050bbe --- /dev/null +++ b/src/testdata/gotypes/heading.json @@ -0,0 +1,21 @@ +{ + "atom": "h1", + "attributes": {}, + "filename": "", + "html_node": { + "data": "h1", + "data_atom": "h1", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "level": 1, + "nodes": [ + { + "text": "This is a heading", + "type": "hype.Text" + } + ], + "tag": "\u003ch1\u003e", + "type": "hype.Heading" +} \ No newline at end of file diff --git a/src/testdata/gotypes/image.json b/src/testdata/gotypes/image.json new file mode 100644 index 0000000..5a78232 --- /dev/null +++ b/src/testdata/gotypes/image.json @@ -0,0 +1,17 @@ +{ + "atom": "img", + "attributes": { + "src": "https://example.com/image.jpg" + }, + "filename": "", + "html_node": { + "data": "img", + "data_atom": "img", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [], + "tag": "\u003cimg src=\"https://example.com/image.jpg\"\u003e", + "type": "hype.Image" +} \ No newline at end of file diff --git a/src/testdata/gotypes/include.json b/src/testdata/gotypes/include.json new file mode 100644 index 0000000..76636d4 --- /dev/null +++ b/src/testdata/gotypes/include.json @@ -0,0 +1,18 @@ +{ + "atom": "include", + "attributes": { + "src": "sub.md" + }, + "dir": "testdata/includes", + "filename": "", + "html_node": { + "data": "include", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [], + "tag": "\u003cinclude src=\"sub.md\"\u003e", + "type": "hype.Include" +} \ No newline at end of file diff --git a/src/testdata/gotypes/inline_code.json b/src/testdata/gotypes/inline_code.json new file mode 100644 index 0000000..f9a9473 --- /dev/null +++ b/src/testdata/gotypes/inline_code.json @@ -0,0 +1,20 @@ +{ + "atom": "code", + "attributes": {}, + "filename": "", + "html_node": { + "data": "code", + "data_atom": "code", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "var x = 1", + "type": "hype.Text" + } + ], + "tag": "\u003ccode\u003e", + "type": "hype.InlineCode" +} \ No newline at end of file diff --git a/src/testdata/gotypes/li.json b/src/testdata/gotypes/li.json new file mode 100644 index 0000000..56385b1 --- /dev/null +++ b/src/testdata/gotypes/li.json @@ -0,0 +1,21 @@ +{ + "atom": "li", + "attributes": {}, + "filename": "", + "html_node": { + "data": "li", + "data_atom": "li", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "list-type": "ul", + "nodes": [ + { + "text": "This is a list item", + "type": "hype.Text" + } + ], + "tag": "\u003cli\u003e", + "type": "hype.LI" +} \ No newline at end of file diff --git a/src/testdata/gotypes/link.json b/src/testdata/gotypes/link.json new file mode 100644 index 0000000..d1f7281 --- /dev/null +++ b/src/testdata/gotypes/link.json @@ -0,0 +1,23 @@ +{ + "atom": "a", + "attributes": { + "href": "https://example.com" + }, + "filename": "", + "html_node": { + "data": "a", + "data_atom": "a", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "This is a link", + "type": "hype.Text" + } + ], + "tag": "\u003ca href=\"https://example.com\"\u003e", + "type": "hype.Link", + "url": "https://example.com" +} \ No newline at end of file diff --git a/src/testdata/gotypes/metadata.json b/src/testdata/gotypes/metadata.json new file mode 100644 index 0000000..c741450 --- /dev/null +++ b/src/testdata/gotypes/metadata.json @@ -0,0 +1,18 @@ +{ + "atom": "metadata", + "attributes": {}, + "data": { + "title": "Hello, World!" + }, + "filename": "", + "html_node": { + "data": "metadata", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [], + "tag": "\u003cmetadata\u003e", + "type": "hype.Metadata" +} \ No newline at end of file diff --git a/src/testdata/gotypes/now.json b/src/testdata/gotypes/now.json new file mode 100644 index 0000000..9b5f1b4 --- /dev/null +++ b/src/testdata/gotypes/now.json @@ -0,0 +1,20 @@ +{ + "atom": "now", + "attributes": {}, + "filename": "", + "html_node": { + "data": "now", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "1/2/2006", + "type": "hype.Text" + } + ], + "tag": "\u003cnow\u003e", + "type": "hype.Now" +} \ No newline at end of file diff --git a/src/testdata/gotypes/ol.json b/src/testdata/gotypes/ol.json new file mode 100644 index 0000000..e22aaa7 --- /dev/null +++ b/src/testdata/gotypes/ol.json @@ -0,0 +1,20 @@ +{ + "atom": "ol", + "attributes": {}, + "filename": "", + "html_node": { + "data": "ol", + "data_atom": "ol", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "This is an ordered list", + "type": "hype.Text" + } + ], + "tag": "\u003col\u003e", + "type": "hype.OL" +} \ No newline at end of file diff --git a/src/testdata/gotypes/p.json b/src/testdata/gotypes/p.json new file mode 100644 index 0000000..16d7304 --- /dev/null +++ b/src/testdata/gotypes/p.json @@ -0,0 +1,20 @@ +{ + "atom": "p", + "attributes": {}, + "filename": "", + "html_node": { + "data": "p", + "data_atom": "p", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "This is a paragraph", + "type": "hype.Text" + } + ], + "tag": "\u003cp\u003e", + "type": "hype.Paragraph" +} \ No newline at end of file diff --git a/src/testdata/gotypes/page.json b/src/testdata/gotypes/page.json new file mode 100644 index 0000000..c97b51f --- /dev/null +++ b/src/testdata/gotypes/page.json @@ -0,0 +1,21 @@ +{ + "atom": "page", + "attributes": {}, + "filename": "", + "html_node": { + "data": "page", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "more text", + "type": "hype.Text" + } + ], + "tag": "\u003cpage\u003e", + "title": "Page 1", + "type": "hype.Page" +} \ No newline at end of file diff --git a/src/testdata/gotypes/parse_error.json b/src/testdata/gotypes/parse_error.json new file mode 100644 index 0000000..39e71bc --- /dev/null +++ b/src/testdata/gotypes/parse_error.json @@ -0,0 +1,7 @@ +{ + "contents": "contents", + "error": "EOF", + "filename": "test.md", + "root": "root", + "type": "hype.ParseError" +} \ No newline at end of file diff --git a/src/testdata/gotypes/parser.json b/src/testdata/gotypes/parser.json new file mode 100644 index 0000000..e18f50a --- /dev/null +++ b/src/testdata/gotypes/parser.json @@ -0,0 +1,10 @@ +{ + "type": "hype.Parser", + "root": "testdata/auto/snippets/simple", + "disable_pages": true, + "section": 42, + "vars": { + "foo": "bar" + }, + "contents": "# Lone Ranger\n\n\u003ccode src=\"src/main.go\" snippet=\"foo\"\u003e\u003c/code\u003e\n" +} \ No newline at end of file diff --git a/src/testdata/gotypes/post_execute_error.json b/src/testdata/gotypes/post_execute_error.json new file mode 100644 index 0000000..f8a46d1 --- /dev/null +++ b/src/testdata/gotypes/post_execute_error.json @@ -0,0 +1,13 @@ +{ + "document": { + "snippets": {}, + "title": "My Title", + "type": "hype.Document" + }, + "error": "EOF", + "filename": "filename", + "origal_error": "io: read/write on closed pipe", + "post_executer": "\u003cnil\u003e", + "root": "root", + "type": "hype.PostExecuteError" +} \ No newline at end of file diff --git a/src/testdata/gotypes/post_parse_error.json b/src/testdata/gotypes/post_parse_error.json new file mode 100644 index 0000000..15bcba6 --- /dev/null +++ b/src/testdata/gotypes/post_parse_error.json @@ -0,0 +1,13 @@ +{ + "document": { + "snippets": {}, + "title": "My Title", + "type": "hype.Document" + }, + "error": "EOF", + "filename": "foo.md", + "origal_error": "io: read/write on closed pipe", + "post_parser": "\u003cnil\u003e", + "root": "root", + "type": "hype.PostParseError" +} \ No newline at end of file diff --git a/src/testdata/gotypes/pre_execute_error.json b/src/testdata/gotypes/pre_execute_error.json new file mode 100644 index 0000000..2e194fc --- /dev/null +++ b/src/testdata/gotypes/pre_execute_error.json @@ -0,0 +1,12 @@ +{ + "document": { + "snippets": {}, + "title": "My Title", + "type": "hype.Document" + }, + "error": "EOF", + "filename": "module.md", + "pre_executer": "\u003cnil\u003e", + "root": "root", + "type": "hype.PreExecuteError" +} \ No newline at end of file diff --git a/src/testdata/gotypes/pre_parse_error.json b/src/testdata/gotypes/pre_parse_error.json new file mode 100644 index 0000000..36c482c --- /dev/null +++ b/src/testdata/gotypes/pre_parse_error.json @@ -0,0 +1,8 @@ +{ + "contents": "", + "error": "EOF", + "filename": "module.md", + "pre_parser": "\u003cnil\u003e", + "root": "root", + "type": "hype.PreParseError" +} \ No newline at end of file diff --git a/src/testdata/gotypes/ref.json b/src/testdata/gotypes/ref.json new file mode 100644 index 0000000..69e1385 --- /dev/null +++ b/src/testdata/gotypes/ref.json @@ -0,0 +1,22 @@ +{ + "atom": "ref", + "attributes": { + "id": "foo" + }, + "filename": "", + "html_node": { + "data": "ref", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "foo", + "type": "hype.Text" + } + ], + "tag": "\u003cref id=\"foo\"\u003e", + "type": "hype.Ref" +} \ No newline at end of file diff --git a/src/testdata/gotypes/table.json b/src/testdata/gotypes/table.json new file mode 100644 index 0000000..4651443 --- /dev/null +++ b/src/testdata/gotypes/table.json @@ -0,0 +1,382 @@ +{ + "atom": "table", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "table", + "data_atom": "table", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "atom": "thead", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "thead", + "data_atom": "thead", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "atom": "tr", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "tr", + "data_atom": "tr", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "atom": "th", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "th", + "data_atom": "th", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Name", + "type": "hype.Text" + } + ], + "tag": "\u003cth\u003e", + "type": "hype.TH" + } + ], + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "atom": "th", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "th", + "data_atom": "th", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Age", + "type": "hype.Text" + } + ], + "tag": "\u003cth\u003e", + "type": "hype.TH" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "tag": "\u003ctr\u003e", + "type": "hype.TR" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "tag": "\u003cthead\u003e", + "type": "hype.THead" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + { + "atom": "tbody", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "tbody", + "data_atom": "tbody", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "atom": "tr", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "tr", + "data_atom": "tr", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "atom": "td", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "td", + "data_atom": "td", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Alice", + "type": "hype.Text" + } + ], + "tag": "\u003ctd\u003e", + "type": "hype.TD" + } + ], + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "atom": "td", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "td", + "data_atom": "td", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "42", + "type": "hype.Text" + } + ], + "tag": "\u003ctd\u003e", + "type": "hype.TD" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "tag": "\u003ctr\u003e", + "type": "hype.TR" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "tr", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "tr", + "data_atom": "tr", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "atom": "td", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "td", + "data_atom": "td", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Bob", + "type": "hype.Text" + } + ], + "tag": "\u003ctd\u003e", + "type": "hype.TD" + } + ], + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "atom": "td", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "td", + "data_atom": "td", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "13", + "type": "hype.Text" + } + ], + "tag": "\u003ctd\u003e", + "type": "hype.TD" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "tag": "\u003ctr\u003e", + "type": "hype.TR" + } + ], + { + "text": "\n\n", + "type": "hype.Text" + }, + [ + { + "atom": "tr", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "tr", + "data_atom": "tr", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "atom": "td", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "td", + "data_atom": "td", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "Kurt", + "type": "hype.Text" + } + ], + "tag": "\u003ctd\u003e", + "type": "hype.TD" + } + ], + { + "text": "\n", + "type": "hype.Text" + }, + [ + { + "atom": "td", + "attributes": {}, + "filename": "module.md", + "html_node": { + "data": "td", + "data_atom": "td", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "27", + "type": "hype.Text" + } + ], + "tag": "\u003ctd\u003e", + "type": "hype.TD" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "tag": "\u003ctr\u003e", + "type": "hype.TR" + } + ], + { + "text": "\n", + "type": "hype.Text" + } + ], + "tag": "\u003ctbody\u003e", + "type": "hype.Element" + }, + { + "text": "\n", + "type": "hype.Text" + } + ], + "tag": "\u003ctable\u003e", + "type": "hype.Table" +} \ No newline at end of file diff --git a/src/testdata/gotypes/td.json b/src/testdata/gotypes/td.json new file mode 100644 index 0000000..253c34e --- /dev/null +++ b/src/testdata/gotypes/td.json @@ -0,0 +1,20 @@ +{ + "atom": "td", + "attributes": {}, + "filename": "", + "html_node": { + "data": "td", + "data_atom": "td", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [ + { + "text": "foo", + "type": "hype.Text" + } + ], + "tag": "\u003ctd\u003e", + "type": "hype.TD" +} \ No newline at end of file diff --git a/src/testdata/gotypes/th.json b/src/testdata/gotypes/th.json new file mode 100644 index 0000000..221bde1 --- /dev/null +++ b/src/testdata/gotypes/th.json @@ -0,0 +1,15 @@ +{ + "atom": "th", + "attributes": {}, + "filename": "", + "html_node": { + "data": "th", + "data_atom": "th", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [], + "tag": "\u003cth\u003e", + "type": "hype.TH" +} \ No newline at end of file diff --git a/src/testdata/gotypes/thead.json b/src/testdata/gotypes/thead.json new file mode 100644 index 0000000..7983ec7 --- /dev/null +++ b/src/testdata/gotypes/thead.json @@ -0,0 +1,15 @@ +{ + "atom": "th", + "attributes": {}, + "filename": "", + "html_node": { + "data": "th", + "data_atom": "th", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [], + "tag": "\u003cth\u003e", + "type": "hype.THead" +} \ No newline at end of file diff --git a/src/testdata/gotypes/toc.json b/src/testdata/gotypes/toc.json new file mode 100644 index 0000000..fa55ee4 --- /dev/null +++ b/src/testdata/gotypes/toc.json @@ -0,0 +1,15 @@ +{ + "atom": "toc", + "attributes": {}, + "filename": "", + "html_node": { + "data": "toc", + "data_atom": "", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [], + "tag": "\u003ctoc\u003e", + "type": "hype.ToC" +} \ No newline at end of file diff --git a/src/testdata/gotypes/tr.json b/src/testdata/gotypes/tr.json new file mode 100644 index 0000000..a77aab6 --- /dev/null +++ b/src/testdata/gotypes/tr.json @@ -0,0 +1,15 @@ +{ + "atom": "tr", + "attributes": {}, + "filename": "", + "html_node": { + "data": "tr", + "data_atom": "tr", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [], + "tag": "\u003ctr\u003e", + "type": "hype.TR" +} \ No newline at end of file diff --git a/src/testdata/gotypes/ul.json b/src/testdata/gotypes/ul.json new file mode 100644 index 0000000..8707e1a --- /dev/null +++ b/src/testdata/gotypes/ul.json @@ -0,0 +1,15 @@ +{ + "atom": "ul", + "attributes": {}, + "filename": "", + "html_node": { + "data": "ul", + "data_atom": "ul", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "nodes": [], + "tag": "\u003cul\u003e", + "type": "hype.UL" +} \ No newline at end of file diff --git a/src/testdata/gotypes/var.json b/src/testdata/gotypes/var.json new file mode 100644 index 0000000..7bee71a --- /dev/null +++ b/src/testdata/gotypes/var.json @@ -0,0 +1,22 @@ +{ + "atom": "var", + "attributes": {}, + "filename": "", + "html_node": { + "data": "var", + "data_atom": "var", + "namespace": "", + "node_type": "html.ElementNode", + "type": "html.Node" + }, + "key": "id", + "nodes": [ + { + "text": "id", + "type": "hype.Text" + } + ], + "tag": "\u003cvar\u003e", + "type": "hype.Var", + "value": 1 +} \ No newline at end of file diff --git a/src/testdata/simple.json b/src/testdata/simple.json deleted file mode 100644 index f313b56..0000000 --- a/src/testdata/simple.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "nodes": [], - "parser": {}, - "root": "testdata", - "title": "Simple", - "type": "*hype.Document", - "filename": "module.md" -} \ No newline at end of file diff --git a/src/toc.spec.ts b/src/toc.spec.ts index f680601..f9281ab 100644 --- a/src/toc.spec.ts +++ b/src/toc.spec.ts @@ -11,7 +11,7 @@ import { Parser } from "./parser"; describe('toc', () => { let p: Parser = new Parser(); - let data = require("./testdata/errors.json") + let data = require("./testdata/09-errors.json") describe('errors doc', () => { diff --git a/src/visit_atom.spec.ts b/src/visit_atom.spec.ts index f6c8dde..4b2cec5 100644 --- a/src/visit_atom.spec.ts +++ b/src/visit_atom.spec.ts @@ -9,7 +9,7 @@ import { Parser } from "./parser"; describe('visitAtom', () => { let p: Parser = new Parser(); - let data = require("./testdata/errors.json") + let data = require("./testdata/09-errors.json") describe('errors doc', () => { diff --git a/usage.md b/usage.md index cc1ba80..dff9aed 100644 --- a/usage.md +++ b/usage.md @@ -2,6 +2,6 @@ jhklh -