A golang duck-typing library
Switch branches/tags
Nothing to show
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Type Name Latest commit message Commit time
Failed to load latest commit information.


MIT licensed Go Report Card Build Status Coverage Status GoDoc


Sometimes in golang a function returns an interface (or perhaps something was marshalled into an interface). Duck allows you to manipulate and convert from interfaces in a very simple manner. Duck is very eager to fit the inputs to the wanted format.

Type Conversions

The most basic actions are conversions between the standard built-in types.

//true, true
b,ok := duck.Bool(1.0)
//false, true
b,ok = duck.Bool(0.0)

//"1337", true
s, ok := duck.String(1337)
//"true", true
s, ok := duck.String(true)

//56, true
i, ok := duck.Int("56.0")

//1.0, true
f, ok := duck.Float(true)

var vptr interface{}

v := 6.0
vptr := &v	//duck follows pointers

s, ok = duck.String(vptr)
i,ok = duck.Int(vptr)
f,ok = duck.Float(vptr)
b,ok = duck.Bool(vptr)


Duck allows comparing interfaces with similar conversions as the type functions.

//true, true ("34.5" < 35)
out, ok := duck.Lt("34.5",35)
//false, true
out, ok = duck.Lt("34.5",34)

out, ok = duck.Eq("1.0", true)

//false,true - this one is unusual, true is defined as 1 (as in c)
out, ok = duck.Eq("2.0", true)

//false,true - false is defined as 0
out, ok = duck.Eq("2.0", false)

//true, true (34.6 >= 34)
out,ok = duck.Gte(34.6, 34)

if duck.Cmp(45,45.32)==duck.LessThan {

if duck.Cmp(45," LOL ")==duck.CantCompare {

if duck.Cmp(45,45.0)==duck.Equals {


Duck gets very liberal with its duck-typing for objects. The main function here is Get which gets an element from the object. Since duck just loves duck-typing, as long as the requested element can be found in the given object, it is extracted - no matter if the object is a map, struct or array/slice.

floatarray := []float32{0.0,1.0,2.0,3.0,4.0}

// 1.0, true
e,ok := duck.Get(floatarray,1)
e,ok = duck.Get(floatarray,1.0)
e,ok = duck.Get(floatarray,true)
e,ok = duck.Get(floatarray,"1.0")

//Python-style indexing!
e, ok = duck.Get(floatarray,-1.0)

//Currently, only map[string] is supported - panics on other map types!
smap := map[string]string{"foo": "bar", "true": "wow", "1": "one"}

//"bar", true
s, ok := duck.Get(smap, "foo")
//"wow", true
s, ok = duck.Get(smap,true)
// "one", true
s, ok = duck.Get(smap,1)	//Note that string conversions ALWAYS convert 1.000 -> 1

st := struct {
	MyElement string
	SecondElement int

//"woo", true
sv, ok := duck.Get(st,"MyElement")
//nil, false
sv, ok = duck.Get(st,"Nonexisting")


Sometimes you want structs to be recognized by a special tag in Get. The duck tag allows you to do that.

val := struct{
	A1 string `duck:"lol"`
	A2 string `duck:"-"`

v,ok := duck.Get(val,"A1")
v,ok = duck.Get(val,"A2")

//"foo", true
v, ok = duck.Get(val,"lol")


Initial support for setting values is also available.

var integer int
ok := duck.Set(&integer,"54")
if (intger==54) {

var mystring string
ok = duck.Set(&mystring,13.0)
if (mystring=="13") {

var iface interface{}

ok = duck.Set(&iface, true)
_,ok = iface.(bool)

//Currently, only map[string]interface{} is supported for setting values
// reflect makes it very difficult to set map values. Structs and arrays work fine.
mymap := map[string]interface{}{"foo":"bar"}
ok = duck.Set(&mymap,1337,"foo")
//mymap["foo"]=1337 now

//Arbitrary object depth is supported
mysuperobject := struct{
	A1 []interface{}
	A2 string
	A1: []interface{}{"hello","world"},

//sets "world" to "not world anymore"
ok = duck.Set(&m,"not world anymore","A1",1)

If you need speed

Duck itself is very general, but not particularly fast. To work in restricted environments where speed is critical, a limited version of duck was created: quack. Quack is located in the quack subfolder, with the same API. It is much quicker.