#499 Golang reflect

2021-02-17
func Copy(dst, src Value) int
func DeepEqual(x, y any) bool
func Swapper(slice any) func(i, j int)
type ChanDir
    func (d ChanDir) String() string
type Kind
    func (k Kind) String() string
type MapIter
    func (iter *MapIter) Key() Value
    func (iter *MapIter) Next() bool
    func (iter *MapIter) Reset(v Value)
    func (iter *MapIter) Value() Value
type Method
    func (m Method) IsExported() bool
type SelectCase
type SelectDir
type SliceHeader
type StringHeader
type StructField
    func VisibleFields(t Type) []StructField
    func (f StructField) IsExported() bool
type StructTag
    func (tag StructTag) Get(key string) string
    func (tag StructTag) Lookup(key string) (value string, ok bool)

Type

  • func ArrayOf(length int, elem Type) Type
  • func ChanOf(dir ChanDir, t Type) Type
  • func FuncOf(in, out []Type, variadic bool) Type
  • func MapOf(key, elem Type) Type
  • func PointerTo(t Type) Type
  • func PtrTo(t Type) Type
  • func SliceOf(t Type) Type
  • func StructOf(fields []StructField) Type
  • func TypeOf(i any) Type

Value

  • func Append(s Value, x ...Value) Value
  • func AppendSlice(s, t Value) Value
  • func Indirect(v Value) Value
  • func MakeChan(typ Type, buffer int) Value
  • func MakeFunc(typ Type, fn func(args []Value) (results []Value)) Value
  • func MakeMap(typ Type) Value
  • func MakeMapWithSize(typ Type, n int) Value
  • func MakeSlice(typ Type, len, cap int) Value
  • func New(typ Type) Value
  • func NewAt(typ Type, p unsafe.Pointer) Value
  • func Select(cases []SelectCase) (chosen int, recv Value, recvOK bool)
  • func ValueOf(i any) Value
  • func Zero(typ Type) Value
  • func (v Value) Addr() Value
  • func (v Value) Bool() bool
  • func (v Value) Bytes() []byte
  • func (v Value) Call(in []Value) []Value
  • func (v Value) CallSlice(in []Value) []Value
  • func (v Value) CanAddr() bool
  • func (v Value) CanComplex() bool
  • func (v Value) CanConvert(t Type) bool
  • func (v Value) CanFloat() bool
  • func (v Value) CanInt() bool
  • func (v Value) CanInterface() bool
  • func (v Value) CanSet() bool
  • func (v Value) CanUint() bool
  • func (v Value) Cap() int
  • func (v Value) Close()
  • func (v Value) Comparable() bool
  • func (v Value) Complex() complex128
  • func (v Value) Convert(t Type) Value
  • func (v Value) Elem() Value
  • func (v Value) Equal(u Value) bool
  • func (v Value) Field(i int) Value
  • func (v Value) FieldByIndex(index []int) Value
  • func (v Value) FieldByIndexErr(index []int) (Value, error)
  • func (v Value) FieldByName(name string) Value
  • func (v Value) FieldByNameFunc(match func(string) bool) Value
  • func (v Value) Float() float64
  • func (v Value) Grow(n int)
  • func (v Value) Index(i int) Value
  • func (v Value) Int() int64
  • func (v Value) Interface() (i any)
  • func (v Value) InterfaceData() [2]uintptrDEPRECATED
  • func (v Value) IsNil() bool
  • func (v Value) IsValid() bool
  • func (v Value) IsZero() bool
  • func (v Value) Kind() Kind
  • func (v Value) Len() int
  • func (v Value) MapIndex(key Value) Value
  • func (v Value) MapKeys() []Value
  • func (v Value) MapRange() *MapIter
  • func (v Value) Method(i int) Value
  • func (v Value) MethodByName(name string) Value
  • func (v Value) NumField() int
  • func (v Value) NumMethod() int
  • func (v Value) OverflowComplex(x complex128) bool
  • func (v Value) OverflowFloat(x float64) bool
  • func (v Value) OverflowInt(x int64) bool
  • func (v Value) OverflowUint(x uint64) bool
  • func (v Value) Pointer() uintptr
  • func (v Value) Recv() (x Value, ok bool)
  • func (v Value) Send(x Value)
  • func (v Value) Set(x Value)
  • func (v Value) SetBool(x bool)
  • func (v Value) SetBytes(x []byte)
  • func (v Value) SetCap(n int)
  • func (v Value) SetComplex(x complex128)
  • func (v Value) SetFloat(x float64)
  • func (v Value) SetInt(x int64)
  • func (v Value) SetIterKey(iter *MapIter)
  • func (v Value) SetIterValue(iter *MapIter)
  • func (v Value) SetLen(n int)
  • func (v Value) SetMapIndex(key, elem Value)
  • func (v Value) SetPointer(x unsafe.Pointer)
  • func (v Value) SetString(x string)
  • func (v Value) SetUint(x uint64)
  • func (v Value) SetZero()
  • func (v Value) Slice(i, j int) Value
  • func (v Value) Slice3(i, j, k int) Value
  • func (v Value) String() string
  • func (v Value) TryRecv() (x Value, ok bool)
  • func (v Value) TrySend(x Value) bool
  • func (v Value) Type() Type
  • func (v Value) Uint() uint64
  • func (v Value) UnsafeAddr() uintptr
  • func (v Value) UnsafePointer() unsafe.Pointer

#498 Golang: 目录与文件操作汇总

2021-02-16

Golang os 中有很多文件系统相关的操作。

创建文件

// *os.File
file, err = os.Create("abc.txt")
if err != nil {
    log.Fatal(err)
}
defer file.Close()

删除文件

os.Remove()

读写文件

// ioutil
func ReadFile(filename string) ([]byte, error)
func WriteFile(filename string, data []byte, perm os.FileMode) error

// os
func Open(name string) (*File, error)
func OpenFile(name string, flag int, perm FileMode) (*File, error)
func ReadFileToString(filename string) ([]string, error) {
    file, err := os.Open(filename)
    if err != nil {
        return nil, err
    }
    defer file.Close()

    scanner := bufio.NewScanner(file)

    var data []string

    for scanner.Scan() {
        line := scanner.Text()
        data = append(data, line)
    }
    if err = scanner.Err(); err != nil {
        return nil, err
    }

    return data, nil
}

// 写

// 如果文件大于指定大小,则截断到指定大小
// 如果文件小于指定大小,则填充到指定大小
file, err := os.Truncate("abc.txt", 1024)
if err != nil {
    log.Fatal(err)
}

裁剪文件(Truncate)

file, err := os.OpenFile("abc.txt", os.O_RDWR, 0644)
if err != nil {
    log.Fatal(err)
}
defer file.Close()

err := file.Truncate(1024)
if err != nil {
    log.Fatal(err)
}
// os.Truncate(path string, size int64) error
err := os.Truncate("abc.txt", 1024)
if err != nil {
    fmt.Println("截断文件失败:", err)
}

创建目录(mkdir)

err := os.Mkdir(dirName, 0755) // 不能创建已经存在的目录
// err := os.MkdirAll(dirPath, 0755) // mkdir -p
if err != nil {
    fmt.Println("创建目录失败:", err)
    return
}

删除目录(rm)

err := os.Remove(dirName) // 不能删除非空目录
// err := os.RemoveAll(dirName) // rm -rf
if err != nil {
    fmt.Println("删除目录失败:", err)
    return
}

查看目录(List/Walk)

dirEntries, err := os.ReadDir(dirPath)
if err != nil {
    return err
}
for _, entry := range dirEntries {
    entryPath := filepath.Join(dirPath, entry.Name())
    if entry.IsDir() {
        fmt.Println("目录:", entryPath)
    } else {
        fmt.Println("文件:", entryPath)
    }
}
package main

import (
    "fmt"
    "os"
    "path/filepath"
)

func visit(path string, info os.FileInfo, err error) error {
    if err != nil {
        fmt.Println("访问目录失败:", err)
        return nil
    }
    if info.IsDir() {
        fmt.Println("目录:", path)
    } else {
        fmt.Println("文件:", path)
    }
    return nil
}

func main() {
    dirPath := "/path/to/directory"
    err := filepath.Walk(dirPath, visit)
    if err != nil {
        fmt.Println("遍历目录失败:", err)
        return
    }
}

查看文件信息(Stat)

fp.Stat()  // 句柄上执行 Stat 方法

fi, err = os.Stat(filepath)
// type FileInfo interface {
//  Name() string       // base name of the file
//  Size() int64        // length in bytes for regular files; system-dependent for others
//  Mode() FileMode     // file mode bits
//  ModTime() time.Time // modification time
//  IsDir() bool        // abbreviation for Mode().IsDir()
//  Sys() any           // underlying data source (can return nil)
// }

// FileMode -> fs.FileMode -> type FileMode uint32
// func (m FileMode) IsDir() bool
// func (m FileMode) IsRegular() bool
// func (m FileMode) Perm() FileMode
// func (m FileMode) String() string
// func (m FileMode) Type() FileMode
// const (
//  // The single letters are the abbreviations
//  // used by the String method's formatting.
//  ModeDir        FileMode = 1 << (32 - 1 - iota) // d: is a directory
//  ModeAppend                                     // a: append-only
//  ModeExclusive                                  // l: exclusive use
//  ModeTemporary                                  // T: temporary file; Plan 9 only
//  ModeSymlink                                    // L: symbolic link
//  ModeDevice                                     // D: device file
//  ModeNamedPipe                                  // p: named pipe (FIFO)
//  ModeSocket                                     // S: Unix domain socket
//  ModeSetuid                                     // u: setuid
//  ModeSetgid                                     // g: setgid
//  ModeCharDevice                                 // c: Unix character device, when ModeDevice is set
//  ModeSticky                                     // t: sticky
//  ModeIrregular                                  // ?: non-regular file; nothing else is known about this file

//  // Mask for the type bits. For regular files, none will be set.
//  ModeType = ModeDir | ModeSymlink | ModeNamedPipe | ModeSocket | ModeDevice | ModeCharDevice | ModeIrregular

//  ModePerm FileMode = 0777 // Unix permission bits
// )

// is exists
func IsNotExist(err error) bool
// 注意:这个方法只有在出现异常,并且异常是路径已存在导致的,才会返回 True
func IsExist(err error) bool

// is dir
if fi.IsDir() {
    ...
}

// is file
if fi.Mode().IsRegular() {
    ...
}

// readable

// writable

// executable

移动文件

os.Rename(src, dst)

复制文件

sourceFile, err := os.Open(sourceFilePath)
if err != nil {
    return err
}
defer sourceFile.Close()
destinationFile, err := os.Create(destinationFilePath)
if err != nil {
    return err
}
defer destinationFile.Close()
_, err = io.Copy(destinationFile, sourceFile)

创建链接

os.Link()
os.Symlink()

临时目录和临时文件

tempFile, err := os.CreateTemp("", "tmp*.txt")  // *os.File
tempFilePath := tempFile.Name()

tempDir, err := os.MkdirTemp("", "tmp") // string

权限

fp.Chmod()
fp.Chown()  // os.Getuid(), os.Getgid()

#497 修改 cmd 字体

2021-02-14

Windows CMD 太挫,中文字体选择少,XP, Win7 下只有点阵字体 (fixedsys) 和新宋体,Win10 字体又多了几个,但效果页不太好。
不过 Win10 的话,可能是半年前吧,微软新出来了一个 Windows Terminal 的虚拟终端,就现代化多了。现在我在 Windows 下(偶尔)一般都是用的新版 Terminal + PowerShell,听方便。
但如果由于 OS 版本等问题,离不开 cmd 的话,有两个方法,一个是使用第三方终端模拟器,比如 cmder;再一个就是想办法定制一下 cmd 的字体。
我在这里记录一下之前使用的一个方案失效地址(确认有效,不过好久都没有用了)。

#496 Golang io

2021-02-14

io, io/fs, io/util, os

find /usr/share/go-1.17/src/io/ -type f | grep -Fv _test.go
/usr/share/go-1.17/src/io/ioutil/testdata/hello
/usr/share/go-1.17/src/io/ioutil/tempfile.go
/usr/share/go-1.17/src/io/ioutil/ioutil.go
/usr/share/go-1.17/src/io/pipe.go
/usr/share/go-1.17/src/io/fs/fs.go
/usr/share/go-1.17/src/io/fs/readfile.go
/usr/share/go-1.17/src/io/fs/readdir.go
/usr/share/go-1.17/src/io/fs/sub.go
/usr/share/go-1.17/src/io/fs/stat.go
/usr/share/go-1.17/src/io/fs/walk.go
/usr/share/go-1.17/src/io/fs/glob.go
/usr/share/go-1.17/src/io/io.go
/usr/share/go-1.17/src/io/multi.go

方法

https://pkg.go.dev/io

相关方法

io.Reader / io.Writer

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

type Writer interface {
    Write(p []byte) (n int, err error)
}

stringsbytesbufioos.File 都是 io.Reader 的实现。

小技巧:利用类型断言检查是否实现指定接口

https://stackoverflow.com/a/25677274

var _ io.Reader = (*os.File)(nil)
// nil 可以转换成任意类型的空指针
// 这里将 nil 转换成 os.File 指针,再赋值给 io.Reader 类型

io/fs

func Glob(fsys FS, pattern string) (matches []string, err error)
func ReadFile(fsys FS, name string) ([]byte, error)
func ValidPath(name string) bool
func WalkDir(fsys FS, root string, fn WalkDirFunc) error

io/util 包 (原 ioutil)

1.6 以及之后新版本,iouitl 包依然保留,但是只是对 io 包的封装。

Package ioutil implements some I/O utility functions.
As of Go 1.16, the same functionality is now provided by package io or package os, and those implementations should be preferred in new code. See the specific function documentation for details.

  1. func NopCloser(r io.Reader) io.ReadCloser
  2. func ReadAll(r io.Reader) ([]byte, error)
  3. func ReadDir(dirname string) ([]fs.FileInfo, error)
  4. func ReadFile(filename string) ([]byte, error)
  5. func TempDir(dir, pattern string) (name string, err error)
  6. func TempFile(dir, pattern string) (f *os.File, err error)
  7. func WriteFile(filename string, data []byte, perm fs.FileMode) error
// grep -REv "^//" /usr/share/go-1.17/src/io/ioutil/tempfile.go
package ioutil

import (
        "os"
)

func TempFile(dir, pattern string) (f *os.File, err error) {
        return os.CreateTemp(dir, pattern)
}

func TempDir(dir, pattern string) (name string, err error) {
        return os.MkdirTemp(dir, pattern)
}
// grep -REv "^//" /usr/share/go-1.17/src/io/ioutil/ioutil.go
package ioutil

import (
        "io"
        "io/fs"
        "os"
        "sort"
)

func ReadAll(r io.Reader) ([]byte, error) {
        return io.ReadAll(r)
}

func ReadFile(filename string) ([]byte, error) {
        return os.ReadFile(filename)
}

func WriteFile(filename string, data []byte, perm fs.FileMode) error {
        return os.WriteFile(filename, data, perm)
}

func ReadDir(dirname string) ([]fs.FileInfo, error) {
        f, err := os.Open(dirname)
        if err != nil {
                return nil, err
        }
        list, err := f.Readdir(-1)
        f.Close()
        if err != nil {
                return nil, err
        }
        sort.Slice(list, func(i, j int) bool { return list[i].Name() < list[j].Name() })
        return list, nil
}

func NopCloser(r io.Reader) io.ReadCloser {
        return io.NopCloser(r)
}

var Discard io.Writer = io.Discard

引申

io 包是基础,提供了 Reader 和 Writer 接口。其他包则是实现这两个接口。

string 包:字符串 IO

相当于 Python io.StringIO

  • string.Reader

bytes 包:字节 IO

通过 []byte 模拟 io,相当于 Python io.BytesIO

  • bytes.Buffer (Reader + Writer)
  • bytes.Reader

buffio 包:缓冲 IO

就是加入了一个缓冲的功能,提升 IO 效率,减少直接系统调用。
也方便实现一些网络协议中的分包,比如 SMTP 协议中按换行切割。

  • bufio.Reader
  • bufio.Writer
package main

import (
    "bufio"
    "fmt"
    "os"
)

func main() {
    file, err := os.Open("test.txt")
    if err != nil {
        fmt.Println("无法打开文件:", err)
        return
    }
    defer file.Close()

    reader := bufio.NewReader(file)
    for {
        line, err := reader.ReadString('\n')
        if err != nil {
            // 文件结束或发生错误
            break
        }
        fmt.Print(line)
    }
}

os 包:系统 IO

  • os.File 文件类型
func Open(name string) (*File, error)
func OpenFile(name string, flag int, perm FileMode) (*File, error)

var Stdin = NewFile(uintptr(syscall.Stdin), "/dev/stdin")
var Stdout = NewFile(uintptr(syscall.Stdout), "/dev/stdout")
var Stderr = NewFile(uintptr(syscall.Stderr), "/dev/stderr")

net 包:网络 IO

网络编程的部分,这里就不继续展开了。

  • net.Conn 网络连接
func Pipe() (Conn, Conn)

func Dial(network, address string) (Conn, error)
func DialTimeout(network, address string, timeout time.Duration) (Conn, error)
func FileConn(f *os.File) (c Conn, err error)

func (d *Dialer) Dial(network, address string) (Conn, error)
func (d *Dialer) DialContext(ctx context.Context, network, address string) (Conn, error)

func FilePacketConn(f *os.File) (c PacketConn, err error)
func ListenPacket(network, address string) (PacketConn, error)

func DialIP(network string, laddr, raddr *IPAddr) (*IPConn, error)
func ListenIP(network string, laddr *IPAddr) (*IPConn, error)

func DialTCP(network string, laddr, raddr *TCPAddr) (*TCPConn, error)
func (l *TCPListener) Accept() (Conn, error)
func (l *TCPListener) AcceptTCP() (*TCPConn, error)

func DialUDP(network string, laddr, raddr *UDPAddr) (*UDPConn, error)
func ListenMulticastUDP(network string, ifi *Interface, gaddr *UDPAddr) (*UDPConn, error)
func ListenUDP(network string, laddr *UDPAddr) (*UDPConn, error)

func DialUnix(network string, laddr, raddr *UnixAddr) (*UnixConn, error)
func ListenUnixgram(network string, laddr *UnixAddr) (*UnixConn, error)
func (l *UnixListener) Accept() (Conn, error)
func (l *UnixListener) AcceptUnix() (*UnixConn, error)

#494 报任安书

2021-02-12

在网易云音乐中听《软件那些事》聊这篇文章聊了好多期,我也想说一说,不吐不快。
PS: 我有点看不惯那家伙的一些做派,所以就听了一期还是两期,可能《报任安书》还远没有讲完。
PS: 如果抛去上面说的这点,听的士司机(他自己说的)闲聊还是挺有意思。

#493 Golang SHA 函数

2021-02-12

哈希算法(hash)是一种将任意长度数据映射成固定长度数据的方法。有时也叫摘要算法。

有非常多不同的哈希算法,其中最常见的是 md5 和 sha (sha1/sha256/sha512)两种。Golang md5 在 2021/01/14, Go MD5 中已经写过了。这里就记录一下 Golang sha 的使用方法。

// crypto.sha1
func New() hash.Hash
func Sum(data []byte) [Size]byte {
    if boringEnabled {
        return boringSHA1(data)
    }
    var d digest
    d.Reset()
    d.Write(data)
    return d.checkSum()
}
func (d *digest) MarshalBinary() ([]byte, error)
func (d *digest) UnmarshalBinary(b []byte) error
func (d *digest) Reset()
func (d *digest) Size() int
func (d *digest) BlockSize() int
func (d *digest) Write(p []byte) (nn int, err error)
func (d *digest) Sum(in []byte) []byte
func (d *digest) checkSum() [Size]byte
func (d *digest) ConstantTimeSum(in []byte) []byte
func (d *digest) constSum() [Size]byte

// crypto.sha256
func New() hash.Hash
func New224() hash.Hash // sha224
func Sum224(data []byte) [Size224]byte
func Sum256(data []byte) [Size]byte

// crypto.sha512
func New() hash.Hash
func New384() hash.Hash
func New512_224() hash.Hash
func New512_256() hash.Hash
func Sum384(data []byte) [Size384]byte
func Sum512(data []byte) [Size]byte
func Sum512_224(data []byte) [Size224]byte
func Sum512_256(data []byte) [Size256]byte

用法都一样:

h := sha1.New()  // hash.Hash
io.WriteString(h, "His money is twice tainted:")
io.WriteString(h, " 'taint yours and 'taint mine.")
fmt.Printf("% x", h.Sum(nil))
h := sha1.New()
if _, err := io.Copy(h, f); err != nil {
    log.Fatal(err)
}
fmt.Printf("% x", h.Sum(nil))

hash.Hash 接口

type Hash interface {
    io.Writer
    Sum(b []byte) []byte
    Reset()
    Size() int
    BlockSize() int
}

函数

  • sha1.New() -> hash.Hash
  • sha1.Sum(data []byte) -> [Size]byte

  • sha256.New() -> hash.Hash

  • sha256.Sum256(data []byte) -> [Size]byte
  • sha256.New224() -> hash.Hash
  • sha256.Sum224(data []byte) -> [Size224]byte

  • sha512.New() -> hash.Hash

  • sha512.Sum512(data []byte) -> [Size]byte
  • sha512.New384() -> hash.Hash
  • sha512.Sum384(data []byte) -> [Size384]byte
  • sha512.New512_224() -> hash.Hash
  • sha512.Sum512_224(data []byte) -> [Size224]byte
  • sha512.New512_256() -> hash.Hash
  • sha512.Sum512_256(data []byte) -> [Size256]byte
package main

import (
    "crypto/md5"
    "crypto/sha1"
    "crypto/sha256"
    "crypto/sha512"
    "fmt"
    "hash/fnv"
    "io"
    "log"
    "os"
)

func main() {
    filepath := "go.mod"
    f, err := os.Open(filepath)
    if err != nil {
        log.Fatal(err)
    }
    defer f.Close()

    fi, err := f.Stat()
    fmt.Printf("%#v err:%#v\n", fi, err)
    data := make([]byte, fi.Size())
    n, err := f.Read(data)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("%d, %#v, err:%#v\n", n, data, err)

    {
        hash := fnv.New32a()
        hash.Write(data)
        result := hash.Sum32()
        fmt.Printf("FNV-1a 32-bit hash: %d\n\n", result)
    }

    {
        fmt.Printf("MD5    : %x\n", md5.Sum(data))
        fmt.Printf("Sha1   : %x\n", sha1.Sum(data))
        fmt.Printf("Sha256 : %x\n", sha256.Sum256(data))
        fmt.Printf("Sha512 : %x\n", sha512.Sum512(data))
    }

    {
        f.Seek(0, 0)
        hasher := md5.New()
        _, err = io.Copy(hasher, f)
        if err != nil {
            log.Fatal(err)
        }
        sum := hasher.Sum(nil)
        fmt.Printf("MD5 2  : %x\n", sum)
    }
}

#491 瑞典的福利制度

2021-02-10

认识的人家里有亲人在瑞典生活,之前在那边读书,后来在那边工作,再后来身体不好,病得停严重,无法工作了,只能继续留在那边,依靠那边的福利生活,据说不工作每个月也有不少钱,而且主要是医疗免费。
我听说之后,对那边的福利制度挺好奇,在网上查了一下,还真是 🐮