Menu
Coddy logo textTech

Borrowing System

Part of the Object Oriented Programming section of Coddy's GO journey — lesson 100 of 107.

challenge icon

Challenge

Easy

Let's build the borrowing system for our Library Management project! You'll create a Library struct that manages collections of books and users, with methods to handle checkout and return operations—complete with proper validation.

You'll organize your code across four files:

  • book.go: Your Book struct from the previous lesson with ID, Title, Author, ISBN, and Available fields. Include the NewBook constructor that initializes books as available.
  • user.go: Your User struct with ID, Name, Email, and BorrowedBooks (slice of book IDs). Include the NewUser constructor that initializes users with an empty borrowed list.
  • library.go: Create a Library struct that stores books and users in maps (keyed by their IDs). Build these components:
    • A NewLibrary constructor that initializes empty maps for books and users
    • An AddBook method that adds a book to the library
    • An AddUser method that adds a user to the library
    • A Borrow method that takes a user ID and book ID, validates the operation, marks the book unavailable, adds the book ID to the user's borrowed list, and returns an error if something goes wrong
    • A Return method that reverses the borrow process—marks the book available and removes it from the user's borrowed list

    Your Borrow method should return these errors:

    • user not found if the user ID doesn't exist
    • book not found if the book ID doesn't exist
    • book not available if the book is already borrowed

    Your Return method should return these errors:

    • user not found if the user ID doesn't exist
    • book not found if the book ID doesn't exist
    • book not borrowed if the book is already available
  • main.go: Bring everything together by creating a library, adding books and users, then processing borrow/return operations.

    Read the number of books, then for each book read its ID, title, author, and ISBN. Next, read the number of users, and for each user read their ID, name, and email. Then read the number of operations, where each operation is either borrow [userID] [bookID] or return [userID] [bookID].

    For each operation, print either OK if successful, or Error: [message] if it fails.

The following inputs will be provided:

  • Number of books, then each book's ID, title, author, ISBN (each on separate lines)
  • Number of users, then each user's ID, name, email (each on separate lines)
  • Number of operations, then each operation on a separate line

For example, given:

2
B001
The Go Programming Language
Alan Donovan
978-0134190440
B002
Clean Code
Robert Martin
978-0132350884
1
U001
Alice Smith
alice@library.com
4
borrow U001 B001
borrow U001 B001
return U001 B001
borrow U002 B001

Your output should be:

OK
Error: book not available
OK
Error: user not found

And given:

1
B100
Design Patterns
Gang of Four
978-0201633610
2
U001
Bob Jones
bob@email.com
U002
Carol White
carol@email.com
3
borrow U001 B100
borrow U002 B100
return U001 B100

Your output should be:

OK
Error: book not available
OK

And given:

1
B001
Go in Action
William Kennedy
978-1617291784
1
U001
Dave Miller
dave@test.com
2
return U001 B001
borrow U001 B999

Your output should be:

Error: book not borrowed
Error: book not found

Notice how the Library acts as the central coordinator—it validates all operations before modifying state, ensuring books and users stay synchronized. Using pointer receivers lets your methods modify the actual data stored in the maps!

Try it yourself

package main

import (
	"bufio"
	"fmt"
	"os"
	"strings"
)

func main() {
	reader := bufio.NewReader(os.Stdin)

	// Read number of books
	var numBooks int
	fmt.Scanln(&numBooks)

	// TODO: Create a new library

	// TODO: Read each book's details (ID, Title, Author, ISBN on separate lines)
	// and add them to the library
	for i := 0; i < numBooks; i++ {
		id, _ := reader.ReadString('\n')
		id = strings.TrimSpace(id)
		title, _ := reader.ReadString('\n')
		title = strings.TrimSpace(title)
		author, _ := reader.ReadString('\n')
		author = strings.TrimSpace(author)
		isbn, _ := reader.ReadString('\n')
		isbn = strings.TrimSpace(isbn)

		// TODO: Create book and add to library
	}

	// Read number of users
	var numUsers int
	fmt.Scanln(&numUsers)

	// TODO: Read each user's details (ID, Name, Email on separate lines)
	// and add them to the library
	for i := 0; i < numUsers; i++ {
		id, _ := reader.ReadString('\n')
		id = strings.TrimSpace(id)
		name, _ := reader.ReadString('\n')
		name = strings.TrimSpace(name)
		email, _ := reader.ReadString('\n')
		email = strings.TrimSpace(email)

		// TODO: Create user and add to library
	}

	// Read number of operations
	var numOps int
	fmt.Scanln(&numOps)

	// TODO: Process each operation
	// Format: "borrow [userID] [bookID]" or "return [userID] [bookID]"
	for i := 0; i < numOps; i++ {
		line, _ := reader.ReadString('\n')
		line = strings.TrimSpace(line)
		parts := strings.Split(line, " ")

		// TODO: Parse the operation and call appropriate method
		// Print "OK" on success or "Error: [message]" on failure
	}
}

All lessons in Object Oriented Programming