#503 使用 jq 命令解析 JSON 数据

2021-03-04

JSON Logo

jq 是我在命令行中解析 JSON 的一个常用工具,用起来非常顺手。

  • https://github.com/stedolan/jq
  • https://stedolan.github.io/jq/

用法

curl https://24pullrequests.com/users.json | jq

# 取第一个元素
curl https://24pullrequests.com/users.json | jq '.[0]'
# 取第一个元素的指定字段
curl https://24pullrequests.com/users.json | jq '.[0].nickname'

# 切片
curl https://24pullrequests.com/users.json | jq '.[:2]'

# 遍历
curl https://24pullrequests.com/users.json | jq '.[] | .nickname'

# 取字段
curl https://24pullrequests.com/users/changeworld.json | jq .nickname

# 取多个字段
curl https://24pullrequests.com/users/changeworld.json | jq '.nickname,.contributions_count'

# 获取列表长度
curl https://24pullrequests.com/users.json | jq length

# 列出 Keys
curl https://24pullrequests.com/users/changeworld.json | jq keys
curl https://24pullrequests.com/users/changeworld.json | jq "keys[]"
curl https://24pullrequests.com/users.json | jq ".[0] | keys[]"

# 列出 Keys 和 值类型
cat a.json | jq ".[0] | keys,map(type)"
cat a.json | jq ".[0] | to_entries | map([.key, (.value | type)])"
cat a.json | jq '.[0] | to_entries | map("\(.key) : \(.value|type)")[]'

还有很多更强大的用法,可以参考文档,我就会上面几个,在命令行中简单搜索 JSON 也够用了。

刚在文档中学会一招,重新组合 JSON:

curl https://24pullrequests.com/users/changeworld.json | jq '[.nickname, .organisations[].login]'
curl https://24pullrequests.com/users/changeworld.json | jq '{name:.nickname, orgs:[.organisations[].login]}'

👍🏻 Nice!!!

#502 Golang compress

2021-03-01
  • archive: 打包 (tar, zip)
    参考:《Golang archive
  • compress: 压缩 (bzip2, flate, gzip, lzw, zlib)

压缩 & 解压缩

import (
    "bytes"
    "compress/gzip"
    "io"
)

func compressData(data string) ([]byte, error) {
    var buf bytes.Buffer
    gz := gzip.NewWriter(&buf)
    _, err := gz.Write([]byte(data))
    if err != nil {
        return nil, err
    }
    if err := gz.Close(); err != nil {
        return nil, err
    }
    return buf.Bytes(), nil
}

func decompressData(compressedData []byte) (string, error) {
    r, err := gzip.NewReader(bytes.NewReader(compressedData))
    if err != nil {
        return "", err
    }
    defer r.Close()
    decompressedData, err := io.ReadAll(r)
    if err != nil {
        return "", err
    }
    return string(decompressedData), nil
}

压缩 & 解压缩 & 列出压缩包中的内容

import (
    "archive/zip"
)

// 压缩文件
func compressFile(zipFilename string, filenames ...string) error {
    zipFile, err := os.Create(zipFilename)
    if err != nil {
        return err
    }
    defer zipFile.Close()

    zipWriter := zip.NewWriter(zipFile)
    defer zipWriter.Close()

    for _, filename := range filenames {
        file, err := os.Open(filename)
        if err != nil {
            return err
        }
        defer file.Close()
        fi, err := file.Stat()
        if err != nil {
            return err
        }
        fileHeader, err := zip.FileInfoHeader(fi)
        if err != nil {
            return err
        }

        // 设置文件名(压缩后的文件名)
        fileHeader.Name = filename

        // 写入文件头部
        writer, err := zipWriter.CreateHeader(fileHeader)
        if err != nil {
            return err
        }

        // 复制文件内容到压缩包中
        _, err = io.Copy(writer, file)
        if err != nil {
            return err
        }
    }

    return nil
}

// 解压缩文件
func decompressFile(zipFilename, targetDir string) error {
    zipReader, err := zip.OpenReader(zipFilename)
    if err != nil {
        return err
    }
    defer zipReader.Close()

    for _, file := range zipReader.File {
        // 打开压缩包中的文件
        fileReader, err := file.Open()
        if err != nil {
            return err
        }
        defer fileReader.Close()

        // 创建目标文件
        extractedFilePath := fmt.Sprintf("%s/%s", targetDir, file.Name)
        extractedFile, err := os.Create(extractedFilePath)
        if err != nil {
            return err
        }
        defer extractedFile.Close()

        // 复制文件内容到目标文件
        _, err = io.Copy(extractedFile, fileReader)
        if err != nil {
            return err
        }
    }

    return nil
}

func listFilesInZip(zipFilename string) ([]string, error) {
    files := []string{}

    zipReader, err := zip.OpenReader(zipFilename)
    if err != nil {
        return files, err
    }
    defer zipReader.Close()

    for _, file := range zipReader.File {
        files = append(files, file.Name)
    }
    return files, nil
}

#501 Golang archive

2021-03-01

标准库中的 archive 支持 tarzip 两种打包格式。

https://en.wikipedia.org/wiki/Tar_(computing)

最常用的 tar 包:

func createTarArchive(sourceDir, targetFile string) error {
    file, err := os.Create(targetFile)
    if err != nil {
        return err
    }
    defer file.Close()

    tarWriter := tar.NewWriter(file)
    defer tarWriter.Close()

    return filepath.Walk(sourceDir, func(path string, info os.FileInfo, err error) error {
        if err != nil {
            return err
        }

        header, err := tar.FileInfoHeader(info, info.Name())
        if err != nil {
            return err
        }

        if err := tarWriter.WriteHeader(header); err != nil {
            return err
        }

        if !info.IsDir() {
            file, err := os.Open(path)
            if err != nil {
                return err
            }
            defer file.Close()

            _, err = io.Copy(tarWriter, file)
            if err != nil {
                return err
            }
        }

        return nil
    })
}

func extractTarArchive(sourceFile, targetDir string) error {
    file, err := os.Open(sourceFile)
    if err != nil {
        return err
    }
    defer file.Close()

    tarReader := tar.NewReader(file)
    for {
        header, err := tarReader.Next()
        if err == io.EOF {
            break
        }
        if err != nil {
            return err
        }
        targetPath := filepath.Join(targetDir, header.Name)
        if err := os.MkdirAll(filepath.Dir(targetPath), 0755); err != nil {
            return err
        }
        if header.Typeflag == tar.TypeReg {
            file, err := os.Create(targetPath)
            if err != nil {
                return err
            }
            defer file.Close()
            _, err = io.Copy(file, tarReader)
            if err != nil {
                return err
            }
        }
    }

    return nil
}

#500 Golang 数组 & 切片

2021-02-24

数组声明时可以使用 ... 当作长度,表示自动判断。
数组声明时,可以只初始化其中的部分值。

a := [...]int{2: 1, 4: 2} // [5]int{0, 0, 1, 0, 4}

b := [5]int{1, 2, 3} // [5]int{1, 2, 3, 0, 0}

基本操作

a := [...]int{1, 2, 3}
var b []int

// 新增
b = append(b, 1)
// 删除元素
s = append(s[:index], s[index+1:]...)

// 遍历
for i := range a {
    fmt.Println(a[i])
}
for index, value := range a {
    fmt.Printf("%v: %v", index, value)
}
for _, value := range a {
    fmt.Printf("%v", value)
}
for i := 0; i < len(array); i++ {
    fmt.Printf("value: %d\n", array[i])
}

// 判断元素是否存在/获取元素序号
func Index(target int, array []int) int {
    for i, v := range array {
        if target == v {
            return i
        }
    }
    return -1
}

示例

package main

import (
    "fmt"
    "reflect"
)

func main() {
    a := [5]int{1, 3, 5, 7, 9}
    fmt.Printf("%s\t%#v\n", reflect.TypeOf(a), a)
    // [5]int   [5]int{1, 3, 5, 7, 9}

    // array => slice
    b := a[:] // a[0:len(a)]
    fmt.Printf("%s\t%#v\n", reflect.TypeOf(b), b)
    // []int    []int{1, 3, 5, 7, 9}

    // slice => array
    // c := ([5]int)(b) // cannot convert b (type []int) to type [5]int
    c := (*[5]int)(b) // 切片只能转换成数组指针
    fmt.Printf("%s\t%#v\n", reflect.TypeOf(c), c)
    // *[5]int  &[5]int{1, 3, 5, 7, 9}

    // 用类型别名试试:
    type NumArr [5]int
    c2 := (*NumArr)(b)
    fmt.Printf("%s\t%#v\n", reflect.TypeOf(c2), c2)
    // *main.NumArr &main.NumArr{1, 3, 5, 7, 9}

    // 只能遍历赋值
    d := [5]int{}
    for index, v := range b {
        d[index] = v
    }
    fmt.Printf("%s\t%#v\n", reflect.TypeOf(d), d)

    // 通过 copy 的方法实现 slice2array
    e := [5]int{}
    copy(e[:], b) // return length of b
    fmt.Printf("%s\t%#v\n", reflect.TypeOf(e), e)
}

去重

func Unique(arr []int) []int {
    arrLen := len(arr) - 1

    for arrLen > 0 {
        for i := arrLen - 1; i >= 0; i-- {
            if arr[arrLen] == arr[i] {
                arr = append(arr[:i], arr[i+1:]...)
                break
            }
        }
        arrLen--
    }

    return arr
}

func UniqueOptimized(arr []int) []int {
    uniqueArr := make([]int, 0, len(arr))
    uniqueMap := make(map[int]struct{})

    for _, num := range arr {
        if _, ok := uniqueMap[num]; !ok {
            uniqueArr = append(uniqueArr, num)
            uniqueMap[num] = struct{}{}
        }
    }

    return uniqueArr
}

// BenchmarkUniqueOriginal-20           135           8658964 ns/op               0 B/op          0 allocs/op
// BenchmarkUniqueOptimized-20         3501            347027 ns/op          285402 B/op        208 allocs/op

可以看到,一个性能好一些(只用 4% 的时间),资源使用多一些。

使用反射

https://blog.csdn.net/youngwhz1/article/details/83026263

func SliceRemoveDuplicate(a interface{}) (ret []interface{}) {
    if reflect.TypeOf(a).Kind() != reflect.Slice {
        fmt.Printf("<SliceRemoveDuplicate> <a> is not slice but %T\n", a)
        return ret
    }
    va := reflect.ValueOf(a)
    for i := 0; i < va.Len(); i++ {
        if i > 0 && reflect.DeepEqual(va.Index(i-1).Interface(), va.Index(i).Interface()) {
            continue
        }
        ret = append(ret, va.Index(i).Interface())
    }
    return ret
}

func SliceInsert(s []interface{}, index int, value interface{}) []interface{} {
    rear := append([]interface{}{}, s[index:]...)
    return append(append(s[:index], value), rear...)
}

func SliceInsert2(s *[]interface{}, index int, value interface{}) {
    rear := append([]interface{}{}, (*s)[index:]...)
    *s = append(append((*s)[:index], value), rear...)
}

func SliceInsert3(s interface{}, index int, value interface{}) bool {
    if ps, ok := s.(*[]string); ok {
        if val, ok := value.(string); ok {
            rear := append([]string{}, (*ps)[index:]...)
            *ps = append(append((*ps)[:index], val), rear...)
            return true
        }
    } else if ps, ok := s.(*[]int); ok {
        if val, ok := value.(int); ok {
            rear := append([]int{}, (*ps)[index:]...)
            *ps = append(append((*ps)[:index], val), rear...)
        }
    } else if ps, ok := s.(*[]float64); ok {
        if val, ok := value.(float64); ok {
            rear := append([]float64{}, (*ps)[index:]...)
            *ps = append(append((*ps)[:index], val), rear...)
        }
    } else {
        fmt.Printf("<SliceInsert3> Unsupported type: %T\n", s)
    }
    return false
}

func SliceRemove(s []interface{}, index int) []interface{} {
    return append(s[:index], s[index+1:]...)
}

func SliceRemove2(s *[]interface{}, index int) {
    *s = append((*s)[:index], (*s)[index+1:]...)
}

func SliceRemove3(s interface{}, index int) bool {
    if ps, ok := s.(*[]string); ok {
        *ps = append((*ps)[:index], (*ps)[index+1:]...)
    } else if ps, ok := s.(*[]int); ok {
        *ps = append((*ps)[:index], (*ps)[index+1:]...)
    } else if ps, ok := s.(*[]float64); ok {
        *ps = append((*ps)[:index], (*ps)[index+1:]...)
    } else {
        fmt.Printf("<SliceRemove3> Unsupported type: %T\n", s)
        return false
    }
    return true
}

func SliceClear(s *[]interface{}) {
    *s = append([]interface{}{})
}

func SliceClear2(s *[]interface{}) {
    *s = (*s)[0:0]
}

func SliceClear3(s interface{}) bool {
    if ps, ok := s.(*[]string); ok {
        *ps = (*ps)[0:0]
        //*ps = append([]string{})
    } else if ps, ok := s.(*[]int); ok {
        *ps = (*ps)[0:0]
        //*ps = append([]int{})
    } else if ps, ok := s.(*[]float64); ok {
        *ps = (*ps)[0:0]
        //*ps = append([]float64{})
    } else {
        fmt.Printf("<SliceClear3> Unsupported type: %T\n", s)
        return false
    }
    return true
}

泛型实现

func Insert[S ~[]E, E any](s S, i int, v ...E) S {
    tot := len(s) + len(v)
    if tot <= cap(s) {
        s2 := s[:tot]
        copy(s2[i+len(v):], s[i:])
        copy(s2[i:], v)
        return s2
    }
    s2 := make(S, tot)
    copy(s2, s[:i])
    copy(s2[i:], v)
    copy(s2[i+len(v):], s[i:])
    return s2
}

内置方法 make

make(Type, Len, Cap) 可以用来为 slice, map, channel 三种类型初始化(类似:C 语言 (int *)malloc(5))。

这里就看 Slice 的情况。

s1 := make([]int, 5)

s2 := make([]int, 5, 10)
// s2[8] = 1 // panic: runtime error: index out of range [8] with length 5
s2 = append(s2, 1)

如果有预留空间,append 的时候可以不用重新分配内存并遍历赋值。
如果切片有扩容的需要,就最好采用 make 来初始化。

如果不指定容量,则切片的容量和长度将相等。

#499 Golang: 临时文件

2021-02-22
  1. 创建临时文件
  2. 使用编辑器编辑
  3. 获取内容
  4. 删除临时文件
package main

import (
    "bufio"
    "fmt"
    "io/ioutil"
    "log"
    "os"
    "os/exec"
)

func main() {
    // create a tmp file
    // ioutil.TempFile creates a temp file and opens the file for reading and writing
    // and returns the resulting *os.File (file descriptor).
    tmpFile, err := ioutil.TempFile(os.TempDir(), "todo-tmp-")
    if err != nil {
        log.Fatal("Cannot create temporary file", err)
    }
    // defer os.Remove(tmpFile.Name())
    defer tmpFile.Close()
    fmt.Println("Created File: " + tmpFile.Name())

    // choose editor by env var
    editor := os.Getenv("EDITOR")
    args := []string{}
    if editor == "" {
        editor = "vim"
        args = append(args, "--clean")
        fmt.Println("No EDITOR enviroment variable set, use " + editor)
    } else {
        fmt.Println("Using EDITOR enviroment variable: " + editor)
    }
    args = append(args, tmpFile.Name())
    fmt.Println("Opening file with " + editor + " with args: " + fmt.Sprint(args))

    // check the editor command is available
    // _, err = exec.LookPath(editor)
    // if err != nil {
    //  log.Fatal("Cannot find editor: " + editor)
    // }

    // call the editor
    cmd := exec.Command(editor, args...)
    cmd.Stdin = os.Stdin
    cmd.Stdout = os.Stdout
    cmd.Stderr = os.Stderr
    err = cmd.Run()
    if err != nil {
        log.Fatal("Cannot run editor: " + editor)
    }

    // read the file
    // data, err := ioutil.ReadFile(tmpFile.Name())
    // if err != nil {
    //  log.Fatal("Cannot read file: " + tmpFile.Name())
    // }
    tmpFile.Seek(0, 0)
    s := bufio.NewScanner(tmpFile)
    for s.Scan() {
        fmt.Println("Content:\n\n" + s.Text())
    }
    if err = s.Err(); err != nil {
        log.Fatal("error reading temp file", err)
    }
}

#498 Golang strings

2021-02-21
func Clone(s string) string                 //
func Compare(a, b string) int               // 比较
func Contains(s, substr string) bool        // 包含子字符串
func ContainsAny(s, chars string) bool      // 包含任意Char
func ContainsRune(s string, r rune) bool    // 包含Rune
func Count(s, substr string) int            // 计数
func Cut(s, sep string) (before, after string, found bool)
func EqualFold(s, t string) bool                    //
func Fields(s string) []string                      // 切割
func FieldsFunc(s string, f func(rune) bool) []string
func HasPrefix(s, prefix string) bool               // 前缀判断 startswith
func HasSuffix(s, suffix string) bool               // 后缀判断 endswith
func Index(s, substr string) int                    // 查找
func IndexAny(s, chars string) int                  // 查找Any
func IndexByte(s string, c byte) int                // 查找Byte
func IndexFunc(s string, f func(rune) bool) int     // 查找Func
func IndexRune(s string, r rune) int                // 查找Rune
func Join(elems []string, sep string) string        // 连接
func LastIndex(s, substr string) int                // 右查找
func LastIndexAny(s, chars string) int              // 右查找Any
func LastIndexByte(s string, c byte) int            // 右查找Byte
func LastIndexFunc(s string, f func(rune) bool) int // 右查找Func
func Map(mapping func(rune) rune, s string) string  //
func Repeat(s string, count int) string             // 重复
func Replace(s, old, new string, n int) string      // 替换
func ReplaceAll(s, old, new string) string          // 替换 = Replace -1
func Split(s, sep string) []string                  // 切割
func SplitAfter(s, sep string) []string             //
func SplitAfterN(s, sep string, n int) []string     //
func SplitN(s, sep string, n int) []string          //
func Title(s string) string                         //
func ToLower(s string) string                       // 转小写
func ToLowerSpecial(c unicode.SpecialCase, s string) string
func ToTitle(s string) string                       // Title
func ToTitleSpecial(c unicode.SpecialCase, s string) string
func ToUpper(s string) string
func ToUpperSpecial(c unicode.SpecialCase, s string) string
func ToValidUTF8(s, replacement string) string
func Trim(s, cutset string) string
func TrimFunc(s string, f func(rune) bool) string
func TrimLeft(s, cutset string) string
func TrimLeftFunc(s string, f func(rune) bool) string
func TrimPrefix(s, prefix string) string
func TrimRight(s, cutset string) string
func TrimRightFunc(s string, f func(rune) bool) string
func TrimSpace(s string) string
func TrimSuffix(s, suffix string) string

type Builder
    func (b *Builder) Cap() int
    func (b *Builder) Grow(n int)
    func (b *Builder) Len() int
    func (b *Builder) Reset()
    func (b *Builder) String() string
    func (b *Builder) Write(p []byte) (int, error)
    func (b *Builder) WriteByte(c byte) error
    func (b *Builder) WriteRune(r rune) (int, error)
    func (b *Builder) WriteString(s string) (int, error)

type Reader
    func NewReader(s string) *Reader
    func (r *Reader) Len() int
    func (r *Reader) Read(b []byte) (n int, err error)
    func (r *Reader) ReadAt(b []byte, off int64) (n int, err error)
    func (r *Reader) ReadByte() (byte, error)
    func (r *Reader) ReadRune() (ch rune, size int, err error)
    func (r *Reader) Reset(s string)
    func (r *Reader) Seek(offset int64, whence int) (int64, error)
    func (r *Reader) Size() int64
    func (r *Reader) UnreadByte() error
    func (r *Reader) UnreadRune() error
    func (r *Reader) WriteTo(w io.Writer) (n int64, err error)

type Replacer
    func NewReplacer(oldnew ...string) *Replacer
    func (r *Replacer) Replace(s string) string
    func (r *Replacer) WriteString(w io.Writer, s string) (n int, err error)

Builder

Reader

Replacer

参考资料与拓展阅读

#497 Python 弱引用

2021-02-20

垃圾回收

Garbage Collector, 简写: GC

Python 垃圾回收是简单基于引用计数

弱引用

在计算机程序设计中,弱引用与强引用相对,是指不能确保其引用的对象不会被垃圾回收器回收的引用。一个对象若只被弱引用所引用,则被认为是不可访问(或弱可访问)的,并因此可能在任何时刻被回收。一些配有垃圾回收机制的语言,如Java、C#、Python、Perl、Lisp等都在不同程度上支持弱引用。

一句话:弱引用不增加计数,对引用计数型 GC 友好一些

垃圾回收与循环引用的问题

import gc

IDS = {}

class A:
    def __del__(self):
        _id = id(self)
        print('A.__del__ %s: 0x%x' % (IDS[_id], _id))

OBJS = {i: A() for i in range(3)}
for i, obj in OBJS.items():
    _id = id(obj)
    IDS[_id] = f'OBJS[{i}]'
    print('%s: 0x%x' % (IDS[_id], _id))
OBJS[1].attr = OBJS[1]
print('1' * 50)
print('====> del OBJS[0]')
del OBJS[0]
print('2' * 50)
print('====> del OBJS[1]')
del OBJS[1]
print('3' * 50)
print('====> del OBJS[2]')
del OBJS[2]
print('4' * 50)
gc.collect()
import weakref

print()
print('=' * 50)
class B:
    def __init__(self, obj):
        self.attrs = [obj]
    def __del__(self):
        _id = id(self)
        print('B.__del__ %s: 0x%x' % (IDS[_id], _id))
a = A()
b = B(a)
a.xyz = b
IDS[id(a)] = 'a'
IDS[id(b)] = 'b'
del a, b  # do nothing
print('=' * 40)
gc.collect()  # will del a and b

print()
print('=' * 50)
class C:
    def __init__(self, obj):
        self.attrs = [weakref.ref(obj)]
    def __del__(self):
        _id = id(self)
        print('C.__del__ %s: 0x%x' % (IDS[_id], _id))
a = A()
c = C(a)
a.xyz = c
IDS[id(a)] = 'a'
IDS[id(c)] = 'c'
del a, c
print('=' * 40)
gc.collect()

标准库:weakref

  • class weakref.ref(object[, callback]) 回调
  • weakref.proxy(object[, callback])
  • weakref.getweakrefcount(object)
  • weakref.getweakrefs(object)
  • class weakref.WeakKeyDictionary([dict])
  • .keyrefs()
  • class weakref.WeakValueDictionary([dict])
  • .valuerefs()
  • class weakref.WeakSet([elements])

    Set class that keeps weak references to its elements. An element will be discarded when no strong reference to it exists any more.

  • class weakref.WeakMethod(method)
  • class weakref.finalize(obj, func, /, *args, **kwargs)
  • weakref.ReferenceType
  • weakref.ProxyType
  • weakref.CallableProxyType
  • weakref.ProxyTypes
import weakref

class Klass:
    pass

obj = Klass()
ref = weakref.ref(obj)
print(ref())
del obj
print(ref())  # None

obj = Klass()
p = weakref.proxy(obj)
print(p)
del obj
print(p)  # ReferenceError: weakly-referenced object no longer exists

参考资料与拓展阅读

#495 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

#494 修改 cmd 字体

2021-02-14

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