在golang中有个函数的定义如下:

func Trim(s, cutset string) string

按照官方文档的说明是:

Trim returns a slice of the string s with all leading and trailing Unicode code points contained in cutset removed.

stringslicecutset
package main

import (
	"fmt"
	"strings"
)

func main() {
	fmt.Println(strings.Trim("-----Hello, Gophers-----", "-"))
	fmt.Println(strings.Trim("!-!-!-Hello, Gophers-!-!-!-!", "!-"))
	fmt.Println(strings.Trim("!-!-!-Hello,-!-Go-!-!", "!-"))
}

得到的结果:

Hello, Gophers
Hello, Gophers
Hello,-!-Go

但是从正常理解来看,我认为的结果应该是:

Hello, Gophers
Hello, Gophers-!
Hello,-!-Go-!

那么问题到底出在哪里呢?

于是可以查看一下对应的源码:

// Trim returns a slice of the string s with all leading and
// trailing Unicode code points contained in cutset removed.
func Trim(s, cutset string) string {
	if s == "" || cutset == "" {
		return s
	}
	if len(cutset) == 1 && cutset[0] < utf8.RuneSelf {
		return trimLeftByte(trimRightByte(s, cutset[0]), cutset[0])
	}
	if as, ok := makeASCIISet(cutset); ok {
		return trimLeftASCII(trimRightASCII(s, &as), &as)
	}
	return trimLeftUnicode(trimRightUnicode(s, cutset), cutset)
}
if
	if as, ok := makeASCIISet(cutset); ok {
		return trimLeftASCII(trimRightASCII(s, &as), &as)
	}
as
type asciiSet [8]uint32

// makeASCIISet creates a set of ASCII characters and reports whether all
// characters in chars are ASCII.
func makeASCIISet(chars string) (as asciiSet, ok bool) {
	for i := 0; i < len(chars); i++ {
		c := chars[i]
		if c >= utf8.RuneSelf {
			return as, false
		}
		as[c/32] |= 1 << (c % 32)
	}
	return as, true
}

然后我们就可以开始准备一下恍然大悟了,直接和大家说结论吧,这个函数的功能有两个:

charsASCII8 * 32 = 256chars
as[c/32] |= 1 << (c%32)cuint32c%32

基于这个考虑我们可以编写这样的程序:

package main

import (
	"fmt"
	"unicode/utf8"
)

type asciiSet [8]uint32

func main() {
	makeASCIISet("ababab")
	makeASCIISet("ab")
	makeASCIISet("baba")

}


// makeASCIISet creates a set of ASCII characters and reports whether all
// characters in chars are ASCII.
func makeASCIISet(chars string) (as asciiSet, ok bool) {
	for i := 0; i < len(chars); i++ {
		c := chars[i]
		if c >= utf8.RuneSelf {
			return as, false
		}
		as[c/32] |= 1 << (c % 32)
	}
	fmt.Println(as)

	return as, true
}

然后就得到了这样的结果:

[0 0 0 6 0 0 0 0]
[0 0 0 6 0 0 0 0]
[0 0 0 6 0 0 0 0]
strings.Trim()
func trimLeftASCII(s string, as *asciiSet) string {
	for len(s) > 0 {
		if !as.contains(s[0]) {
			break
		}
		s = s[1:]
	}
	return s
}

// contains reports whether c is inside the set.
func (as *asciiSet) contains(c byte) bool {
	return (as[c/32] & (1 << (c % 32))) != 0
}
trimLeftASCIIasbreak

我们可以编写这个函数来验证一下:

package main

import (
	"fmt"
	"strings"
)

type asciiSet [8]uint32

func main() {
	fmt.Println(strings.Trim("---a--Hello, Gophers-----", "-a"))
}

其中的返回结果:

Hello, Gophers
strings.Trim