Josh Gwosdz ([email protected])
red.ht/devconf24-quirky-go
except when...
Josh Gwosdz | Site Reliability Engineer / Software Engineer |
maintainer of package-operator | my router is running NixOS (and currently chokes on IPv6) |
I have a big big side project / playground graveyard | master procrastinator |
layouting is not my strength :) |
ACHTUNG
ACHTUNG
3 9 4 8 6 |
func doIO() error {
defer unhappiness();
}
func doIO() error {
f, err := f.Create("my-file.txt")
if err != nil { return fmt.Errorf("creating file: %w", err) }
defer f.Close();
_, err := f.WriteString(`"Meow!" (=^・ω・^=)`)
return err
}
func TestReturn(t *testing.T) {
actual := func() error {
var err error
defer func() {
err = expectedError
}()
return err
}()
assert.Equal(t, expectedError, actual)
}
func TestReturn(t *testing.T) {
actual := func() error {
var err error
defer func() {
err = expectedError
}()
return err
}()
assert.Equal(t, expectedError, actual)
}
func TestNamedReturn(t *testing.T) {
actual := func() (err error) {
defer func() {
err = expectedError
}()
return err
}()
assert.Equal(t, expectedError, actual)
}
Hooray this works!
As long as the outer function itself doesn't return an error, right?
func TestNamedReturnShadow(t *testing.T) {
actual := func() (err error) {
defer func() {
err = deferedError
}()
err = expectedError
return err
}()
assert.Equal(t, expectedError, actual)
}
func getNil() io.Writer {
var writer *bufio.Writer // pointer to a struct
return writer
}
func getNil() io.Writer {
var writer *bufio.Writer // pointer to a struct
fmt.Println("is nil:", writer == nil)
return writer
}
func getNil() io.Writer {
var writer *bufio.Writer // pointer to a struct
fmt.Println("is nil:", writer == nil)
// => is nil: true
return writer
}
n := getNil()
n := getNil()
fmt.Println("is nil:", n == nil)
n := getNil()
fmt.Println("is nil:", n == nil)
// is nil: false
* in some cases
a := "look ma, no var!"
func tuplerator(a, b int) (int, int) {
return a, b
}
a, b := tuplerator(13, 37)
func tuplerator(a, b int) (int, int) {
return a, b
}
a, b := tuplerator(13, 37)
a, b := tuplerator(4, 2) // doesn't work
func tuplerator(a, b int) (int, int) {
return a, b
}
a, b := tuplerator(13, 37)
{
a, b := tuplerator(4, 2) // does work
// a: 4, b: 2
}
// a: 13, b: 37
func tuplerator(a, b int) (int, int) {
return a, b
}
a, b := tuplerator(13, 37)
a, c := tuplerator(4, 2)
// a: 4, b: 37, c: 2
func tuplerator(a, b int) (int, int) {
return a, b
}
a, b := tuplerator(13, 37)
{
a, c := tuplerator(4, 2)
// a: 4, b: 37, c: 2
}
// a: 13, b: 37, c: does not exist
I don't know.
the man pages for close(2) say:
A careful programmer will check the return value of close(), since it is quite possible that errors on a previous write(2) operation are reported only on the final close() that releases the open file description. Failing to check the return value when closing a file may lead to silent loss of data.
[...] A careful programmer who wants to know about I/O errors may precede close() with a call to fsync(2).
func TestNamedReturnWrap(t *testing.T) {
actual := func() (err error) {
err = expectedError
defer func() {
cErr := deferedError
if err != nil && cErr != nil {
err = fmt.Errorf(`defered func errored but
surrounding function also encountered an error.
surrounding err: %w
defered err: %w`, err, cErr)
} else if cErr != nil {
err = cErr
}
}()
return err
}()
assert.ErrorIs(t, actual, expected)
assert.ErrorIs(t, actual, defered)
}
aka: this talk does not contain anything original ;)
and enjoy the rest of devconf :)