Hone logo
Hone
Problems

Go Channels: Implementing a Range Generator

This challenge focuses on leveraging Go's powerful concurrency primitives, specifically channels, to create a function that generates a sequence of values. You will implement a generator function that returns a channel, allowing you to iterate over a range of numbers in a concurrent and idiomatic Go fashion. This pattern is incredibly useful for producing data streams that can be consumed by other goroutines without blocking the main execution flow.

Problem Description

Your task is to create a Go function named MakeRange that takes two integer arguments: start and end. This function should return a read-only channel of integers (<-chan int).

The channel should emit integers sequentially from start up to (but not including) end. Once all numbers in the range have been sent, the channel must be closed.

The MakeRange function should be implemented as a goroutine that sends values to the channel. This allows the caller to receive values from the channel as they are generated, without waiting for the entire sequence to be computed.

Key Requirements:

  1. Function Signature: func MakeRange(start, end int) <-chan int
  2. Channel Emission: Emit integers start, start + 1, ..., end - 1.
  3. Channel Closure: Close the channel after emitting the last number.
  4. Goroutine Implementation: The emission logic must run in a separate goroutine.
  5. Read-only Channel: The returned channel must be of type <-chan int.

Expected Behavior:

When a caller receives from the returned channel, they should get the next number in the sequence. When the range is exhausted, receiving from the channel should indicate that it's closed (e.g., using the val, ok := <-ch idiom).

Edge Cases:

  • start is greater than or equal to end: The channel should be closed immediately without emitting any values.

Examples

Example 1:

package main

import "fmt"

func main() {
	// Assume MakeRange is implemented as described
	for num := range MakeRange(1, 5) {
		fmt.Println(num)
	}
}
Output:
1
2
3
4

Explanation: The MakeRange function is called with start=1 and end=5. It starts a goroutine that sends 1, then 2, then 3, then 4 to the channel. After sending 4, it closes the channel. The for range loop in main receives these values and prints them until the channel is closed.

Example 2:

package main

import "fmt"

func main() {
	// Assume MakeRange is implemented as described
	count := 0
	for range MakeRange(10, 10) { // start == end
		count++
	}
	fmt.Println("Count:", count)
}
Output:
Count: 0

Explanation: When start is equal to end, the range is empty. The MakeRange function should detect this, close the channel immediately, and emit no values. The for range loop terminates without executing its body.

Example 3:

package main

import "fmt"

func main() {
	// Assume MakeRange is implemented as described
	count := 0
	for range MakeRange(5, 2) { // start > end
		count++
	}
	fmt.Println("Count:", count)
}
Output:
Count: 0

Explanation: Similar to Example 2, when start is greater than end, the range is considered empty. The channel is closed immediately, and no values are sent or received.

Constraints

  • The start and end integers will be within the standard int range in Go.
  • The MakeRange function must be implemented entirely in Go.
  • Efficiency is important; avoid unnecessary allocations or complex operations. The primary goal is to demonstrate channel usage for generating sequences.

Notes

  • Remember to use a go keyword to start the goroutine that populates the channel.
  • The defer close(ch) pattern within the goroutine is a clean way to ensure the channel is closed.
  • Think about how the for range loop on a channel behaves when the channel is closed. This is key to making the generator work correctly.
  • Consider the case where start >= end. How should your generator handle this gracefully?
Loading editor...
go