Go Quickstart
Get up and running with EiplGrader for Go in minutes.
Prerequisites
- Go 1.16+
- Python 3.7+ (for running EiplGrader)
- OpenAI API key (or compatible LLM API)
Installation
pip install eiplgrader
Basic Example
1. Generate Go Code
from eiplgrader.codegen import CodeGenerator
# Initialize the code generator for Go
api_key = "your-openai-api-key"
generator = CodeGenerator(api_key, client_type="openai", language="go")
# Generate code from a student's explanation
result = generator.generate_code(
student_response="that filters even numbers from a slice of integers",
function_name="filterEven",
gen_type="cgbg"
)
print("Generated code:")
print(result["code"][0])
Output:
func filterEven(numbers []int) []int {
var result []int
for _, num := range numbers {
if num%2 == 0 {
result = append(result, num)
}
}
return result
}
2. Test the Generated Code
from eiplgrader.tester import CodeTester
# Define test cases - Go REQUIRES explicit type annotations
test_cases = [
{
"parameters": {"numbers": [1, 2, 3, 4, 5, 6]},
"parameter_types": {"numbers": "[]int"}, # Go slice type
"expected": [2, 4, 6],
"expected_type": "[]int"
},
{
"parameters": {"numbers": [1, 3, 5, 7]},
"parameter_types": {"numbers": "[]int"},
"expected": [],
"expected_type": "[]int"
},
{
"parameters": {"numbers": []},
"parameter_types": {"numbers": "[]int"},
"expected": [],
"expected_type": "[]int"
}
]
# Create and run the tester
tester = CodeTester(
code=result["code"][0],
test_cases=test_cases,
function_name="filterEven",
language="go"
)
results = tester.run_tests()
print(f"Tests passed: {results.successes}/{results.testsRun}")
Go-Specific Features
Type Annotations are REQUIRED
Despite Go having type inference in the language, EiplGrader requires explicit types:
# CORRECT - with type annotations
test_case = {
"parameters": {"name": "Alice", "age": 25},
"parameter_types": {"name": "string", "age": "int"}, # Required!
"expected": "Alice is 25 years old",
"expected_type": "string" # Required!
}
# WRONG - missing type annotations
test_case = {
"parameters": {"name": "Alice", "age": 25},
"expected": "Alice is 25 years old"
# This will fail with: "Missing required type information"
}
Go Type Mappings
Generic Type | Go Type | Example |
---|---|---|
int | int | 42 |
double | float64 | 3.14 |
string | string | "hello" |
bool | bool | true |
List[int] | []int | []int{1, 2, 3} |
List[string] | []string | []string{"a", "b"} |
Automatic Import Management
The test harness automatically manages imports based on usage:
// These imports are added automatically when needed:
import "fmt" // For basic output
import "encoding/json" // For complex type output
import "os" // For error handling
Common Go Patterns
Slice Operations
result = generator.generate_code(
student_response="that returns unique elements from a slice",
function_name="unique"
)
test_cases = [
{
"parameters": {"items": [1, 2, 2, 3, 3, 3, 4]},
"parameter_types": {"items": "[]int"},
"expected": [1, 2, 3, 4],
"expected_type": "[]int"
}
]
String Manipulation
result = generator.generate_code(
student_response="that capitalizes the first letter of each word",
function_name="titleCase"
)
test_cases = [
{
"parameters": {"text": "hello world"},
"parameter_types": {"text": "string"},
"expected": "Hello World",
"expected_type": "string"
}
]
Map Operations
result = generator.generate_code(
student_response="that counts word frequency in a string",
function_name="wordFrequency"
)
test_cases = [
{
"parameters": {"text": "hello world hello"},
"parameter_types": {"text": "string"},
"expected": {"hello": 2, "world": 1},
"expected_type": "map[string]int"
}
]
Working with Structs
# Note: Struct handling is limited to basic types
result = generator.generate_code(
student_response="that calculates the total price from a list of prices and quantities",
function_name="calculateTotal"
)
test_cases = [
{
"parameters": {
"prices": [10.0, 5.0, 15.0],
"quantities": [2, 3, 1]
},
"parameter_types": {
"prices": "[]float64",
"quantities": "[]int"
},
"expected": 50.0,
"expected_type": "float64"
}
]
Multiple Return Values
Go supports multiple return values, but test cases check the first return value:
result = generator.generate_code(
student_response="that divides two numbers and returns quotient and remainder",
function_name="divmod"
)
# Test harness only checks the first return value
test_cases = [
{
"parameters": {"a": 17, "b": 5},
"parameter_types": {"a": "int", "b": "int"},
"expected": 3, # Only checking quotient
"expected_type": "int"
}
]
Error Handling Patterns
Go’s error handling is unique, but the test harness focuses on the primary return value:
# Generate code that might return an error
result = generator.generate_code(
student_response="that parses an integer from a string",
function_name="parseInteger"
)
# Test cases focus on successful cases
test_cases = [
{
"parameters": {"str": "123"},
"parameter_types": {"str": "string"},
"expected": 123,
"expected_type": "int"
}
]
In-Place Modifications
Go supports in-place modifications through slices:
# Mode 1: Modifies slice in-place
test_case = {
"parameters": {"nums": [3, 1, 4, 1, 5]},
"parameter_types": {"nums": "[]int"},
"expected": [1, 1, 3, 4, 5],
"expected_type": "[]int",
"inplace": "1" # Tests that nums is sorted in-place
}
Advanced Features
Type Conversions
result = generator.generate_code(
student_response="that converts a slice of strings to integers",
function_name="stringsToInts"
)
test_cases = [
{
"parameters": {"strings": ["1", "2", "3"]},
"parameter_types": {"strings": "[]string"},
"expected": [1, 2, 3],
"expected_type": "[]int"
}
]
Working with Runes
result = generator.generate_code(
student_response="that counts unicode characters in a string",
function_name="countRunes"
)
test_cases = [
{
"parameters": {"text": "Hello 世界"},
"parameter_types": {"text": "string"},
"expected": 8,
"expected_type": "int"
}
]
Output Format
Go uses different output formats based on the return type:
- Simple types (int, string, bool, float64): Direct fmt.Println
- Complex types (slices, maps): JSON encoding
// Simple type output
fmt.Println(result) // For int, string, etc.
// Complex type output
output, _ := json.Marshal(result)
os.Stdout.Write(output) // For slices, maps
Best Practices
- Always specify Go types:
# Use Go-specific type names "parameter_types": { "nums": "[]int", # not "List[int]" "value": "float64", # not "double" "data": "[]string" # not "List[string]" }
- Use idiomatic Go patterns:
// Generated code should use: // - range loops // - append for slices // - make for maps // - proper error handling
- Be aware of zero values:
# Go has zero values for all types test_cases = [ { "parameters": {"count": 0}, # Zero value for int "parameter_types": {"count": "int"}, "expected": 0, "expected_type": "int" } ]
- Slice vs Array:
# Always use slices for flexibility "[]int" # Slice (preferred) "[5]int" # Array (fixed size, rarely needed)
Common Gotchas
- nil slices vs empty slices:
# Both are handled correctly "expected": [] # Can match both nil and empty slices
- Map ordering:
# Maps are unordered, but JSON output is consistent "expected": {"a": 1, "b": 2} # Order doesn't matter
- String immutability:
// Strings are immutable in Go // Generated code should return new strings
- Interface types:
# Avoid interface{} in test cases # Use concrete types instead
Compilation and Execution
- Compilation:
go build -o output input.go
- Execution: Binary with embedded test values
- Package: Always uses
package main
Error Messages
Go provides clear compilation and runtime errors:
try:
results = tester.run_tests()
if not results.was_successful():
for result in results.test_results:
if not result["pass"]:
print(f"Test failed: {result['function_call']}")
# Common Go errors:
# - "undefined: functionName"
# - "cannot use x (type T) as type U"
# - "index out of range"
except Exception as e:
print(f"Error: {e}")
Next Steps
- Compare with Java Quickstart for static typing similarities
- Explore Haskell Quickstart for functional programming
- Learn about Test Case Format for complex types
- See Language Support for Go-specific details