Maison >développement back-end >Golang >Boucle infinie io.Reader et fmt.Fscan

Boucle infinie io.Reader et fmt.Fscan

WBOY
WBOYavant
2024-02-09 17:45:191205parcourir

io.Reader 与 fmt.Fscan 无限循环

l'éditeur php Strawberry vous présentera le problème de boucle infinie de io.Reader et fmt.Fscan dans cet article. Lorsque vous utilisez la fonction fmt.Fscan pour lire une entrée, si le contenu lu ne correspond pas au format d'entrée, une boucle infinie se produira. Ce problème peut nous causer beaucoup de problèmes, mais avec quelques conseils et précautions, nous pouvons facilement résoudre ce problème. Ensuite, nous expliquerons en détail comment éviter les boucles infinies dans io.Reader et fmt.Fscan pour vous aider à mieux utiliser ces deux fonctions.

Contenu de la question

Je ne sais pas pourquoi, mais ma io.reader implémentation semble avoir une sorte de défaut ?

La documentation de

io.reader indique que renvoyer un nombre d'octets différent de zéro et une erreur non nulle devrait convenir :

it may return the (non-nil) error from the same call or return the error (and n == 0) from a subsequent call. an instance of this general case is that a reader returning a non-zero number of bytes at the end of the input stream may return either err == eof or err == nil. the next read should return 0, eof.
callers should always process the n > 0 bytes returned before considering the error err. doing so correctly handles i/o errors that happen after reading some bytes and also both of the allowed eof behaviors.

Mais cela ne fonctionne pas pour fmt.fscan et bloque le programme :

package main

import (
    "fmt"
    "io"
)

type byte byte

func (b byte) read(p []byte) (n int, err error) {
    if len(p) == 0 {
        return 0, io.errshortbuffer
    }
    p[0] = byte(b)
    return 1, io.eof
}

func main() {
    var n int
    b := byte('9')
    z, err := fmt.fscan(b, &n)
    fmt.println(n, z, err)
}

Bien sûr, si j'utilise io.eof seul, il renvoie zéro nombre d'octets :

type Byte struct {
    v   byte
    eof bool
}

func (b *Byte) Read(p []byte) (n int, err error) {
    if len(p) == 0 {
        return 0, io.ErrShortBuffer
    }
    if b.eof {
        return 0, io.EOF
    }
    p[0] = b.v
    b.eof = true
    return 1, nil
}

func main() {
    var n int
    b := Byte{v: '9'}
    z, err := fmt.Fscan(&b, &n)
    fmt.Println(n, z, err)
}

Y a-t-il un défaut dans mon implémentation d'origine ou ne dois-je pas me fier à ce comportement de journalisation spécifique de io.reader 的这一特定记录行为,并且在没有更多数据可供读取时始终单独返回 0, io.eof

解决方法

fmt.scanf 确实正确处理返回计数和 io.eof,但即使在 io.eof et renvoyer toujours 0, io.eof seul lorsqu'il n'y a plus de données à lire ?

Solution

io.readfull,而后者使用 io.readatleast,因此您将需要一个更完整的实现来处理重复读取。您可以通过使用跟踪 eof 的扩展版本来测试这一点,并在第一个 read 上返回 io.eof ,它仍然可以按预期与 fmt.fscanfmt.scanf gère correctement le nombre de retours et

, mais votre lecteur continue de renvoyer des valeurs même après

.

Étant donné que l'implémentation du scanner repose sur l'utilisation de io.readfull qui utilise

, vous aurez besoin d'une implémentation plus complète pour gérer les lectures en double. Vous pouvez tester cela en utilisant une version étendue qui suit eof et renvoie

lors de la première lecture et elle fonctionnera toujours avec

comme prévu.

io.readatleastExtraits clés de la documentation :

io 帮助程序需要自己解释 io.eof ,所以它们的调用者只能查找返回的实际数据,并且由于您的阅读器继续返回数据,它们将无限期地重复调用。通过在阅读器上重复调用 io.readall...il ne traite pas eof en lecture comme une erreur à signaler

L'erreur ne sera eof que si aucun octet n'a été lu. 🎜 🎜Parce que ces assistants io doivent interpréter 🎜 eux-mêmes, leurs appelants ne peuvent rechercher que les données réelles renvoyées, et puisque votre lecteur continue de renvoyer des données, ils seront appelés à plusieurs reprises indéfiniment. Cela peut être facilement démontré en appelant io.readall à plusieurs reprises sur le lecteur, renvoyant une autre valeur à chaque fois. 🎜
b := Byte('9')
fmt.Println(io.ReadAll(b))
fmt.Println(io.ReadAll(b))
fmt.Println(io.ReadAll(b))

// [57] <nil>
// [57] <nil>
// [57] <nil>
🎜🎜https://www.php.cn/link/ad6fff7b7be06acff1c63ced9f0da4ea🎜🎜

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer