Heim > Backend-Entwicklung > Golang > io.Reader und fmt.Fscan Endlosschleife

io.Reader und fmt.Fscan Endlosschleife

WBOY
Freigeben: 2024-02-09 17:45:19
nach vorne
1225 Leute haben es durchsucht

io.Reader 与 fmt.Fscan 无限循环

php-Editor Strawberry stellt Ihnen in diesem Artikel das Endlosschleifenproblem von io.Reader und fmt.Fscan vor. Wenn Sie die Funktion fmt.Fscan zum Lesen von Eingaben verwenden und der gelesene Inhalt nicht mit dem Eingabeformat übereinstimmt, kommt es zu einer Endlosschleife. Dieses Problem kann uns viel Ärger bereiten, aber mit ein paar Tipps und Vorsichtsmaßnahmen können wir es leicht lösen. Als Nächstes erklären wir ausführlich, wie Sie Endlosschleifen in io.Reader und fmt.Fscan vermeiden, damit Sie diese beiden Funktionen besser nutzen können.

Frageninhalt

Ich weiß nicht warum, aber meine io.reader Implementierung scheint einen Fehler zu haben?

In der Dokumentation für

io.reader heißt es, dass die Rückgabe einer Byteanzahl ungleich Null und eines Fehlers ungleich Null in Ordnung sein sollte:

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.
Nach dem Login kopieren

Aber das funktioniert nicht für fmt.fscan und stattdessen hängt das Programm:

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)
}
Nach dem Login kopieren

Natürlich, wenn ich io.eof allein verwende, wird die Byteanzahl Null zurückgegeben:

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)
}
Nach dem Login kopieren

Gibt es einen Fehler in meiner ursprünglichen Implementierung oder sollte ich mich nicht auf dieses spezielle Protokollierungsverhalten von io.reader 的这一特定记录行为,并且在没有更多数据可供读取时始终单独返回 0, io.eof

解决方法

fmt.scanf 确实正确处理返回计数和 io.eof,但即使在 io.eof verlassen und immer nur 0, io.eof zurückgeben, wenn keine Daten mehr zum Lesen vorhanden sind?

Workaround

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

zwar korrekt, aber Ihr Reader gibt auch nach

weiterhin Werte zurück.

Da die Scanner-Implementierung auf der Verwendung von io.readfull basiert, das

verwendet, benötigen Sie eine vollständigere Implementierung, um doppelte Lesevorgänge zu verarbeiten. Sie können dies testen, indem Sie eine erweiterte Version von eof verwenden, die

beim ersten Lesen verfolgt und zurückgibt und weiterhin wie erwartet mit

funktioniert.

io.readatleastWichtige Auszüge aus der Dokumentation:

:

io 帮助程序需要自己解释 io.eof ,所以它们的调用者只能查找返回的实际数据,并且由于您的阅读器继续返回数据,它们将无限期地重复调用。通过在阅读器上重复调用 io.readall...es behandelt eof in read nicht als zu meldenden Fehler

:

Der Fehler tritt nur dann auf, wenn keine Bytes gelesen wurden. 🎜 🎜Da diese io-Helfer sich selbst interpretieren 🎜 müssen, können ihre Aufrufer nur die tatsächlich zurückgegebenen Daten nachschlagen, und da Ihr Reader weiterhin Daten zurückgibt, werden sie auf unbestimmte Zeit wiederholt aufgerufen. Dies kann leicht demonstriert werden, indem io.readall wiederholt auf dem Reader aufgerufen wird und jedes Mal ein anderer Wert zurückgegeben wird. 🎜
b := Byte('9')
fmt.Println(io.ReadAll(b))
fmt.Println(io.ReadAll(b))
fmt.Println(io.ReadAll(b))

// [57] <nil>
// [57] <nil>
// [57] <nil>
Nach dem Login kopieren
🎜🎜//m.sbmmt.com/link/ad6fff7b7be06acff1c63ced9f0da4ea🎜🎜

Das obige ist der detaillierte Inhalt vonio.Reader und fmt.Fscan Endlosschleife. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Quelle:stackoverflow.com
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage