Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Go Cookbook

Practical, copy-paste-ready recipes for Go code generation. For the full API of each spec type, see Building Functions & Fields, Building Types & Enums, and Files & Projects.

Struct with tags

extern crate sigil_stitch;
use sigil_stitch::prelude::*;
fn main() {
let type_spec = TypeSpec::builder("User", TypeKind::Struct)
    .add_field(
        FieldSpec::builder("Name", TypeName::primitive("string"))
            .tag("json:\"name\" db:\"name\"")
            .build()
            .unwrap(),
    )
    .add_field(
        FieldSpec::builder("Email", TypeName::primitive("string"))
            .tag("json:\"email\" db:\"email\"")
            .build()
            .unwrap(),
    )
    .add_field(
        FieldSpec::builder("Age", TypeName::primitive("int"))
            .tag("json:\"age,omitempty\"")
            .build()
            .unwrap(),
    )
    .build()
    .unwrap();
}
type User struct {
    Name string `json:"name" db:"name"`
    Email string `json:"email" db:"email"`
    Age int `json:"age,omitempty"`
}

Newtype (distinct type)

extern crate sigil_stitch;
use sigil_stitch::prelude::*;
fn main() {
let type_spec = TypeSpec::builder("Meters", TypeKind::Newtype)
    .extends(TypeName::primitive("float64"))
    .build()
    .unwrap();
}
type Meters float64

Interface

extern crate sigil_stitch;
use sigil_stitch::prelude::*;
fn main() {
let type_spec = TypeSpec::builder("Repository", TypeKind::Interface)
    .doc("Repository defines data access methods.")
    .add_method(
        FunSpec::builder("FindByID")
            .add_param(ParameterSpec::new("id", TypeName::primitive("string")).unwrap())
            .returns(TypeName::raw("(Entity, error)"))
            .build()
            .unwrap(),
    )
    .add_method(
        FunSpec::builder("Save")
            .add_param(ParameterSpec::new("entity", TypeName::primitive("Entity")).unwrap())
            .returns(TypeName::primitive("error"))
            .build()
            .unwrap(),
    )
    .build()
    .unwrap();

let file = FileSpec::builder("repo.go")
    .header(CodeBlock::of("package repo", ()).unwrap())
    .add_type(type_spec)
    .build()
    .unwrap();
let output = file.render(80).unwrap();
}
package repo

// Repository defines data access methods.
type Repository interface {
	FindByID(id string) (Entity, error)

	Save(entity Entity) error
}

Generic function

extern crate sigil_stitch;
use sigil_stitch::prelude::*;
fn main() {
let tp = TypeParamSpec::new("T").with_bound(TypeName::primitive("comparable"));

let mut body_b = CodeBlock::builder();
body_b.begin_control_flow("if a > b", ());
body_b.add_statement("return a", ());
body_b.end_control_flow();
body_b.add_statement("return b", ());
let body = body_b.build().unwrap();

let fun = FunSpec::builder("Max")
    .add_type_param(tp)
    .add_param(ParameterSpec::new("a", TypeName::primitive("T")).unwrap())
    .add_param(ParameterSpec::new("b", TypeName::primitive("T")).unwrap())
    .returns(TypeName::primitive("T"))
    .body(body)
    .build()
    .unwrap();

let file = FileSpec::builder("max.go")
    .header(CodeBlock::of("package main", ()).unwrap())
    .add_function(fun)
    .build()
    .unwrap();
let output = file.render(80).unwrap();
}
package main

func Max[T comparable](a T, b T) T {
	if a > b {
		return a
	}
	return b
}

Const block with enum generation

Use sigil_quote! with a $for inside const ( ... ) to generate enum-like const blocks:

extern crate sigil_stitch;
use sigil_stitch::prelude::*;
use sigil_stitch::lang::go::Go;
fn main() {
let variants = vec!["Alpha", "Beta", "Gamma"];

let const_block = sigil_quote!(Go {
    const (
    $for(v in &variants) {
        $L("@{v}Kind @{v} = \"@{v}\"");
    }
    )
}).unwrap();

let file = FileSpec::builder("kind.go")
    .header(CodeBlock::of("package main", ()).unwrap())
    .add_code(const_block)
    .build()
    .unwrap();
let output = file.render(80).unwrap();
}
package main

const (
	AlphaKind Alpha = "Alpha"
	BetaKind Beta = "Beta"
	GammaKind Gamma = "Gamma"
)

The parser recognizes const (, var (, import (, and type ( as structural blocks in Go, so $for, $if, $C_each, and interpolation markers all work inside the parentheses. The body is auto-indented with tabs.