Surprising, not surprisingly, choose any two, the go community doesn't seem to have any intrusive linked list implementations. I'm currently working with data that has an html/dom like structure, i don't want to expose all of the existing code to a new container structure, and it would be nice for elements to have direct access to their siblings -- all in all, a classic use case for intrusive lists.
After searching around a bit, the few i could find were incomplete or experimental attempts. This example, by Lex Sheehan, is nice; but, it's a tutorial, and it ends by introducing go's standard library list implementation ( which is not intrusive. )
So, i decided to write one myself. Package inlist ( via GoDoc, and github ) is a port of the go standard library list package. It hews close enough to the original that i could use the same test code with some tweaks necessary to support the intrusive changes.
See full post...
issues with go const
posted
Tuesday, February 21, 2017
Here's a nice little gotcha. In go, "enums" are often defined using the iota generator like this:
Assertions, and reflection will fail.
In the first const example, using iota, there's only one equal sign: so all of the constants get the same type.
In the second const example, even though we started the list with Sunday as a type of "DaysOfTheWeek", the presence of the equal sign on the line which declares Monday resets the type declaration engine to its defaults. In this case, a string. So, only Sunday is of our enumerated type. Monday-Saturday are all of type "string".
Now, while ExampleDay() says it returns our enumerated type, Friday's actual type will never change. It's always and forever string. The fact the compiler lets this pass seems to violate the principle of least surprise, but there might be other common cases where this behavior makes more sense. ( While go is strongly typed, the way it handles literals and other edge cases sometimes leaves me wanting for warnings. ) I was writing off-the-cuff. Go underlying types only apply to interfaces, not primitive values.
The issue, then, for reflect.DeepEqual(Friday, ExampleDay()) is that the first parameter, Friday, is of type "string", while the second parameter, ExampleDay(), is of type "DaysOfTheWeek". The types don't match and DeepEqual returns false. Testify assert, which relies on reflect, therefore also fails.
If we redeclare our const list:
See full post...
The downside, of course, is that when you want to print those values:type DaysOfTheWeek int const ( Sunday DaysOfTheWeek = iota Monday Tuesday Wednesday Thursday Friday )
While the "stringer" code-generator is the recommend way of handling this, I'm often tempted to simply change the declaration:fmt.Println(Sunday) // prints 0, would rather it print "Sunday"
But, this is wrong in an important way.type DaysOfTheWeek string const ( Sunday DaysOfTheWeek = "Sunday" Monday = "Monday" Tuesday = "Tuesday" Wednesday = "Wednesday" Thursday = "Thursday" Friday = "Friday" )
Assertions, and reflection will fail.
We expect that both statements return true, but in fact the second statement is false. If you are using testify, an assertion on the value will also fail.import "reflect" func ExampleDay() DaysOfTheWeek { return Friday } func main() { fmt.Println(reflect.DeepEqual(Friday, Friday)) // true fmt.Println(reflect.DeepEqual(Friday, ExampleDay())) // false! }
The reason is that DeepEqual requires types match, and that the definition of const lists, in effect, resets the type declaration for each line containing an equals sign.func TestSomething(t *testing.T) { // passes, these are the same type and same object. assert.Equal(t, Friday, Friday) // fails, these are of different types! assert.Equal(t, Friday, ExampleDay()) }
In the first const example, using iota, there's only one equal sign: so all of the constants get the same type.
In the second const example, even though we started the list with Sunday as a type of "DaysOfTheWeek", the presence of the equal sign on the line which declares Monday resets the type declaration engine to its defaults. In this case, a string. So, only Sunday is of our enumerated type. Monday-Saturday are all of type "string".
If we redeclare our const list:
Then reflect, and asserts, will work as expected:const ( Sunday DaysOfTheWeek = "Sunday" Monday DaysOfTheWeek = "Monday" Tuesday DaysOfTheWeek = "Tuesday" Wednesday DaysOfTheWeek = "Wednesday" Thursday DaysOfTheWeek = "Thursday" Friday DaysOfTheWeek = "Friday" )
Unfortunately, unlike with iota, there's no pretty way to declare all of those strings without repeating the type. The closest we can get looks like this:func main() { fmt.Println(reflect.DeepEqual(Friday, ExampleDay()) // true! } func TestSomething(t *testing.T) { // passes, these are of now the same type! assert.Equal(t, Friday, ExampleDay()) }
Which is error prone, and looks a little gross with the default go formatter, but is at least easy to generate, and more importantly: it's correct.const ( ParamTypeUnknown, ParamTypeCommand, ParamTypeArray, ParamTypePrim, ParamTypeBlob ParamType = "ParamTypeUnknown", "ParamTypeCommand", "ParamTypeArray", "ParamTypePrim", "ParamTypeBlob" )
See full post...
Posted in:
go
Subscribe to:
Posts (Atom)