Skip to content

Instantly share code, notes, and snippets.

@piotrpersona
Last active December 25, 2019 23:58
Show Gist options
  • Save piotrpersona/5c40de14860662a3ad1810032fa39d6e to your computer and use it in GitHub Desktop.
Save piotrpersona/5c40de14860662a3ad1810032fa39d6e to your computer and use it in GitHub Desktop.
Go hacks
type Spinlock struct {
state *int32
}
const free = int32(0)
func (l *Spinlock) Lock() {
for !atomic.CompareAndSwapInt32(l.state, free, 42) { // 42 or any other value but 0
runtime.Gosched() // Poke the scheduler
}
}
func (l *Spinlock) Unlock() {
atomic.StoreInt32(l.state, free) // Once atomic, always atomic
}
// What is the output?
package main
import "fmt"
type MyError struct {}
// Implement error interface
func (me *MyError) Error() string {
return "error"
}
func foo() *MyError {
return nil
}
// Output: error
// Explanation:
// foo returns nil which is of type *MyError
// nil is a specific type in golang
// therefore due to type mismarch of expression:
// nil != *MyError
// condition result is true
func main() {
var err error // interface error
err = foo() // *MyError - nil pointer of type MyError
if err != nil { // nil is a separate type - due to type mismatch nil != *MyError this is true
fmt.Println(err)
} else {
fmt.Println("Else")
}
}
// Fan Out:
//
// OutA
// /
// /
// In --- o
// \
// \
// OutB
func Fanout(In <-chan int, OutA, OutB chan int) {
for data := range In { // Receive until closed
select { // send to first non-blocking channel
case OutA <- data:
case OutB <- data:
}
}
}
func TryReceiveWithTimeout(c <-chan int, duration time.Duration) (data int, more, ok bool) {
select {
case data, more = <-c:
return data, more, true
case <-time.After(duration):
return 0, true, false
}
}
func TurnoutQuit(Quit <-chan int, InA, InB, OutA, OutB chan int) {
for {
select {
case data := <- InA:
case data := <- InB:
case <- Quit:
close(InA) // anti-pattern receiver should not close the channel, however quit is delegated
close(InB)
Fanout(InA, OutA, OutB) // Flush the remaining data
Fanout(InB, OutA, OutB)
return
}
}
}
c := make(chan int)
close(c)
fmt.Println(<-c) // Receive and print
// Output:
// 0, false
// 0 - zero value of type channel c - zero of `int` in this case
// false - there is no more data to read, because this is not the buffered channel
// Turn Out:
//
// InA OutA
// \ /
// \ /
// o
// / \
// / \
// InB OutB
func Turnout(InA, InB <-chan int, OutA, OutB chan int) {
for {
select {
case data, more := <- InA:
case data, more := <- InB:
}
if !more {
return
}
select {
case OutA <- data:
case OutB <- data:
}
}
}
// What is the output?
package main
import "fmt"
// Output: Hello
// Explanation:
// Both goroutines will be scheduled, but the main goroutine will not wait for them to complete
// Fix #1: wait in main goroutine
// Fix #2: wait via sync.WaitGroup
func main() {
fmt.Println("Hello")
// fix #2
var wg sync.WaitGroup
wg.Add(2)
defer wg.Wait()
go func() {
fmt.Println("1")
wg.Done() // fix #2
}()
go func() {
fmt.Println("2")
wg.Done() // fix #2
}()
// fix #1
time.Sleep(1)
}
// What is the output?
package main
// Output: Compile error ... Cannot write to a closed channel
func main() {
c := make(chan int)
close(c)
c <- 1
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment