Golang Program to Create an Interface Named Reader That Defines a Read Method


In this go-language article, we are going to create an interface named Reader that defines the read method using direct interface implementation, and interface Composition along with examples to elaborate on the concept. A read method in go language is used to read the data from a source.

Syntax

sw.data

It represents accessing the data of a struct.

  • sw − it represents a variable, it can be a user defined struct variable or a pointer to struct.

  • data − it is the name of the field you want to access.

copy(p, sw.data[sw.pos:])

used to copy data from one slice to another.

  • copy − used to copy elements from a source slice to a designation slice.

  • p − it represents the designation slice.

  • data, pos − these the fields of the struct.

string.newReader()

This function is used to read data from a string using functions.

Algorithm

  • Declare the Reader interface with a Read method.

  • Implement the Reader interface by creating types with their own Read method implementations.

  • Write a function that operates on Reader objects, utilizing the Read method.

  • Create instances of the implementing types and assign them to variables of type Reader.

  • Invoke the function with different Reader objects to ensure proper functionality.

  • Test the program by running it and verifying that the Read method is invoked correctly.

  • Validate the flexibility of the Reader interface by adding new types that implement it and ensuring compatibility without modifying existing code.

Example 1

In this code example, we first define the Reader interface with the Read method.

Next, we implement the Read method for a type named StringWriter, which is a custom type that implements the Reader interface. The Read method reads bytes from the data field of the StringWriter and copies them into the provided byte slice.

package main

import (
   "fmt"
   "io"
   "strings"
)

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

type StringWriter struct {
   data string
   pos  int
}

func (sw *StringWriter) Read(p []byte) (n int, err error) {
   if sw.pos >= len(sw.data) {
      return 0, io.EOF
   }

   n = copy(p, sw.data[sw.pos:])
   sw.pos += n
   return n, nil
}

func main() {
   stringWriter := StringWriter{data: "Hello, World!"}
   
   buffer := make([]byte, 5)

   n, err := stringWriter.Read(buffer)
   if err != nil {
      fmt.Println("Error:", err)
   } else {
      fmt.Println("Bytes Read:", n)
      fmt.Println("Content:", string(buffer[:n]))
   }

   reader := strings.NewReader("Hello, Gophers!")
   n, err = reader.Read(buffer)
   if err != nil {
      fmt.Println("Error:", err)
   } else {
      fmt.Println("Bytes Read:", n)
      fmt.Println("Content:", string(buffer[:n]))
   }
}

Output

Bytes Read: 5
Content: Hello
Bytes Read: 5
Content: Hello

Example 2

In this code example, we first define the Reader interface with the Read method and the Closer interface with the Close method. Then, we create a new interface named ReadCloser that embeds both the Reader and Closer interfaces. We implement the Read and Close methods for a type named FileReader, which represents a file reader. The Read method reads bytes into the provided byte slice, and the Close method closes any resources used by the FileReader.

package main

import "fmt"

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

type Closer interface {
   Close() error
}

type ReadCloser interface {
   Reader
   Closer
}

type FileReader struct {
}

func (fr FileReader) Read(p []byte) (n int, err error) {
   return 0, nil
}

func (fr FileReader) Close() error {
   return nil
}

func main() {
   fileReader := FileReader{}

   var rc ReadCloser = fileReader

   buffer := make([]byte, 1024)
   n, err := rc.Read(buffer)
   fmt.Println("Bytes Read:", n, "Error:", err)
   err = rc.Close()
   fmt.Println("Close Error:", err)
}

Output

Bytes Read: 0 Error: <nil>
Close Error: <nil>

Conclusion

In this article, we examine how to create an interface called "Reader" together with a "Reader". By defining a link and using it with different models, we allow different objects to be used interchangeably, providing polymorphic behavior. The Reader interface provides a contract that guarantees that anything that uses it will have a "Read" method. This flexibility allows us to write more modular and extensible code.

Updated on: 20-Jul-2023

76 Views

Kickstart Your Career

Get certified by completing the course

Get Started
Advertisements