Recap - File Parser
Part of the Object Oriented Programming section of Coddy's GO journey — lesson 58 of 107.
Challenge
EasyLet's build a configuration file parser that brings together all the error handling techniques from this chapter. Your parser will handle multiple failure scenarios with custom error types, sentinel errors, error wrapping, and proper cleanup using defer.
You'll organize your code across three files:
errors.go: Define your error infrastructure for the parser.Create two sentinel errors:
ErrEmptyContentwith message"file content is empty"ErrInvalidFormatwith message"invalid configuration format"
Create a custom error type
ParseErrorwithLine(int) andMessage(string) fields. ItsError()method should return:parse error at line [Line]: [Message]parser.go: Build the configuration parser with layered error handling.Create a
ConfigParserstruct with aparsedboolean field to track whether parsing completed successfully.Implement these methods:
NewConfigParser() *ConfigParser- creates a new parser withparsedset tofalseParseLine(lineNum int, line string) error- validates a single line. If the line doesn't contain an=character, return a*ParseErrorwith the line number and message"missing key-value separator". Otherwise returnnil.Parse(content string) error- the main parsing method that:- Returns
ErrEmptyContentif content is empty - Returns
ErrInvalidFormatif content doesn't contain at least one newline character - Splits content by newlines and calls
ParseLinefor each line (line numbers start at 1) - If
ParseLinereturns an error, wrap it with"parsing configuration: %w"and return - Sets
parsedtotrueon success and returnsnil
- Returns
Status() string- returns"ready"ifparsedis true, otherwise"not parsed"
main.go: Read configuration content and demonstrate comprehensive error inspection.Read two lines of input that together form the configuration content (join them with a newline). Use
deferto always print the parser's status at the end, regardless of success or failure.After attempting to parse, inspect any error using both
errors.Is()anderrors.As()to provide specific feedback based on what went wrong.
The following inputs will be provided:
- Line 1: First line of configuration content
- Line 2: Second line of configuration content
Handle errors with specific messages:
- If
errors.Is()findsErrEmptyContent: printError: No configuration provided - If
errors.Is()findsErrInvalidFormat: printError: Configuration must have multiple lines - If
errors.As()finds a*ParseError: print the full wrapped error, then on a new line printFix line [Line]: [Message] - If parsing succeeds: print
Configuration parsed successfully
After handling the result (success or error), the deferred status should print on a new line: Parser status: [status]
For example, given host=localhost and port=8080, your output should be:
Configuration parsed successfully
Parser status: readyAnd given host=localhost and invalid line, your output should be:
parsing configuration: parse error at line 2: missing key-value separator
Fix line 2: missing key-value separator
Parser status: not parsedTry it yourself
package main
import (
"bufio"
"errors"
"fmt"
"os"
)
func main() {
reader := bufio.NewReader(os.Stdin)
// Read first line of configuration
line1, _ := reader.ReadString('\n')
line1 = line1[:len(line1)-1] // Remove trailing newline
// Read second line of configuration
line2, _ := reader.ReadString('\n')
if len(line2) > 0 && line2[len(line2)-1] == '\n' {
line2 = line2[:len(line2)-1]
}
// Join the two lines with a newline to form the configuration content
content := line1 + "\n" + line2
// Create a new parser
parser := NewConfigParser()
// TODO: Use defer to always print the parser's status at the end
// Format: "Parser status: [status]"
// TODO: Attempt to parse the content
// TODO: Handle errors using errors.Is() and errors.As()
// - If errors.Is() finds ErrEmptyContent: print "Error: No configuration provided"
// - If errors.Is() finds ErrInvalidFormat: print "Error: Configuration must have multiple lines"
// - If errors.As() finds a *ParseError: print the full wrapped error,
// then on a new line print "Fix line [Line]: [Message]"
// - If parsing succeeds: print "Configuration parsed successfully"
_ = errors.Is // hint: use errors.Is for sentinel errors
_ = errors.As // hint: use errors.As for custom error types
_ = fmt.Println
}
All lessons in Object Oriented Programming
1Fundamentals of Go OOP
External FilesGo Workspace & ModulesPackages & ImportsExported vs Unexported NamesIntroduction to OOP in GoStructs as ClassesDefining Methods on StructsPointer vs Value ReceiversStruct InitializationConstructor FunctionsRecap - Simple Calculator4Interfaces
Introduction to InterfacesImplicit ImplementationInterface as ContractEmpty Interface (any)Type AssertionType SwitchInterface CompositionStringer & Error InterfacesRecap - Shape Calculator7Encapsulation
Exported vs Unexported FieldsPackage-Level EncapsulationGetter & Setter MethodsInformation Hiding in GoRecap - Student Records10Generics (Go 1.18+)
Introduction to GenericsType ParametersType ConstraintsGeneric StructsGeneric Methods WorkaroundRecap - Generic Collection2Types & Structs Deep Dive
Basic & Composite TypesCustom Type DefinitionsStruct TagsAnonymous StructsNested StructsZero Values & DefaultsRecap - Contact Book5Composition Over Inheritance
Why Go Has No InheritanceStruct Embedding BasicsMethod PromotionEmbedding Multiple StructsEmbedding vs AggregationShadowing Embedded MethodsRecap - Employee Hierarchy8Error Handling & OOP
The error InterfaceCustom Error TypesError Wrapping (fmt.Errorf)Sentinel Errorserrors.Is() and errors.As()Panic, Defer, and RecoverRecap - File Parser3Pointers & Memory
Pointer Basics in GoPointers to StructsPass by Value vs ReferenceThe new() FunctionGarbage Collection in GoRecap - Linked List Builder6Polymorphism in Go
Polymorphism via InterfacesDuck Typing in GoInterface Satisfaction RulesPolymorphic CollectionsDependency InjectionRecap - Payment Processor9Concurrency & OOP
Goroutines BasicsChannels & CommunicationBuffered vs Unbuffered ChanSelect Statementsync.Mutex & sync.RWMutexsync.WaitGroupThread-Safe Struct DesignRecap - Worker Pool