So loops in ruby has several ways to implement
10.times do |i|
puts i
end
while condition
# ...
end
users.each do |user|
# ...
end
until finished
# ...
end
Enter fullscreen mode Exit fullscreen mode
Go looks at all of this and basically says:
We only need one loop.
That loop is for.
Before getting into loops, though, let’s look at conditions.
Conditions in Go
Go has the familiar if, else if, and else.
if age >= 18 {
fmt.Println("Adult")
} else {
fmt.Println("Minor")
}
Enter fullscreen mode Exit fullscreen mode
The syntax is pretty close to Ruby, but there is one important difference.
Go does not use end.
Ruby:
if age >= 18
puts "Adult"
else
puts "Minor"
end
Enter fullscreen mode Exit fullscreen mode
Go uses curly braces to define the block:
if age >= 18 {
fmt.Println("Adult")
} else {
fmt.Println("Minor")
}
Enter fullscreen mode Exit fullscreen mode
Coming from Ruby, I had to get used to seeing {} everywhere.
Boolean Operators
The familiar operators are there:
if !active {
// not active
}
Enter fullscreen mode Exit fullscreen mode
if age == 18 {
// exactly 18
}
Enter fullscreen mode Exit fullscreen mode
And for inequality:
if age != 18 {
// not 18
}
Enter fullscreen mode Exit fullscreen mode
So the basic logic isn’t particularly difficult to transition to.
It’s mostly the syntax that’s different.
now going back to loops
The for Loop
Go has only one looping construct:
for
Enter fullscreen mode Exit fullscreen mode
The traditional form looks like this:
for init; condition; post {
// code
}
Enter fullscreen mode Exit fullscreen mode
For example:
for i := 0; i < 10; i++ {
fmt.Println(i)
}
Enter fullscreen mode Exit fullscreen mode
There are three parts:
- Initialization — runs before the first iteration
- Condition — checked before every iteration
- Post statement — runs after every iteration
This is very similar to the traditional C-style loop.
And this is where my C++ nostalgia started showing up.
Go doesn’t have separate times, while, or until loops.
Instead, you use for.
for i := 0; i < 10; i++ {
fmt.Println(i)
}
Enter fullscreen mode Exit fullscreen mode
One keyword, several forms.
The While-Like for
What if we don’t need the initialization and post statements?
No problem.
x := 1
for x < 10 {
fmt.Println(x)
x++
}
Enter fullscreen mode Exit fullscreen mode
This behaves like a while loop.
In other words:
for condition {
// ...
}
Enter fullscreen mode Exit fullscreen mode
is Go’s version of:
while condition
# ...
end
Enter fullscreen mode Exit fullscreen mode
This is one of those examples where Go’s simplicity starts making more sense.
Instead of introducing another keyword for while, Go reuses for.
Infinite Loops
You can even remove the condition completely:
for {
// keep going
}
Enter fullscreen mode Exit fullscreen mode
This creates an infinite loop.
Of course, you’ll usually want some way to escape it.
That’s where break comes in.
x := 1
for {
if x > 9 {
break
}
fmt.Println(x)
x++
}
Enter fullscreen mode Exit fullscreen mode
The loop keeps running until the break statement is reached.
Ruby has a similar concept:
x = 1
loop do
break if x > 9
puts x
x += 1
end
Enter fullscreen mode Exit fullscreen mode
Again, Go doesn’t need a separate loop construct.
for handles it.
break and continue
Go also provides the familiar break and continue keywords.
break
break exits the loop completely.
for i := 0; i < 10; i++ {
if i == 5 {
break
}
fmt.Println(i)
}
Enter fullscreen mode Exit fullscreen mode
The loop stops when i reaches 5.
continue
continue skips the remaining code in the current iteration and moves to the next one.
for i := 0; i < 10; i++ {
if i%2 == 0 {
continue
}
fmt.Println(i)
}
Enter fullscreen mode Exit fullscreen mode
This skips even numbers and prints the odd ones.
Ruby has the same concepts:
10.times do |i|
next if i.even?
puts i
end
Enter fullscreen mode Exit fullscreen mode
Ruby uses next where Go uses continue.
range: The Go Way to Iterate Over Collections
The for loop becomes even more interesting when combined with range.
The range form allows you to iterate over collections such as:
- arrays
- slices
- strings
- maps
- channels
For example:
names := []string{"Alice", "Bob", "Charlie"}
for index, name := range names {
fmt.Println(index, name)
}
Enter fullscreen mode Exit fullscreen mode
This gives us both the index and the value.
The output would look conceptually like:
0 Alice
1 Bob
2 Charlie
Enter fullscreen mode Exit fullscreen mode
Comparing range with Ruby
In Ruby, I’d probably write:
names = ["Alice", "Bob", "Charlie"]
names.each_with_index do |name, index|
puts "#{index} #{name}"
end
Enter fullscreen mode Exit fullscreen mode
Or, if I don’t need the index:
names.each do |name|
puts name
end
Enter fullscreen mode Exit fullscreen mode
In Go, range handles both cases.
for index, name := range names {
fmt.Println(index, name)
}
Enter fullscreen mode Exit fullscreen mode
And if I only care about the value, I can ignore the index:
for _, name := range names {
fmt.Println(name)
}
Enter fullscreen mode Exit fullscreen mode
The _ tells Go that I intentionally don’t need that value.
Switch Statements
Go also has switch for conditional logic.
A simple switch looks like this:
switch name {
case "Moneypenny":
fmt.Println("Miss Moneypenny")
case "Bond":
fmt.Println("Bond, James Bond")
case "Q":
fmt.Println("This is Q")
default:
fmt.Println("Unknown")
}
Enter fullscreen mode Exit fullscreen mode
Unlike Ruby’s case, Go doesn’t require an end.
Ruby:
case name
when "Moneypenny"
puts "Miss Moneypenny"
when "Bond"
puts "Bond, James Bond"
when "Q"
puts "This is Q"
else
puts "Unknown"
end
Enter fullscreen mode Exit fullscreen mode
But there is another interesting form of Go’s switch.
Switch Without an Expression
You can leave the value out completely:
switch {
case age < 18:
fmt.Println("Minor")
case age >= 18:
fmt.Println("Adult")
}
Enter fullscreen mode Exit fullscreen mode
Each case is essentially a condition.
This can be useful when you have several related conditions.
Ruby’s case can also be used for conditional expressions, although the syntax and matching behavior are different.
Multiple Values in a Case
A Go case can match multiple values:
switch name {
case "Moneypenny", "Bond", "Dr No":
fmt.Println("Secret agent")
default:
fmt.Println("Unknown")
}
Enter fullscreen mode Exit fullscreen mode
This means we don’t need separate cases for every value when they should produce the same result.
fallthrough
One thing that caught my attention was fallthrough.
Normally, once a Go switch finds a matching case, it stops.
switch {
case true:
fmt.Println("first")
case true:
fmt.Println("second")
}
Enter fullscreen mode Exit fullscreen mode
Only the first case runs.
If you explicitly use fallthrough:
switch {
case true:
fmt.Println("first")
fallthrough
case true:
fmt.Println("second")
case true:
fmt.Println("third")
}
Enter fullscreen mode Exit fullscreen mode
The first and second cases run, but the third does not.
This is different from the behavior many people might expect from C-style switch statements, where falling through can happen unless you explicitly stop it.
Go makes the behavior explicit with fallthrough.
Go vs Ruby: Control Flow
Here’s how the two languages compare.
Concept Go Ruby Conditionif / else
if / else
Not
!
!
Equality
==
==
Inequality
!=
!=
Main loop
for
Multiple constructs
While loop
for condition
while condition
Infinite loop
for {}
loop do
Iterate collection
for ... range
.each
Skip iteration
continue
next
Exit loop
break
break
Switch
switch
case
Multiple switch values
case "a", "b"
when "a", "b"
Neither approach is necessarily better.
They’re just optimizing for different things.
답글 남기기