Go Practice Questions (Solutions)¶
Using English plus simple code examples, explain the difference between arrays and slices in Go.
Sample solution:
In Go, an array is sequence of 0 or more objects stored contiguously and efficiently accessible by their position, e.g.:
a := [3]float64{1, 2, 3} // array of 3 floats
Importantly, in Go the length of an array is part of the array’s type. That means arrays with different lengths are incompatible. For instance, this is okay in Go:
a := [3]float64{1, 2, 3} var b [3]float64 b = a // okay: copies a into a var c [4]float64 // length 4, so c is not same type as a and b c = a // compile-time error: a and c are different type
A slice is an object that describes a contiguous sub-part of an array. For example:
sl := []float64{1, 2, 3} // a slice
The size of the slice is not specified here because slices do not have a fixed size. Instead, they can grow and shrink in size.
Slices always refer to an underlying array, i.e. slices are “backed” by an array. The built-in
copy
function can be used to make a copy of a slice, and the built-inappend
function can be used to add a new element to the end of a slice.Using English plus a simple code example, give a major reason why Go does not let you pass a slice to a function that expects an array.
Sample solution:
You can’t pass a slice to a function that expects an array because the slice might not be the same size as the array. For example:
func sum(p [3]float64) float64 { return p[0] + p[1] + p[2] } // ... sl := []{5, 6} // a slice of length 2
If Go let you call
sum(sl)
, then there would be an error when it tried to accessp[2]
, because there is no position 2 in the array.Write a function called
vc_count(s string)
that returns the number of vowels and consonants ins
.A vowel is defined to be one of these lowercase letters:
a
,e
,i
,o
,u
,y
. A consonant is defined to be any character that is not a vowel, and also the lettery
. Thusy
should be counted as both a vowel and a consonant.Also, you must use a ranged for-loop (in a sensible way) in your solution.
Your function must work with code like this:
v, c := vc_count("yay") fmt.Println(v, c)
Sample solution:
func isVowel(c rune) bool { return c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u' || c == 'y' } func vc_count(s string) (int, int) { vowels, cons := 0, 0 for _, ch := range s { if isVowel(ch) { vowels++ } if ch == 'y' || !isVowel(ch) { cons++ } } return vowels, cons }
Write a goroutine called
char_gen(s string, out chan rune)
that returns the characters ofs
one at a time on channelout
. Use the built-in functionclose
to closeout
when all the characters have been sent.Demonstrate how to use
char_gen
by writing amain
function that uses it print out an entire string.Sample solution:
func char_gen(s string, out chan rune) { for _, c := range s { out <- c } close(out) }
One way to write
main
:func main() { nextChar := make(chan rune) s := "applesauce" go char_gen(s, nextChar) for i := 0; i < len(s); i++ { fmt.Println(string(<-nextChar)) } }
An alternate way using a ranged for-loop:
func main() { nextChar := make(chan rune) s := "applesauce" go char_gen(s, nextChar) for ch := range nextChar { fmt.Println(string(ch)) } }
This second version only works if
char_gen
closes the channel when its done. Try commenting-outclose(out)
inchar_gen
to see what happens.Answer all the following questions with Go code.
Write a function called
add(x, y)
that returns the sum of two ints, e.g.:fmt.Println(add(3, 5)); // 8
Solution:
func add(x, y int) int { return x + y }
Write a function called
c_add
that is a curried version ofadd
, e.g.:add3 := c_add(3) fmt.Println(add3(5)) // 8 fmt.Println(c_add(2)(4)) // 6Solution:
func c_add(x int) func(int) int { f := func(y int) int { return x + y } return f }Write a function called
curry(f)
that returns a curried version off
. Assume thatf
is a (non-curried) function that takes two ints as input and returns an int.It can be used like this:
curr_add := curry(add) // add is the regular non-curried add function add2 := curr_add(2) fmt.Println(add2(6)) // 8Solution:
func curry(f func(int, int) int) func(int) func(int) int { g := func(x int) func(int) int { h := func(y int) int { return f(x, y) } return h } return g }
a) Write a function called
negpos(s)
that takes a slice of ints as input, and returns two new slices, named neg and pos, where neg contains all the numbers ins
that are less than 0, and pos contains all the numbers ins
that are greater than, or equal to, 0. For example:s := []int{6, -2, 0, 2, -6, -4, 3} neg, pos := negpos(s) fmt.Println(neg) // {-2, -6, -4} fmt.Println(pos) // {6, 0, 2, 3}
Use features of Go to make
negpos
as short and clear as possible.Sample solution:
func negpos(s []int) (neg, pos []int) { for _, n := range s { if n < 0 { neg = append(neg, n) } else { pos = append(pos, n) } } return neg, pos }
b) To help test your
negpos
function, write a function calledall(s, pred)
where:s
is a slice ofint
valuespred
is a function that takes oneint
as input, and returns abool
all(s, pred)
returnstrue
if everyint
ins
is true forpred
, andfalse
otherwise (i.e. it returnsfalse
ifs
contains 1, or more,int` values that cause ``pred
to returnfalse
).Sample solution:
func all(s []int, pred func(int) bool) bool { for _, n := range s { if !pred(n) { return false } } return true }c) Write a single Go statement of the form
all(s, pred)
that returnstrue
just when every element ins
is less than 0, andfalse
otherwise.Sample solution:
all(neg, func(n int) bool { return n < 0 })