Rule of thumb:
If the behavior is intrinsically tied to a type → use a method receiver.
If it’s more of a package-level operation or helper → use a regular function.
package xfile
// xfile/file.go
package xfile
import (
"io"
"os"
)
type File struct {
Path string
Data []byte
}
func New(path string) *File {
return &File{Path: path}
}
// Pointer receiver: mutates f.Data
func (f *File) Load() error {
b, err := os.ReadFile(f.Path)
if err != nil {
return err
}
f.Data = b
return nil
}
func (f *File) Save() error {
return os.WriteFile(f.Path, f.Data, 0o644)
}
// Package-level helper: not tied to one File instance
func CopyFile(src, dst string) error {
in, err := os.Open(src)
if err != nil {
return err
}
defer in.Close()
out, err := os.Create(dst)
if err != nil {
return err
}
defer func() { _ = out.Close() }()
if _, err = io.Copy(out, in); err != nil {
return err
}
return out.Sync()
}
main.go
package main
import (
"fmt"
"github.com/you/project/xfile"
)
func main() {
// Using a constructor (preferred when there’s setup)
f := xfile.New("test.txt")
// Or: f := &xfile.File{Path: "test.txt"}
// Or: f := new(xfile.File); f.Path = "test.txt"
if err := f.Load(); err != nil {
fmt.Println("load error:", err)
return
}
// mutate and save
f.Data = append(f.Data, []byte("\nhello\n")...)
if err := f.Save(); err != nil {
fmt.Println("save error:", err)
return
}
// Use package-level utility
if err := xfile.CopyFile("test.txt", "test_copy.txt"); err != nil {
fmt.Println("copy error:", err)
}
}
No comments:
Post a Comment