Search code examples
stringgotypespanic

I've started a panic with my index out of range, and I can't get out


I'm writing this program to become comfortable with types (not objects!).

The basic premise is the user enters an animal name (cow, snake bird), then an action (eat, move, sound.) My code then looks it up and returns the value.

So, the user entry is suppose to be on ONE line separated by a " ". I use strings.Split.

I'm getting a "panic" notice when the user only enters a single char. I'm thinking this panic arises out of the compiler trying to "split" a single char.

TWO Questions: 1. Am I right? 2. How do I fix it?

package main

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

//Create our type object.
type animal struct {
    aType, eats, moves, sounds string
}

//Create our methods.
func (animal animal) info (querie string) {
    if querie == "eats" {
        fmt.Printf("The animal, %s , eats %s\n ", animal.aType, animal.eats)
    } else if querie == "moves" {
        fmt.Printf("The animal, %s , moves by  %s\n ", animal.aType, animal.moves)
    } else {
        fmt.Printf("The animal, %s , makes the sound %s\n ", animal.aType, animal.sounds)
    }
}

func main() {
    //Now create our animals

    cow := animal{aType:"cow", eats: "grass", moves: "walking", sounds: "moo"}
    bird := animal{aType:"bird", eats: "worms", moves: "flying", sounds: "peep"}
    snake := animal{aType:"snake", eats: "mice", moves: "slithering", sounds: "hiss"}
    // need a boolean to perpetuate our loop
    var flag bool = true

    for flag {
        fmt.Println("Remember enter X to exit")
        fmt.Printf(">please enter your (format: type & information) request -> ")
        scanner := bufio.NewScanner(os.Stdin)
        scanner.Scan()
        request := scanner.Text()

        //Capture user entered data

        typed := strings.Split(request, " ")[0]
        if typed == "X" {
            flag = false
            break
        }
        infoe := strings.Split(request, " ")[1]

        // contruct the logic tree. 

        if !((infoe == "eat") || (infoe == "move") || (infoe == "speak")) {
            switch typed {
            case "cow": 
                cow.info(infoe)

            case "snake": 
                snake.info(infoe)

            case "bird": 
                bird.info(infoe)
            default: 
                fmt.Println("I don't know about that animal.")          
            }
        } else {
            fmt.Printf("I don't have that informtion")
                break
            }
        }
    }

Solution

  • Create the scanner outside the loop to avoid discarding buffered data. Break when Scan() returns false. Check for and handle invalid input.

    scanner := bufio.NewScanner(os.Stdin)
    for {
        fmt.Println("Remember enter X to exit")
        if !scanner.Scan() {
            break
        }
        request := scanner.Text()
        parts := strings.Split(request, " ")
        if parts[0] == "X" {
            break
        }
        if len(parts) < 2 {
            fmt.Println("bad input")
            break
        }
    
        typed := parts[0]
        infoe := parts[1]
    
        ...