Learn go and rust — IO reader through examples

Time:2021-6-30

IO operation is often encountered in our programming. Both languages provide general read method, which allows us to read data from the reader structure.

Go

//io/io.go
type Reader interface {
    Read(p []byte) (n int, err error)
}

//bytes/reader.go
type Reader struct {
    s        []byte
    i        int64 // current reading index
    prevRune int   // index of previous rune; or < 0
}

// Read implements the io.Reader interface.
func (r *Reader) Read(b []byte) (n int, err error) {
    if r.i >= int64(len(r.s)) {
        return 0, io.EOF
    }
    r.prevRune = -1
    n = copy(b, r.s[r.i:])
    r.i += int64(n)
    return
}

It can be seen that whether a type implements an interface in go language is not marked. As long as the function signature is the same, it can be said that the interface is implemented.

a.Read(b)It means to copy the data in a to B and modify the read coordinates in a.

A chestnut, for example

import (
    "bytes"
)

func main() {
    reader := bytes.NewReader([]byte{1, 2, 3})
    target := make([]byte, 5)
    fmt.Println(reader, target)
    reader.Read(target)
    fmt.Println(reader, target)
}
&{[1 2 3] 0 -1} [0 0 0 0 0]
&{[1 2 3] 3 -1} [1 2 3 0 0]

Rust

pub trait Read {
    fn read(&mut self, buf: &mut [u8]) -> Result<usize>;
    
impl Read for &[u8] {
    #[inline]
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        let amt = cmp::min(buf.len(), self.len());
        let (a, b) = self.split_at(amt);

        // First check if the amount of bytes we want to read is small:
        // `copy_from_slice` will generally expand to a call to `memcpy`, and
        // for a single byte the overhead is significant.
        if amt == 1 {
            buf[0] = a[0];
        } else {
            buf[..amt].copy_from_slice(a);
        }

        *self = b;
        Ok(amt)
    }

Different from the copy in go language, when it is read, the original data will be modified, leaving only the unread part.

Another chestnut

use std::io::Read;

fn main() {
    let mut reader: &[u8] = &[1, 2, 3][..];
    let target: &mut [u8] = &mut [0;5][..];
    reader.read(target);
    
    let empty_slice: &[u8] = &[][..];
    assert_eq!(reader, empty_slice);
    assert_eq!(target, &[1,2,3,0,0]);
}