4
respostas

Scanf não funciona no loop

Queria saber porque o comando Scanf não funciona apropriadamente em um loop com for. Achei que estava tendo problemas no meu código pois assim que digitava um comando, ele retornava o valor 0 logo após executar a primeira vez, exemplo abaixo:

PS C:\Users\Colaborador\go\src\hello> go run hello.go
Olá, sr. Gustavo
Este programa está na versão 1.2
1 - Iniciar monitoramento
2 - Exibir logs
0 - Sair do programa
1
O comando escolhido foi 1
Monitorando...
Site: https://www.alura.com.br foi carregado com sucesso!
1 - Iniciar monitoramento
2 - Exibir logs
0 - Sair do programa
O comando escolhido foi 0
Saindo do programa...
PS C:\Users\Colaborador\go\src\hello>

Ao substituir o Scanf por Scan, funcionou normalmente. Alguém sabe explicar o porquê?

4 respostas

a sintaxe da função Scanf é diferente da Scan;

na função Scanf você tem: func fmt.Scanf(format string, a...interface{})( n int, err erro)

ja na Scan você tem: func fmt.Scan(a ...interface{} (n int, err erro)

format string: Estes são os diferentes formatos que são usados para cada elemento fornecido.

a… interface {}: Esses parâmetros recebem cada um dos elementos fornecidos.

Logo: var valor int Scan(&valor) Scanf("%d",&valor) torna-se necessario você apresentar o formato do valor que você vai receber no seu input

exemplo:

var nome string

fmt.Scanf("%d",&nome)

fmt.Println(nome)

Se seu Input for string mas seu formato dentro do Scanf é inteiro.

seu output será: 0 mesmo você informando na criação da variavel que ela é uma string

E se voce não declarar o formato variavel que você esta recebendo(acredito que seja o seu caso, mas se não for posta seu codigo)

fmt.Scanf(&nome)

dará erro por falta de argumentos na função que você esta utilizando.

obs: espero ter ajudado

Entendi a diferença entre Scan e Scanf no sentido da formatação que se utiliza, mas porque ao colocar em um loop, mesmo colocando a formatação correta, como %d para um número inteiro, o programa entende que é feito um novo input com o valor 0 ao final do loop? Porque ao meu ver, se o parâmetro da formatação é o problema, porque ela não atrapalha na primeira vez que é feito o input?

"o programa entende que é feito um novo input com o valor 0 ao final do loop", não, o programa não entende que é feito um novo input, ele não consegue interpretar o input que voce esta aplicando.

poste seu arquivo .go pra poder ver seu código

Eu entendo que ao não conseguir interpretar o input ele interpreta como zero e por isso sai do programa. O que não compreendo é porque que depois de eu fazer um input de 1, por exemplo, depois de executar o código, ele realizar um novo input que ele interpreta como 0. Segue código:

package main

import (
    "bufio"
    "fmt"
    "io"
    "io/ioutil"
    "net/http"
    "os"
    "strconv"
    "strings"
    "time"
)

const monitoramentos = 3
const delay = 5

func main() {

    exibeIntroducao()
    leSitesDoArquivo()

    for {
        exibeMenu()

        comando := leComando()

        switch comando {
        case 1:
            iniciarMonitoramento()
        case 2:
            fmt.Println("Exibindo logs...")
            imprimeLog()
        case 0:
            fmt.Println("Saindo do programa...")
            os.Exit(0)
        default:
            fmt.Println("Não conheço este comando")
            os.Exit(-1)
        }
    }

}

func exibeIntroducao() {
    nome := "Gustavo"
    versao := 1.2

    fmt.Println("Olá, sr.", nome)
    fmt.Println("Este programa está na versão", versao)
}

func exibeMenu() {
    fmt.Println("1 - Iniciar monitoramento")
    fmt.Println("2 - Exibir logs")
    fmt.Println("0 - Sair do programa")
}

func leComando() int {
    var comandoLido int
    fmt.Scanf("%d", &comandoLido)
    fmt.Println("O comando escolhido foi", comandoLido)

    return comandoLido
}

func iniciarMonitoramento() {
    fmt.Println("Monitorando...")
    sites := leSitesDoArquivo()

    for i := 0; i < monitoramentos; i++ {
        for _, site := range sites {
            testaSite(site)
        }
        fmt.Println("")
        time.Sleep(delay * time.Second)
    }

}

func testaSite(site string) {
    resp, err := http.Get(site)
    leSitesDoArquivo()

    if err != nil {
        fmt.Println("Ocorreu um erro:", err)
    }

    if resp.StatusCode == 200 {
        fmt.Println("Site:", site, "foi carregado com sucesso!")
        registraLog(site, true)
    } else {
        fmt.Println("Site:", site, "está com problemas. Status Code:", resp.StatusCode)
        registraLog(site, false)
    }
}

func leSitesDoArquivo() []string {
    var sites []string

    arquivo, err := os.Open("sites.txt")

    if err != nil {
        fmt.Println("Ocorreu um erro:", err)
    }

    leitor := bufio.NewReader(arquivo)
    for {
        linha, err := leitor.ReadString('\n')

        linha = strings.TrimSpace(linha)
        sites = append(sites, linha)

        if err == io.EOF {
            break
        }
    }

    arquivo.Close()

    return sites
}

func registraLog(site string, status bool) {
    arquivo, err := os.OpenFile("log.txt", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)

    if err != nil {
        fmt.Println("Ocorreu um erro:", err)
    }

    arquivo.WriteString(time.Now().Format("02/01/2006 15:04:05") + "-" + site + "-online: " + strconv.FormatBool(status) + "\n")

    arquivo.Close()
}

func imprimeLog() {
    arquivo, err := ioutil.ReadFile("log.txt")

    if err != nil {
        fmt.Println("Ocorreu um erro:", err)
    }

    fmt.Println(string(arquivo))
}

Eu alterei novamente na função do leComando() para poder testar, e segue com o mesmo problema. Só gostaria de entender o motivo de ao executar pela primeira vez funcionar, e aí, ao voltar para o menu, ele já colocar outro input sem eu digitar nada.