面向 Java 程序员的 Go 教程(五)
十二、关键包的比较
本章总结了几个关键的(常用的和广泛使用的)Java 包。如果可行,任何等效的 Go 包或函数都会被注明。由于 Go 和 Java 在它们的可用库中不是一一对应的,如果在标准的 Go 库中存在 Go 等价类,那么让每个 Java API(方法)与 Go 等价类完全匹配是不切实际的。
Java 语言包
Java 标准版 (JSE)有很多类型和方法的捆绑包。可用的方法(也称为 API)数以千计。Go 也有一套标准包,其类型和功能多达数百种。在这些包和类型的集合之间,库行为有很大的重叠,但组织结构(行为所在的包、类型或功能)没有重叠。
仅仅列出(对比描述)所有的 JSE 包和它们包含的方法类型就需要上百页。本书不会试图这样做。相反,它将列出 JSE 包和类型的精选子集。对于其中的一些,它将把关键 Java 类型可用的方法与任何 Go 等价物进行比较。
JRE 在java.lang包中有一些关键类型。下面的列表描述了任何 Go 环境的等价物。
接口摘要
-
可追加–可以追加到该类型的实例中;由 Go 片隐式支持。
-
auto closeable–可以通过使用资源进行尝试来关闭;没有直接的 Go 对应物。
-
char sequence–字符序列(如字符串或 StringBuilder);没有直接的 Go 对应物。
-
可克隆–实现
Object.clone();没有直接的 Go 对应物。 -
可比的–可以支持一个
compareTo()方法;没有直接的 Go 对应物;许多类型是隐式可比的。 -
iterable–可以迭代;一些 Go 类型:数组、切片、映射、通道。
-
可读–可以将字符读入缓冲区;
io.Reader为 UTF-8。 -
runnable——可以作为线程体运行;在 Go 中,任何函数都可以作为 goroutine 运行。
课程总结
-
布尔–布尔包装器;Go 系列不需要。
-
字节-字节包装器;Go 系列不需要。
-
字符-字符包装器;Go 系列不需要。
-
类–类的运行时视图;用于反射的特征;Go 有反射包。
-
class loader–在运行时加载/管理类;在 Go 中不需要,没有运行时类。
-
双层包装纸;Go 系列不需要。
-
枚举>–所有枚举类型的基本类型;在 Go 中不需要(
int是大多数 Go 枚举的基础)。 -
浮动——浮动包装;Go 系列不需要。
-
integer–Int 包装器;Go 系列不需要。
-
长长的包装纸;Go 系列不需要。
-
数学——一个有一套数学工具的类;Go 也有类似的
math包。 -
模块——模块的运行时视图;没有直接的 Go 对应物。
-
number——数值包装类型的超类;没有直接的 Go 对应物。
-
object–所有对象类型的超类;没有直接的 Go 对应物;
interface{}最接近。 -
包–包的运行时视图;没有直接的 Go 对应物。
-
进程——外部程序的运行时视图;一个 Go
exec包有类似的。 -
ProcessBuilder 运行外部程序的助手;一个 Go
exec包有类似的。 -
记录(新)-类似类的结构;Go 有
struct型。 -
运行时——管理运行程序的实用程序;Go 有一个
runtime包。 -
runtime permission——控制对类中函数的访问;Go 没有对等物。
-
security manager——控制对类中某个函数的访问的方法;Go 没有对等物。
-
短——短包装纸;Go 系列不需要。
-
StackTraceElement–描述一个调用堆栈元素;Go 也有类似的结构类型。
-
stack walker–抓取堆栈;没有直接的 Go 对应物;一个可以写。
-
strict Math——像一门数学课,有更多关于算法如何工作的规则;没有直接的 Go 对应物。
-
字符串–字符串类型;Go 有
string类型和strings、strconv和fmt包。 -
StringBuffer,StringBuilder–一个可变的字符串类型;Go 有一个
strings.Builder型。 -
系统-管理运行程序的实用程序;Go 有
runtime、time和io包。 -
线程——操作系统线程;没有直接的 Go 对应物;go 有 goroutines。
-
thread group–相关线程的集合;没有直接的 Go 对应物。
-
thread local–具有线程相关值的变量;没有直接的 Go 对应物;可以制造。
-
throwable——可以被抛出的类型;Go 有恐慌。
-
void–不等同于 Go;Go 函数可以不返回任何值(相对于 void)。
-
数学。big integer–不定精度整数;Go 属于 math.Int 类型。
-
数学。BigDecimal–不确定精度的十进制浮点值;Go 有数学。Float(不过是二进制,不是十进制)。
系统类:
静态字段摘要
-
PrintStream err – STDERR – Go
os.Stderr -
输入流输入 – STDIN – 转到
os.Stdin -
打印流出 – 标准输出 – 转到
os.Stdout
方法总结。如果没有提到,则没有直接的 Go 等价物。
-
array Copy(…)–复制一个数组;Go 运算符:数组[:]和
copy(..)函数 -
clearProperty(字符串键)–空系统属性
-
console()–访问操作系统控制台
-
currentTimeMillis()–获取当前纪元时间;转到
time.Now() -
exit(…)–查看运行时类;转到
os.Exit(...) -
GC()–查看运行时类;转到
runtime.GC() -
getenv()–获取所有环境值;转到
os.Environ() -
getenv(…)–获取单个环境值
-
Get logger(…)–获取一个命名的记录器;转到
log包 -
Get properties()–获取所有属性
-
getProperty(…)–获取一个命名的属性
-
getSecurityManager()–获取一个 JVM 安全管理器
-
identity hashcode(Object x)-获取对象的标识;在 Go 中,使用
&x 运算符 -
line separator()–获取一个操作系统行分隔符(例如,NL,CR+NL)
-
load(…),loadLibrary(…)–参见运行时类
-
nano time()–获取以纳秒为单位的运行时间;转到
time包 -
run finalization()–查看运行时类
-
set err(…)-更改 STDERR
-
setIn(...) – 更改 STDIN
-
setOut(…)–更改标准输出
-
setProperties(属性属性)–设置许多系统属性
-
setProperty(字符串键,字符串值)-设置系统属性
-
setSecurityManager(…)–设置 JVM 安全管理器
属性有社区实现。参见 github.com/magiconair/properties 使用类似 Java 属性的文件格式的例子。
运行时类:
-
addShutdownHook(…)–在 JVM 的出口运行一个线程;没有直接的 Go 对应物;Go 可以陷 OS 信号;Go 可以捕捉恐慌。
-
available processors()–获取 CPU(核心)计数;去
runtime.NumCPU()。 -
exec(...)–启动外部流程的方法系列;去
exec.Cmd。 -
Exit(…)–用 cleanup 退出 JVM 没有 Go 对应物;去罐大约。通过使用
os.Exit()。 -
free memory()–获取 JVM 可用的空闲内存;去
runtime.MemStats。 -
GC()–运行垃圾收集;去
runtime.GC ()。 -
Get runtime()–获取该类的 singleton 没有 Go 等价物。
-
halt(…)–不清理就退出 JVM 去
os.Exit(...)。 -
load(…),loadLibrary(…)–加载外部代码库;没有 Go 等价物。
-
maxMemory()–获取 JVM 可用的最大内存;去
runtime.MemStats。 -
removeShutdownHook(…)–移除出口挂钩;没有 Go 等价物。
-
run finalization()–强制对象终结;没有 Go 等价物。
-
total memory()–获取 JVM 使用的内存;去
runtime.MemStats。 -
version()–获取 JVM 版本;去
runtime.version()。
由于 Go 是在构建时生成的一个完整的可执行文件,所以不需要加载系统库。
Java IO 包
JRE 在java.io包中有一些关键类。下面的列表描述了任何 Go 环境的等价物。
界面摘要
-
可关闭–可以关闭。由 try with resources 使用;没有直接的 Go 对应物。
-
Data input–数据可以作为二进制编码值流读取。一些 Go 编码库提供了类似的功能。
-
Data output–数据可以作为二进制编码值流写入。一些 Go 编码库提供了类似的功能。
-
可外部化——可以使用非标准编码将数据读写到流中;没有直接的 Go 对应物。
-
file filter–选择与过滤器回调匹配的目录路径;没有直接的 Go 对应物。
-
filename filter–选择与过滤器回调匹配的文件名;没有直接的 Go 对应物。
-
可刷新–可以刷新(持久保存缓冲数据);一些 Go
io包接口提供了这个操作。 -
object input–可以读取 Java 序列化对象(DataInput 的超集);没有直接的 Go 对应物。
-
object output–可以编写 Java 序列化对象(DataOutput 的超集);没有直接的 Go 对应物。
-
serializable–通过默认编码将类型声明为可序列化;没有直接的 Go 对应物。
-
课程总结
-
BufferedInputStream–带缓冲区的输入流(字节数);Go
bufio包提供了类似的支持。 -
BufferedOutputStream–带缓冲区的输出流(字节数);Go
bufio包提供了类似的支持。 -
buffered reader–带缓冲区的输入编写器(在字符上);Go
bufio包提供了类似的支持。 -
buffered writer–带缓冲区的输出编写器(在字符上);Go
bufio包提供了类似的支持。 -
ByteArrayInputStream–从 byte[]读取;Go
io包提供了类似的支持。 -
ByteArrayOutputStream–在 byte[]上写入;Go
io包提供了类似的支持。 -
CharArrayReader–在 char[]上写入;Go
io包提供了类似的支持。 -
CharArrayWriter–在 char[]上写入;Go
io包提供了类似的支持。 -
控制台——标准输入、标准输出和标准错误的抽象。Go
io包提供了类似的支持。 -
data inputstream–读取二进制编码值的流;一些 Go 编码库提供了类似的功能。
-
data output stream–写入二进制编码值的流;一些 Go 编码库提供了类似的功能。
-
文件-对文件(或目录)的访问;Go
io和os包提供了类似的支持。 -
文件描述符-访问主机操作系统文件;Go
io和os包提供了类似的支持。 -
file inputstream–从文件中读取字节;Go
io和os包提供了类似的支持。 -
file output stream–将字节写入文件;Go
io和os包提供了类似的支持。 -
file permission–访问文件权限;Go
io和os包提供了类似的支持。 -
从文件中读取字符;Go
io和os包提供了类似的支持。 -
FileWriter–将字符写入文件;Go
io和os包提供了类似的支持。 -
InputStream–读取字节;Go
io和os包提供了类似的支持。 -
InputStreamReader–将字节输入转换为字符输入;Go
io和os包提供了类似的支持。 -
ObjectInputStream 读取序列化对象;没有直接的 Go 对应物。
-
object output stream–编写序列化对象;没有直接的 Go 对应物。
-
output stream–写入字节;Go
io和os包提供了类似的支持。 -
output streamwriter–将字符转换为字节。
-
PrintStream–格式化的字节输出;Go
fmt、io和os包提供了类似的支持。 -
PrintWriter–格式化字符输出;Go
fmt、io和os包提供了类似的支持。 -
RandomAccessFile–支持查找的文件;Go
io和os包提供了类似的支持。 -
阅读器-阅读字符;Go
fmt、io和os包提供了类似的支持。 -
SequenceInputStream–连接输入流;Go
io和os包提供了类似的支持。 -
stream tokenizer–标记流输入;Go
fmt、io和os包提供了类似的支持。 -
string reader–从字符串中读取字符;Go
fmt、io和os包提供了类似的支持。 -
作家——写人物;Go
io和os包提供了类似的支持。
Java 还有一个 NIO(新 IO)包,提供更高级的文件(例如,监控文件更改)和目录服务。这本书不会涵盖他们。Go 库有一些功能可以与一些 NIO 类提供的功能相媲美。
Java 文本包
JRE 在java.text包中有一些关键类。这个包提供了文本序列和消息格式的双向迭代。下面的列表描述了任何 Go 环境的等价物。一些 Go 扩展库和社区库提供了类似的支持。
界面摘要
-
AttributedCharacterIterator–对属性化文本序列进行双向迭代;没有直接的 Go 对应物。
-
character iterator——文本序列的双向迭代;没有直接的 Go 对应物;
utf8和utf16包有一定的功能。
课堂总结。除非特别说明,Go 没有直接的对等词。
-
注释–类似注释的文本属性。
-
attributed String–带注释的字符串。
-
双向——提供双向遍历规则。
-
break iterator–迭代不同类型的断点(单词、行等)。).
-
choice format–帮助格式化具有不同计数和复数的消息。
-
CollationElementIterator–根据区域设置规则遍历中的字符。
-
collation Key–基于区域设置的排序规则的键。
-
collator–基于区域设置的排序规则的基类。
-
compact number format–使数字变小的十进制格式。
-
date format–格式化日期和时间;Go 有一个类似功能的
time包。 -
decimal format–格式化十进制数字。
-
格式–各种格式类别的基本类别。
-
message format–用替换来格式化消息。
-
规格化器–规格化 Unicode 文本以帮助排序。
-
number format–数字格式化程序的基类。
-
RuleBasedCollator–规则表驱动程序整理器。
-
simple Date format–日期格式,具有可配置的日期和时间结构;Go 有一个类似功能的
time包。 -
StringCharacterIterator–迭代字符串中的字符。
注意 Go 的fmt包可以用来完成各种格式类型的一些任务。此外,在 Java String.format()和 Go fmt.Sprintf()中可以做格式化程序做的很多事情。
Java 时间包
JRE 在java.time包及其子包中有一些关键类。下面的列表描述了任何 Go 环境的等价物。
界面总结。Go 有time包可以解决其中的一些问题;大多是作为函数,而不是类型;这个函数只有一小部分出现在 Go 中。一些 Go 扩展库和社区库提供了类似的支持。
-
ChronoLocalDate–一些年表中的日期
-
ChronoLocalDateTime–某些年表中的日期时间(时间戳)
-
年表——一个日历系统(比如公历)
-
ChronoPeriod–一个时间段
-
ChronoZonedDateTime>–某些年表中的时区日期时间(时间戳)
-
纪元——一些年表中的有界范围(如公元前)
-
时间的;操作日期和时间的步骤如下
-
临时处理器
-
临时调整
-
临时账户
-
临时字段
-
风暴查询
-
临时的
课堂总结。Go 有如下一些行为的time包:主要是作为函数,而不是类型。
-
时钟-访问日期和时间
-
持续时间——一段时间;Go 具有持续时间类型
-
瞬间——一瞬间
-
local date–本地时区中的日期
-
local datetime–本地时区中的日期和时间(也称为时间戳)
-
local time–当地时区中的时间
-
月日-一个月中的一天
-
offset datetime–相对于 UTC 的日期和时间(即时间戳)偏移量
-
offset time–相对于 UTC 的时间偏移量
-
周期–以日历单位表示的持续时间
-
年–以年为单位的持续时间
-
year month–月份解析的瞬间
-
zoned DateTime–时区中的日期时间
-
datetime formatter–格式化日期时间
-
DateTimeFormatterBuilder–创建格式化程序
-
年表——年表(日历系统)的基础
-
年代学,年代学,等时学
-
日本年表,日本日期,日本
-
民国年表
-
ThaiBuddhistChronology,ThaiBuddhistDate
Java Util 包
JRE 在java.util包及其子包中有一些关键类。子包处理对象集合、遗留日期和时间处理、并发(线程)处理以及对对象的并发访问。下面的列表描述了任何 Go 环境的等价物。
界面总结。大多数没有直接的 Go 等价物。这个函数的大部分是由 Go 内置类型提供的。一些 Go 扩展库和社区库提供了类似的支持。
-
集合–e 类型的可迭代集合。
-
比较器–比较 t 类型的两个可比较对象。
-
deque–E 类双头队列;Go 切片已接近。
-
枚举–支持对 e 类型集合的正向迭代。
-
event listener–形式化事件侦听器的类型(回调)。
-
format table–可以格式化。
-
迭代器–支持对 e 类型集合的双向迭代。
-
列表–E 型可转位集合;Go 切片已接近。
-
地图,地图。条目–具有键 K 的类型 V 的关联集合;Go 地图已经很接近了。
-
队列–E 类队列(FIFO);Go 切片已接近。
-
set–一套 K 型;Go 地图已经很接近了。
-
sorted Map–带有排序关键字的地图。
-
sorted Set–用已排序的元素设置。
课堂总结。大多数没有直接的 Go 等价物。
-
abstract collection–以下是该类型的基本实现。
-
抽象列表
-
摘要图〔??〕
-
摘要队列〔??〕
-
抽象序列列表
-
抽象集
-
array deque【】阵列上的任何位置。
-
ArrayList–数组上的列表;Go 具有切片类型。
-
数组——数组访问的助手。
-
Base64。解码器–解码 Base64 字符串;Go 有一个
base64包。 -
Base64。编码器–对 Base64 字符串进行编码;Go 有一个
base64包。 -
比特集–比特的集合;Go 有一个
bits包。 -
日历–日历;Go 有一个
time包。 -
集合——集合的助手。
-
货币——一种货币。
-
日期——一个日期;Go 有一个
time包。 -
字典–一种基本的地图类型;Go 有一个
map型。 -
枚举按钮,v>
-
枚举集〔??〕
-
event list pro xy〔??〕
-
事件对象
-
格式程序
-
公历-西历。
-
HashMap–默认地图类型;Go 有一个地图类型。
-
哈希集合–默认集合类型。
-
哈希表–线程安全的哈希表。
-
identity hashmap–以对象标识为关键字的映射;Go 有一个 map[uintptr]类型。
-
linked hashmap–按照加法顺序迭代的地图。
-
linked hashset–按加法顺序迭代的集合。
-
linked List–由链表支持的列表。
-
语言环境–定义区分语言环境的设置和行为。
-
对象–所有引用类型的帮助。
-
可选的–空安全包装器。
-
优先级队列–按优先级排序的列表。
-
properties–具有持久形式的键/值集合。
-
扫描仪-读取格式化输入;去
fmt包。 -
simple time zone–一个时区实现。
-
堆栈–按后进先出顺序处理的列表。
-
String joiner–字符串助手。
-
string tokenizer–简单的字符串解析器;去
fmt包。 -
定时器——每隔一段时间驱动事件(回调)。
-
TimerTask–间隔驱动事件(回调)。
-
时区–时区的基准。
-
树形图–按关键字排序的地图。
-
TreeSet–按关键字排序的集合。
-
UUID-UUID 型;可从第三方获得。
-
vector–线程安全数组列表。
-
weak hashmap–不阻止键 GC 的映射。
-
界面摘要
-
阻塞队列–使用多个消费者线程进行排队。
-
blocking Queue–具有多个消费者线程的队列。
-
可调用–线程可以异步调用。
-
concurrent map–线程安全的高并发映射。
-
ConcurrentNavigableMap–线程安全的高并发映射。
-
执行者——多线程的管理者。
-
ExecutorService–管理多个线程。
-
流动。处理器–反应式编程流程处理器。
-
流动。发布者–反应式编程流程发布者。
-
流动。订户–反应式编程流程订户。
-
流动。订阅–反应式编程流订阅。
-
未来–可以在未来完成的异步任务。
-
条件–带锁的外部化条件;去
sync.Cond。 -
锁定-锁定对关键部分的访问;去
sync.Mutex。 -
读写锁–多读,单写锁。
课堂总结。上述接口的部分或全部实现。名称通常描述该功能。许多没有直接的 Go 等价物。LoadX和StoreX函数提供了类似 Java volatile修饰符的行为。
-
抽象执行服务
-
array blockqueue
-
可完成的未来〔??〕
-
并发哈希表
-
并发〔??〕
-
并发队列〔??〕
-
concurrentskiplistmap〔??〕
-
concurrents kiplistset〔??〕
-
CopyOnWriteArrayList
-
CopyOnWriteArraySet
-
CountDownLatch–等待计数;Go
sync.WaitGroup也差不多。 -
cyclic barrier–允许多个线程到达同步点。
-
delay Queue–延迟的队列(在特定时间使能)。
-
交换器–允许线程交换项目。
-
executors–创建多线程的管理器。
-
ForkJoinPool–在多线程中分而治之。
-
未来–可以在未来完成的异步任务。
-
linkblockgdeque〔??〕
-
linkeding queue〔??〕
-
link transfer queue
-
phaser–线程同步;增强型 CyclicBarrier 或 CountDownLatch。
-
优先级阻塞队列
-
ScheduledThreadPoolExecutor
-
信号量——对关键会话的基本控制访问;Go 有一个
lock包。 -
同步队列
-
线程池执行器
-
Atomic boolean——Atomic 允许线程间安全的读-修改-写循环;Go 有一个
async包。 -
atomic integer–Go 有一个
async包。 -
数组也能无锁
-
atomicintegerfieldupdater 更新程式
-
AtomicLong–Go 有一个
async包。 -
原子克隆阵列
-
atomiclongfieldupdater 更新程式
-
AtomicMarkableReference
-
atomic reference–Go 有一个
async包。 -
原子分离机阵列〔??〕
-
原子参考场更新
-
AtomicStampedReference
-
双累加器——累加器/加法器支持线程间的安全读-修改-写循环。
-
double adder–Go 有一个
async包。 -
long accumulator–Go 有一个
async包。 -
long adder–Go 有一个
async包。 -
锁定支持–锁定助手。
-
reentrant Lock–锁实现。
-
可重入读写锁
注意 Java 中的锁(和synchronized访问)是可重入的;同一个线程可以多次获取锁。在 Go 中,锁是不可重入的,试图重新获取锁的同一个 goroutine 会阻塞(死锁)自己。
十三、关键方法/函数比较
这个库调查并不打算作为程序员的参考,更多的是一个介绍。它将有一些有用的库函数的例子,应该可以帮助你在 Go 库中获得基本的能力。要更深入地理解提到的函数和任何省略的函数,请参阅在线 Go 软件包文档。该文档描述了每个包及其类型和它们提供的功能。也有一些例子。
Go 和 Java 库有很大的不同,因为 Java 是面向对象的,而 Go 不是。在 Java 中,许多函数是某个接收者类型的实例方法(隐含的this参数)。在 Go 中,它们通常是通用函数,将接收者类型作为第一个参数。这更像是 Java 中的static方法。例如,以将字符串转换为全大写的函数为例。
在 Java 中,这是
var uc = "some string".toUpperCase();
在 Go 中,这是
var uc = strings.ToUpper("some string")
这些函数的最大区别在于接收方传递给函数的方式。Java 实例方法可以被定义为
public class String {
public static String toUpperCase(String s) {
:
}
}
其访问方式如下
var uc = String.toUpperCase("some string")
因此,很像 Go 的风格,但是 Java 设计者选择不这样做。
Java 有很多很多的库函数。下面的表格将总结几个常用的 Java 函数,跨越几个 Java 包和类型,列出它们的 Java 和 Go 等价物(其行为可能不总是与 Java 函数完全一样)。有关 Go 函数的更完整列表,请参见“Go 库调查”部分。
静态 Java 方法和 Go 包顶层函数都是以句点(" . "),如表 13-1 至 13-8 所示。实例方法有一些变量(接收者)。
表 13-1
关键 Java 对象类方法
|Java 函数
|
Go 等效
|
Go 包
|
笔记
|
| --- | --- | --- | --- |
| o.toString() | o.String() | Many | 如果由接收类型定义 |
| o.wait() | c.Wait() | sync.Cond | |
| o.notify() | c.Signal() | sync.Cond | |
| o.notifyAll() | c.Broadcast() | sync.Cond | |
| o.hashCode | | | 没有 Go 等价物 |
| o.equals(x) | x ==1T5y | | Go 有一个运算符 |
表 13-2
关键 Java 运行时类方法
|Java 函数
|
Go 等效
|
Go 包
|
笔记
|
| --- | --- | --- | --- |
| add/removeShutdownHook | Signal | os | Go 只监听信号 |
| availableProcessors | NumCPU() | runtime | |
| exec(...) | Exec(...) | runtime | 许多变体 |
| exit(n) | | | 没有 Go 等价物 |
| freeMemory() | ReadMemoryStats() | runtime | |
| maxMemory() | ReadMemoryStats() | runtime | |
| gc() | GC() | runtime | |
| halt() | Exit(n) | runtime | |
| runFinalization() | | | 没有 Go 等价物 |
| version() | Version() | runtime | |
表 13-3
关键的 Java 系统类方法(运行时的重复被省略)
|Java 函数
|
Go 等效
|
Go 包
|
笔记
|
| --- | --- | --- | --- |
| .arraycopy(a,...) | a[:] | | Go 运算符 |
| .clear/set/getProperty``.getProperties() | | | 没有 Go 等价物 |
| .console | | | 没有 Go 等价物 |
| .currentTimeMillis | Now() | time | |
| .getenv() | Environ() | os | |
| .getLogger() | | log | Go 使用记录器方法 |
| .get/SetSecurityManager() | | | 没有 Go 等价物 |
| .identityHashCode() | | | 没有 Go 等价物 |
| .lineSeparator | | | Go 一般忽略 CR |
| .nanoTime() | Now() | time | |
| SetIn/Out/Err | | | 可以设置 os.Stdin/out/err 值 |
表 13-4
关键 Java 字符串类方法
|Java 函数
|
Go 等效
|
Go 包
|
笔记
|
| --- | --- | --- | --- |
| s.substr(s,e) | s[s:e] | | Go 运算符 |
| s.charAt(i) | s[i] | | Go 运算符 |
| s.indexOf(s2) | .Index(s, o) | strings | |
| s.lastIndexOf(s2) | | strings | |
| s.indexOf(c) | | strings | |
| s.lastIndexOf(c) | | strings | |
| s.toUpperCase() | .ToUpper(s) | strings | |
| s.toLowerCase() | .ToLower(s) | strings | |
| s.toCharArray() | []byte(s) | | 转到转换 |
| s.length() | len(s) | | 内置 |
| s.compareTo(o) | s op o | | Go 运算符:< <= == != > >= |
| s.startsWith(s2) | .HasPrefix(s1, s2) | strings | |
| s.endsWith(s2) | .HasSuffix(s1, s2) | strings | |
| s.contains(s2) | .Index(s,s2) >= 0 | strings | |
| s1 + s2 | s1 + s2 | | Go 运算符 |
| .join(delim,s...) | .join(delim,s...) | strings | |
| s.getBytes() | []byte(s) | | 转到转换 |
| s.matches(s1) | .matches(s, s1) | regex | |
| s.repeat(n) | .Repeat(s, n) | strings | |
| s.replace(c1,c2) | | | 没有直接的对等物 |
| s.replace(s1,s2) | .ReplaceAll(s, s1, s2) | strings | |
| s.replaceAll(p,s2) | | regex | |
| s.replaceFirst(p,s2) | | regex | |
| | .Split(s, s2) | strings | |
| | .Split(s, s2, n) | | |
| s.split(p) | | | 没有直接的对等物 |
| s.split(p,n) | .Split(s, n) | regex | |
| s.trim()``s.strip()``s.stripLeading()``s.stripTrailing() | .TrimSpaces(s) | strings | |
| s.substring(p)``s.substring(p,e)``s.substring(0,e)``s.substring(0,s.length()) | s[p:]``s[p:e]``s[:e]``s[:] | | Go 运算符 |
| .valueOf(x)``.format(f, ...) | .Sprintf("%v",x)``.Sprintf(f,...) | fmt | |
表 13-5
关键 Java StringBuilder 类方法
|Java 函数
|
Go 等效
|
Go 包
|
笔记
|
| --- | --- | --- | --- |
| sb.append(o) | b.Write``String(s) | strings.``Builder | |
| sb.length() | b.Size() | strings.``Builder | |
表 13-6
关键 Java 列表接口方法
|Java 函数
|
Go 等效
|
Go 包
|
笔记
|
| --- | --- | --- | --- |
| l.add(x) | append(s,x) | | 内置 |
| l.size() | len(l) | | 内置 |
| l.get(i) | l[i] | | Go 运算符 |
| l.set(I, x) | l[i] = x | | Go 运算符 |
表 13-7
关键的 Java Map 接口方法
|Java 函数
|
Go 等效
|
Go 包
|
笔记
|
| --- | --- | --- | --- |
| m.put(k,v) | m[k] = v | | Go 运算符 |
| m.size() | len(m) | | 内置 |
| m.get(k) | m[k] | | 内置缺失测试 |
表 13-8
关键 Java PrintWriter 类方法
|Java 函数
|
Java 类型
|
Go 等效
|
Go 包
|
笔记
|
| --- | --- | --- | --- | --- |
| pw.println(o) | Print``Writer | w.Write(o)``w.Write('\n') | io.Writer | |
有些类型有一个等同于 equals 的方法。
十四、Go 包调查
本章包含几个 Go 软件包的简要介绍。接下来的其他章节将更详细地讨论选择包。
使用 Go 访问文件
Go 和 Java 有所不同的一个常用领域是访问文件和目录。Java 的设计比 Go 更倾向于将文件访问抽象化。Java 提供了多种访问模式:
-
字节/字符流-文件看起来像字节或字符序列。
-
字节/字符通道–支持块模式访问;面向随机和异步访问;可以跨进程共享内存。
-
高级文件操作抽象,如复制文件或遍历目录树。
Go 提供了不太抽象但通常等价的访问,特别是对于流风格的操作。Go access 类似于 Unix 风格的文件处理。存在与 Unix 文件 API 非常匹配的 API。文件几乎总是被视为字节序列。Go 还提供了与 Unix APIs 几乎完全匹配的低级 API。
这些差异体现在 Java 和 Go APIs 的风格上。
例如,使用基本的 Java 流,可以复制这样一个文件:
public static long copyFile(String fromPath, String toPath)
throws IOException {
try (var bis = new BufferedInputStream(new FileInputStream(
new File(fromPath)))) {
try (var bos = new BufferedOutputStream(new FileOutputStream(
new File(toPath)))) {
return copyContent(bis, bos);
}
}
}
注意两个 try 语句可以合并成一个 try 语句:
public static long copyFile(String fromPath, String toPath)
throws IOException {
try (var bis = new BufferedInputStream(new FileInputStream(
new File(fromPath)));
var bos = new BufferedOutputStream(new FileOutputStream(
new File(toPath)))) {
return copyContent(bis, bos);
}
}
文件数据由复制
private static long copyContent(InputStream is, OutputStream os)
throws IOException {
var total = 0L;
var buf = new byte[N]; // N at least several KB
for (;;) {
var count = is.read(buf, 0, buf.length);
if (count == 0)
break;
os.write(buf);
total +=buf.length;
}
return total;
}
或者更简洁地说,通过使用 JRE 库等价物:
private static long copyContent(InputStream is, OutputStream os)
throws IOException {
return is.transferTo(os);
}
在 Go 中,这可能是
func CopyFile(fromPath, toPath string) (count int64, err error) {
var from, to *os.File
if from, err = os.Open(fromPath); err != nil {
return
}
defer from.Close()
if to, err = os.Create(toPath)
err != nil {
return
}
defer to.Close()
count, err = io.Copy(to, from)
return
}
因此,我们看到 Go 倾向于更直接地使用文件类型。这是因为File类型实现了io.Reader和io.Writer接口。我们还看到了如何用多个defer语句替换try语句。
Go 和 Java 都可以处理目录。例如,要输出从某个根目录开始的所有文件及其大小,在 Java 中可以这样做(使用 Java 流):
public static void PrintAllNames(String path) throws IOException {
try (var walk = Files.walk(Paths.get(path))) {
walk.filter(Files::isRegularFile).
map(p -> String.format("%s %d", p, p.toFile().length())).
forEach(System.out::println);
}
}
这样叫:
PrintAllNames(".")
在 Go 中,这可能是
var printName = func(path string, info os.FileInfo, xerr error) error{
if xerr != nil { // exit fast if entered with an error
return xerr
}
if info.Mode().IsRegular() {
fmt.Println(path, info.Size())
}
return nil
}
func PrintAllNames(path string) (err error) {
err = filepath.Walk(path, printName)
return
}
这样叫:
PrintAllNames(".")
Java 代码使用 Java 的函数流和方法引用/lambdas(作为回调)。Go 代码使用了一个回调函数。在这两种情况下,回调只选择文件并格式化数据。
压缩服务
本节概述了一些用于压缩和归档的 Go 包。
存档包
与 Java 一样,Go 提供了读写归档文件的功能。Java 专注于 ZIP 存档格式。Go 也支持 TAR 格式。每种格式都有子程序包:
-
tar–读写 tar 档案 -
zip–读写 ZIP 档案
archive/tar包提供了这些类型:
-
type Format–代表支持的 tar 格式 USTAR、PAX 和 GNU 的枚举
-
type Header–表示 tar 文件中的标题
-
类型读取器–提供对 tar 的读取权限
-
类型编写器—提供对 tar 的写访问权限
标题类型有以下方法:
-
func FileInfoHeader(fi os。FileInfo,链接字符串)(*Header,error)–从文件信息创建标题
-
func (h *Header) FileInfo() os。FileInfo–从文件头获取文件信息
读取器类型有以下方法:
-
func NewReader(r io。读者)*读者–成为读者
-
func (tr *Reader) Next() (*Header,error)-前进到下一个文件
-
func(tr * Reader)Read(b[]byte)(int,error)-从文件中读取数据
编写器类型有以下方法:
-
func NewWriter(w io。作家)*作家–成为作家
-
func (tw *Writer) Close()错误–刷新并关闭文件
-
func (tw *Writer) Flush()错误–写入缓冲数据
-
func(tw * Writer)Write(b[]byte)(int,error)–带缓冲写入数据
-
func(tw * Writer)Write Header(HDR * Header)错误–写入文件头
archive/zip包提供了这些类型:
-
type Compressor–将编写器转换为压缩编写器/关闭器的功能
-
类型解压缩器–将阅读器转换为解压缩阅读器/关闭器的功能
-
类型文件–表示压缩文件;包装文件头
-
type file header–表示 zip 文件中的文件;有许多有用的领域
-
ReadCloser 标牌-可读取和关闭
-
类型阅读器-可以阅读
-
打字者-可以书写
文件类型有这样的方法:
- func (f *File) Open() (io。ReadCloser,error)–打开压缩文件
FileHeader 类型有以下方法:
-
func FileInfoHeader(fi os。FileInfo) (*FileHeader,error)-创建文件头
-
func (h *FileHeader) FileInfo() os。文件关于
-
func (h *FileHeader) ModTime()时间。时间
-
func(h * file header)mode()(OS 模式)。FileMode)
-
func(h * file header)setmodtime(t time)。时间)
-
func(h * file header)set mode(OS 模式)。FileMode)
ReadCloser 类型有以下方法:
-
func OpenReader(名称字符串)(*ReadCloser,错误)–访问压缩条目
-
func (rc *ReadCloser) Close()错误–关闭压缩条目
读取器类型有这个方法:
- func NewReader(r io。ReaderAt,size int64) (*Reader,error)-创建一个阅读器
编写器类型有以下方法:
-
func NewWriter(w io。作家)*作家–成为作家
-
func (w *Writer) Close()错误–关闭压缩条目
-
func (w *Writer) Create(名称字符串)(io。编写器,错误)–添加压缩条目
-
func(w * Writer)create header(FH * file header)(io。编写器,错误)
-
func (w *Writer) Flush()错误–刷新任何缓冲的输出
-
func (w *Writer) SetComment(注释字符串)错误
压缩包
Java 支持多种环境下的数据压缩。对于存档文件,通常会这样做。Go 使压缩成为一个更加独立和通用的动作。它支持多种形式的压缩。Go 支持(通过包)这些形式的压缩:
-
bzip2–bzip2 解压缩 -
gzip–gzip 压缩数据的读写 -
zlib–zlib 压缩数据的读写 -
flate–放气压缩 -
伦佩尔-齐夫-韦尔奇压缩公司
这些可用于压缩/解压缩字节流,通常是压缩/解压缩到文件中。它们由归档包使用。有关更多详细信息,请参见 Go 包文档。
作为使用这些包(和os包)的例子,让我们将一个文件压缩成另一个 GZ 格式的文件。下面是一个可能的实现:
func CompressFileToNewGZIPFile(path string) (err error) {
var inFile, gzFile *os.File
// access input file
if inFile, err = os.Open(path); err != nil {
return
}
defer inFile.Close()
// create output file
if gzFile, err = os.Create(path + ".gz"); err != nil {
return
}
defer gzFile.Close()
// copy input to output, compressing as copied
w := gzip.NewWriter(gzFile)
defer w.Close()
_, err = io.Copy(w, inFile)
return
}
请注意,如果此函数返回一个错误,则可能会用无效数据创建输出文件。
如果你替换
w := gzip.NewWriter(gzFile)
随着
w := gzFile
并且去掉最后一个defer语句,你会得到一个未压缩的文件副本。
图像
image包及其子包为读取、绘制和格式化图像提供了支持。image包包含使用各种形式/大小的颜色的图像表示,例如 Alpha、Alpha16、CMYK、Gray、Gray16、NRGBA、NRGBA64、NYCbCrA、Paletted、RGBA、YCbCr。它还支持几种图像类型:image、PalatedImage 和 Uniform。它还有一些关键的图像相关类型,如点和矩形。
有关使用此软件包的一些示例,请参见顶点计划。
映像包具有以下关键接口和结构:
type Image interface {
ColorModel() color.Model
Bounds() image.Rectangle
At(x, y int) color.Color
}
包image有一些关键方法:
-
func Decode(rio.Reader) (Image, string, error)–读取图像
type Point struct {
X, Y int
}
type Rectangle struct {
Min, Max Point
}
点和矩形具有创建、调整和比较值的方法:
-
func Pt(X,Y int)Point–创建一个点
-
功能(p 点)添加(q 点)点–添加点
-
函数(p 点)除法(k 整数)点–将 p 除以 k
-
func (p 点)Eq(q 点)bool–测试相等
-
func (p 点)In(r 矩形)bool–测试 p 是否在 r 中
-
func (p 点)Mod(r 矩形)点–p 在 r 中的模数
-
函数(p 点)乘法(k 整数)点–将 p 乘以 k
-
功能(p 点)子(q 点)点–减去一个点
-
func Rect(x0,y0,x1,y1 int)Rectangle–制作一个矩形
-
功能(r 矩形)添加(p 点)矩形–添加矩形
-
func (r 矩形)At(x,y int) color。颜色测试–获取某一点的颜色
-
func(r Rectangle)Bounds()Rectangle–获取边界
-
func(r Rectangle)Canon()Rectangle–制作 r 的规范版本
-
func (r 矩形)ColorModel()颜色。模型–获取颜色模型
-
func(r Rectangle)Dx()int–获取宽度
-
func(r Rectangle)Dy()int–获取高度
-
func(r Rectangle)Empty()bool–测试是否没有包含点
-
func(r Rectangle)Eq(s Rectangle)bool–测试相等
-
func(r Rectangle)In(s Rectangle)bool–r all In s
-
func(r Rectangle)Inset(n int)Rectangle–返回 r inset 乘 n
-
func (r 矩形)Intersect(s 矩形)Rectangle–返回最大的交集
-
函数(r 矩形)重叠(s 矩形)布尔–如果交集不为空
-
func (r 矩形)大小()点
-
函数(r 矩形)子(p 点)矩形–将 r 平移-p
-
func(r Rectangle)Union(s Rectangle)Rectangle–返回覆盖 r 和 s 的矩形
所有的图像形式至少都有这些方法(有些超出了图像接口):
-
func (p * ) At(x,y int) color。颜色-获取某一点的值
-
func(p *)Bounds()Rectangle–获取图像边界
-
func (p * ) ColorModel()颜色。模型–获取图像颜色模型
-
func(p *)Opaque()bool–查看图像是否不透明(没有透明单元格)
-
func (p * ) PixOffset(x,y int)int–获取该点在像素列表中的偏移量
-
func (p * ) Set(x,y int,c color。颜色)–在一个点上设置值
-
func (p * ) SetAlpha(x,y int,c color。Alpha)–仅设置一个点的 alpha
-
func (p * )子图像(r 矩形)图像–获取图像的子集
输入/输出
io和ioutil包提供了基本的 I/O 操作,这些操作抽象了基本操作系统(OS)提供的动作。这个io包主要由接口组成,而不是实现。
Go 有几个关键接口,当它们组合在一起时,允许丰富的输入/输出(I/O)功能。在最基本的层面上,I/O,就像在 Java 中一样,通常是在字节流上完成的,有时被解释为 UTF-8 字符。支持其他字符编码。
-
读取器–可以读取一个字节或一系列字节
-
writer–可以写入一个字节或一系列字节
-
seeker–可以改变流中的读/写位置(一种随机 I/O 形式)
-
closer–可以关闭对流的访问
-
前述接口的组合
许多 Go 类型都实现了这些接口,大多数用于字节,一些用于字符。例如,Go File类型,它允许使用一个打开的文件实例来访问它所代表的操作系统文件的内容。
ioutil包提供了常见文件和目录操作的实现。
Go 和 Java 都支持读写文件(或类似文件的对象)。Java 通过字节或字符流读/写器访问来支持这一点。Java 在其 NIO(新 I/O)包中也有更高的、通常更具性能的选项。Go 的访问级别通常更低,但是 Java 的缓冲流的等价物是可用的。
Go bufio包在非缓冲 I/O 的基础上实现了缓冲 I/O。它提供了类似 Java 支持的各种缓冲流的支持。
io包提供了这些类型(主要是接口)和功能:
-
ByteReader–读取一个字节
-
bytes scanner–读取和未读取的字节
-
打字机–写入一个字节
-
接近–接近
-
limited reader——有限制的阅读器
-
piped reader——来自管道的阅读器
-
piped writer–管道的编写器
-
read closer–可以读取和关闭
-
read seeker–可以阅读和搜索
-
读写关闭——可以读、写、关闭
-
read write seeker–可以读、写、查找
-
读写——可以读、写
-
读者–可以阅读
-
reader at——在某一位置的读取受限
-
reader from–剩余读取
-
阅读符文
-
阅读和未阅读符文
-
section reader–读取一段(跨度)字节
-
探索者-可以设定一个位置
-
string writer–编写一个字符串
-
write closer–可以写,关闭
-
write seeker–可以写、查找
-
写入器–可以写入字节
-
WriterAt–可以在一个位置写入一个字节
-
writer to–可以写入有限的字节
io包有这个键值:
var EOF = errors.New("EOF")
io包具有以下功能:
-
func Copy(dst Writer,src Reader)(写入 int64,err error)-将字节 src 复制到 dst
-
func CopyBuffer(dst Writer,src Reader,buf []byte)(写入 int64,err error)–带缓冲区复制
-
func CopyN(dst Writer,src Reader,n int64) (written int64,err error)-有限制的复制
-
func Pipe() (PipeReader, Pipe writer)-在管道之间复制
-
func Read 至少(r Reader,buf []byte,min int) (n int,err error)-有限制地读取
-
func ReadFull(r Reader,buf []byte) (n int,err error)–读取所有可用的
-
func WriteString(w Writer,s string) (n int,err error)-写入一个字符串
-
func LimitReader(r Reader,n int 64)Reader–创建一个最多接受 n 个字节的读取器
-
func MultiReader(阅读器...Reader)阅读器——制作一个结合所有阅读器的阅读器
-
func TeeReader(r Reader,w Writer)Reader——创建一个将 r 复制到 w 的阅读器
-
func NewSectionReader(r ReaderAt,off int64,n int 64)* section reader–创建节阅读器
ioutil包有这个键值:
var Discardio.Writer用来丢弃任何写入其中的东西
ioutil包定义了这些函数:
-
func no closer(r io。读者)io。read closer–空阅读器
-
func ReadAll(r io。reader)([]字节,错误)–读取所有剩余字节
-
func ReadDir(目录名字符串)([]os。FileInfo,error)–读取目录
-
func ReadFile(文件名字符串)([]字节,错误)-读取整个文件
-
func TempDir(dir,pattern string)(名称字符串,err 错误)-创建唯一的命名目录
-
func TempFile(目录,模式字符串)(f *os。文件,err 错误)–创建一个唯一的命名文件
-
func WriteFile(文件名字符串,数据[]字节,perm os。FileMode)错误–写入整个文件
bufio包定义了这些函数(提供了各种扫描仪):
-
func ScanBytes(data []byte,atEOF bool) (advance int,token []byte,err error)
-
func ScanLines(data []byte,atEOF bool) (advance int,token []byte,err error)
-
func 扫描(data []byte,atEOF bool)(前进 int,token []byte,err error)
-
func 扫描字(data []byte,atEOF bool) (advance int,token []byte,err error)
ReadWriter类型实现了读和写接口:
- func NewReadWriter(r *Reader,w *Writer) *ReadWriter
Reader类型实现了阅读器接口:
-
func NewReader(rd io。读者)*读者
-
func NewReaderSize(rd io。阅读器,尺寸 int)*阅读器
-
func(b *读取器)Buffered() int
-
func (b *Reader) Discard(n int)(丢弃的 int,err error)
-
func(b * Reader)Peek(n int)([]字节,错误)
-
func(b * Reader)Read(p[]byte)(n int,err error)
-
func (b *Reader) ReadByte()(字节,错误)
-
func (b *Reader)读取字节(delim 字节)([]字节,错误)
-
func(b * Reader)ReadLine()(line[]byte,isPrefix bool,err error)
-
func (b *Reader) ReadRune() (r rune,size int,err error)
-
func (b *Reader) ReadSlice(delim 字节)(line[]字节,err 错误)
-
func (b *Reader) ReadString(delim 字节)(String,error)
-
func(b *阅读器)复位(r io。读者)
-
func (b *Reader) Size() int
-
func (b *Reader) UnreadByte()错误
-
func(b * Reader)un readune()错误
-
func (b *Reader) WriteTo(w io。Writer) (n int64,err error)
Scanner类型实现扫描仪接口:
-
func 新闻扫描器(r io。阅读器)*扫描仪
-
func (s *Scanner)缓冲区(buf []byte,max int)
-
func (s *Scanner)字节()[]字节
-
func (s *Scanner) Err()错误
-
func(s *扫描仪)Scan() bool
-
func(s *扫描仪)分割(split SplitFunc)
-
func (s *Scanner) Text()字符串
Writer类型实现了编写器接口:
-
func NewWriter(w io。作家)*作家
-
func NewWriterSize(w io。Writer,size int) *Writer
-
func (b *Writer) Available() int
-
func (b *Writer)缓冲的()int
-
func (b *Writer) Flush()错误
-
func (b *Writer) ReadFrom(r io。读取器)(n int64,err error)
-
func (b *Writer)复位(w io。作家)
-
func (b *Writer) Size() int
-
func (b *Writer)写入(p[]字节)(nn int,err error)
-
func (b *Writer) WriteByte(c 字节)错误
-
func(b * Writer)write rune(r rune)(size int,err error)
-
func(b * Writer)WriteString(s string)(int,error)
作为使用os、bufio和其他包的一个例子,清单 14-1 和 14-2 展示了一个函数,它可以计算一个单词在某个文本文件中出现的次数。
func CountWordsInFile(path string) (counts map[string]int, err error) {
var f *os.File
if f, err = os.Open(path); err != nil {
return
}
defer f.Close()
counts, err = scan(f)
return
}
func scan(r io.Reader) (counts map[string]int, err error) {
counts = make(map[string]int)
s := bufio.NewScanner(r)
s.Split(bufio.ScanWords) // make into words
for s.Scan() { // true while words left
lcw := strings.ToLower(s.Text()) // get last scanned word
counts[lcw] = counts[lcw] + 1 // missing is zero value
}
err = s.Err() // notice any error
return
}
Listing 14-1Word Count Example (Part 1)
这将返回文件中每个(忽略大小写)单词的计数图。一个扫描器的工作方式很像一个 Java 迭代器(通过它的hasNext和next方法)。函数ScanWords被传递给扫描器,以确定如何解析出单词。其他几种分割方法被预定义为按字节、符号或行扫描。有状态扫描器通过Text()(下一个扫描的字符串)和Err()(任何扫描错误)方法返回结果。如果没有错误,则设置文本。扫描在第一个错误时停止。
path := `...\words.txt` // point to a real file
counts, err := CountWordsInFile(path)
if err != nil {
fmt.Printf("Count failed: %v\n", err)
return
}
fmt.Printf("Counts for %q:\n", path)
for k, v := range counts {
fmt.Printf(" %-20s = %v\n", k, v)
}
Listing 14-2Word Count Example (Part 2)
现在是时候来帮助我们的同胞了!
它产生以下内容:
Counts for ".../words.txt":
Now = 1
time = 1
come = 1
countrymen! = 1
our = 1
is = 1
the = 2
to = 2
aid = 1
of = 1
字节包
在 Go 中,类型[]byte经常被使用,尤其是作为输入源或输出目标(I/O)。在 Java 中,使用字节数组作为目标的情况较少;相反,使用字节数组(或字符)上的流。Go bytes包提供了对字节片进行 I/O 的函数。
bytes包提供了这些类型和功能。大多数都是不言自明的,并且与strings包中的函数相匹配,因为字节片段通常可以被视为 ASCII 字符串,或者更具挑战性的 UTF 8 字符:
-
func Compare(a,b []byte) int
-
func 包含(b,subslice []byte) bool
-
func 包含三洋(b[]字节,char string)bool
-
func containsruna(b[]字节,r run)bool
-
函数计数(s,sep []byte) int
-
func Equal(a,b[]字节)布尔值
-
func EqualFold(s,t[]byte)bool–case 折叠 s 和 t 后等于
-
func 字段(s[]字节)[][]字节
-
func field sfunc(s[]字节,f func(rune)bool[])字节
-
func HasPrefix(s, prefix []byte) bool
-
func HasSuffix(s,后缀[]字节)布尔
-
函数索引(s,sep []byte) int
-
func index ny(s[]字节,char string)int
-
func 索引字节(b[]字节、c 字节)int
-
func 索引 unc(s[]字节,f func(r rune) bool) int
-
func index rune(s[]字节,r rune) int
-
func Join(s[][]字节,sep[]字节)[]字节
-
func LastIndex(s,sep []byte) int
-
func lastindexany(s[]字节,char string)int
-
func 负载索引字节(带[]字节、c 字节)int
-
func lastindexfunc(s[]字节,f func(r rune) bool) int
-
func Map(映射 func(r rune) rune,s []byte) []byte
-
func 重复(b[]字节,count int)[]字节
-
func Replace(s,old,new[]字节,n int)[]字节
-
func ReplaceAll(s,旧,新[]字节)[]字节
-
func runes(s[]字节)[]rune
-
func Split(s,sep[]byte)[][]byte–在 sep 处拆分,删除 sep
-
func SplitAfter(s,sep[]byte)[][]byte–在所有 sep 之后拆分
-
func SplitAfterN(s,sep []byte,n int)[][]byte–sep 后分割受 n 限制
-
func SplitN(s,sep []byte,n int) [][]byte
-
func Title(s[]byte)[]byte–字开始到标题大小写
-
func to lower(s[]字节)[]字节
-
func to title(s[]byte)[]byte–全部为标题大小写
-
func ToUpper(s []byte) []byte
-
func ToValidUTF8(s,替换[]字节)[]字节
-
func Trim(s[]字节,割集字符串)[]字节
-
func trimfunc(s[]字节,f func(r rune)bool[]字节
-
func trim left(s[]字节,割集字符串)[]字节
-
func trimleftfunc(s[]字节,f func(r rune)bool)[]字节
-
func 前缀(s,前缀[]字节)[]字节
-
func trim right(s[]字节,割集字符串)[]字节
-
func trimrghtfunc(s[]字节,f func(r rune)bool)[]字节
-
func TrimSpace(s []byte) []byte
-
func 三字尾(s,字尾[]位元组)[]位元组
缓冲器类型提供这些功能。大多数是不言自明的。Buffer类型提供了一种缓冲 I/O 的方法,通常来自文件或网络:
-
func new Buffer(buf[]byte)* Buffer
-
func NewBufferString(s 字符串)*缓冲区
-
func (b *Buffer) Bytes() []byte
-
func (b *Buffer) Cap() int
-
func (b *Buffer) Grow(n int)
-
func (b *Buffer) Len() int
-
func(b * Buffer)Next(n int)[]字节
-
func (b *Buffer)读取(p[]字节)(n int,err error)
-
func (b *Buffer) ReadByte()(字节,错误)
-
func(b * Buffer)Read bytes(delim byte)(line[]byte,err error)-一直读到 delim(通常是换行)
-
func (b *Buffer) ReadFrom(r io。读取器)(n int64,err error)
-
func (b *Buffer) ReadRune() (r rune,size int,err error)
-
func (b *Buffer) ReadString(delim 字节)(行字符串,err 错误)
-
func(b * Buffer)Reset()–返回起点
-
func (b *Buffer) Truncate(n int)
-
func (b *Buffer) UnreadByte()错误
-
func(b * Buffer)un readune()错误
-
func (b *Buffer)写(p[]字节)(n int,err error)
-
func (b *Buffer)写字节(c 字节)错误
-
func(b * Buffer)write rune(r rune)(n int,err error)
-
func(b * Buffer)WriteString(s string)(n int,err error)
-
func (b *Buffer) WriteTo(w io。Writer) (n int64,err error)
读取器类型提供了这些功能。大多数是不言自明的:
-
func new Reader(b[]字节)*Reader
-
func (r *Reader) Len() int
-
func (r *Reader)读取(b[]字节)(n int,err error)
-
func (r *Reader) ReadAt(b []byte,off int64) (n int,err error)
-
func (r *Reader) ReadByte()(字节,错误)
-
func(r * Reader)ReadRune()(ch rune,size int,err error)
-
func(r *读取器)复位(b[]字节)
-
func (r *Reader) Seek(偏移量 int64,where int)(int 64,error)
-
func (r *Reader) Size() int64
-
func (r *Reader) UnreadByte()错误
-
func(r * Reader)un readune()错误
-
func (r *Reader) WriteTo(w io。Writer) (n int64,err error)
格式化包
fmt包提供了一个格式化的字符串和 I/O 函数,很像 Java 的String.format和PrintStream/PrintWriterprintf函数。
scanner包提供了文本扫描和标记化。
tabwriter包提供了一种简单但功能较低的方式来生成表格(列化)文本输出。社区提供更高的功能支持。
fmt包提供了这些功能:
-
func Errorf(格式字符串,a...interface { })error–从格式化字符串中出错
-
func Fprint(w io。作家...interface{}) (n int,err error)–输出到 w
-
func Fprintf(w io。编写器,格式字符串,一个...interface{}) (n int,err error)–输出到 w
-
func Fprintln(w io。作家...interface{}) (n int,err error)–输出到 w 并添加 NL
-
函数 Fscan(r io。读者 a...interface{}) (n int,err error)–按类型扫描来自 r 的输入
-
func Fscanf(r io。读取器,格式字符串,一个...interface{}) (n int,err error)–按类型扫描来自 r 的输入
-
func Fscanln(r io。读者 a...interface{}) (n int,err error)–按类型从 r 扫描输入行
-
功能打印(a...interface{}) (n int,err error)–输出到 STDOUT
-
func Printf(格式字符串,a...interface{}) (n int,err error)–输出到 STDOUT
-
func Println(a...interface{}) (n int,err error)–输出到添加了 NL 的 STDOUT
-
功能扫描(a...interface{}) (n int,err error)–扫描来自 STDIN 的输入
-
func Scanf(格式字符串,a...interface{}) (n int,err error)–扫描来自 STDIN 的输入
-
函数扫描(a...interface{}) (n int,err error)–从 STDIN 扫描行输入
-
func Sprint(a...interface { })string–输出字符串
-
func Sprintf(格式字符串,a...interface { })string–输出字符串
-
func Sprintln(a...interface { })string–输出添加了 NL 的字符串
-
func Sscan(字符串 string,a...interface{}) (n int,err error)–从字符串中扫描输入
-
func Sscanf(字符串,格式字符串,一个...interface{}) (n int,err error)–从字符串中扫描输入
-
func Sscanln(字符串 string,a...interface{}) (n int,err error)–从字符串中扫描行输入
fmt包提供了这些类型:
-
类型格式化程序–一种可以自我格式化的类型
-
GoStringer 类型——这种类型可以支持根据
%#v用细节格式化自身 -
扫描仪类型–可以自定义扫描方法的类型
-
Stringer 类型–可以将自身格式化为字符串的类型
scanner包提供了这些类型和功能。
Scanner从io.Reader中读取字符和标记:
-
func (s *Scanner) Init(src io。阅读器)*扫描仪–制作扫描仪
-
func(s * Scanner)Next()rune–获取下一个字符
-
func(s * Scanner)Peek()rune–检查下一个字符
-
func(s * Scanner)Pos()(Pos Position)-输出位置信息
-
func(s * Scanner)Scan()rune–获取下一个令牌
-
func(s * Scanner)token text()string–获取刚刚扫描的令牌的文本
tabwriter包提供了这些类型和功能。
Writer 是一个具有列对齐功能的io.Writer:
-
func NewWriter(输出 io。Writer,minwidth,tabwidth,padding int,padchar byte,flags uint)* Writer–创建一个编写器
-
func (b *Writer) Flush()错误
-
func (b Writer) Init(输出 io。Writer,minwidth,tabwidth,padding int,padchar byte,flags uint) Writer–重置一个 Writer
-
func (b *Writer)写(buf []byte) (n int,err error)
数据收集
与 Java 不同,Go 不太依赖一组标准的集合(列表、地图、集合等)。)类型和关联的实现。slice和map类型满足了大部分需求。但是 Go 包含了一些特殊用途的容器库。有关更多详细信息,请参见在线软件包文档:
-
heap为任何堆接口实现者提供操作;仅接口。 -
list提供了一个双向链表。 -
ring提供循环列表。
包堆提供了一些实现类型必须提供的类型和函数:
-
func Fix(h Interface,I int)–元素值更改后修复
-
功能初始化(h 接口)–初始化
-
func Pop(h Interface)Interface { }–获取最低值
-
func Push(h 接口,x 接口{ })–添加新值
-
func Remove(h Interface,I int)Interface { }–删除第 I 个值
包list提供了这些类型和功能。
元素是列表成员:
-
func(e * Element)Next()* Element–获取任何前任
-
func(e * Element)Prev()* Element–获取任何后续元素
List包含元素。这些方法不言自明:
-
func New()* List–制作列表
-
func(l * List)Back()*元素–向后移动
-
func(l * List)Front()*元素–获取第一个
-
func(l * List)Init()* List –{ Re }初始化(清空)列表
-
func(l * List)InsertAfter(v interface { },mark * Element)*元素
-
func(l * List)insert before(v interface { },mark * Element)*元素
-
func(l * List)Len()int–获取长度
-
func (l *List) MoveAfter(e,mark *Element)
-
func (l *List) MoveBefore(e,mark *Element)
-
func(l * List)move to back(e * Element)
-
func(l * List)move to front(e * Element)
-
func (l *List)推回(v interface { })*元素
-
func (l List)推回列表(其他List)
-
func(l * List)push front(v interface { })*元素
-
func (l List) PushFrontList(其他List)
-
func (l *List) Remove(e *Element)接口{}
例如,以相反的顺序输出列表中的所有元素:
var l = list.New()
for _, x := range []int{1,2,3,4,5} {
l.PushFront(x)
}
for v := l.Front(); v != nil; v = v.Next() {
fmt.Print(v.Value)
}
fmt.Println()
从而产生54321。
包ring为Ring类型提供了这些功能。每个环元素都有一个Value字段。没有什么元素是特殊的:
-
func New(n int)* Ring–创建一个包含 n 个元素的环
-
func(r * Ring)Do(f func(interface { })–对每个元素运行一个函数
-
func(r * Ring)Len()int–获取长度
-
func(r * Ring)Link(s * Ring)* Ring–将 s 插入 r
-
func(r * Ring)Move(n int)* Ring–前进 n 个元素
-
func(r * Ring)Next()* Ring–前进一个元素
-
func(r * Ring)Prev()* Ring–后退一个元素
-
func(r * Ring)Unlink(n int)* Ring–将接下来的 n 个元素组成一个环
下面是一个打印整数环的示例:
N := 5
ring := ring.New(N) // some capacity
count := ring.Len()
// set each element to square root the element index cubed
for i := 0; i < count; i++ {
ring.Value = math.Sqrt(float64(i * i * i))
ring = ring.Next()
}
// now output the values; now back at start
x := 0
ring.Do(func(v interface{}) {
fmt.Printf("Root of cube %v = %v\n", x, v)
x++
})
这产生了
Root of cube 0 = 0
Root of cube 1 = 1
Root of cube 2 = 2.8284271247461903
Root of cube 3 = 5.196152422706632
Root of cube 4 = 8
整理
sort包提供了对可比较类型的片和支持特定接口的用户定义集合进行排序的方法。
sort包提供了这些类型和功能:
-
func float 64s(a[]float 64)-Sort[]float 64
-
func float 64 sorted(a[]float64)bool–测试[]float 64 是否已经排序
-
func ints(a[]int)-输出[]int
-
func int sorted(a[]int)bool–测试[]int 是否已经排序
-
func IsSorted(数据接口)bool–测试是否已经排序
-
func Search(n int,f func(int)bool)int–二分搜索法 0…N-1 查找 f 为真的值
-
func SearchFloat64s(a []float64,x float 64)int–二分搜索法为 x 排序的[]float64
-
func SearchInts(a []int,x int)int–二分搜索法为 x 排序的[]int
-
func SearchStrings(a []string,x string)int–x 的二分搜索法排序[]字符串
-
func Slice(slice interface{},less func(i,j int)bool)–Sort[]?使用 less 函数
-
func slice sorted(slice interface { },less func(i,j int)bool)bool–测试是否已经排序
-
func slice table(slice interface { },less func(i,j int)bool)–稳定排序[]?使用 less 函数
-
函数排序(数据接口)-排序数据
-
函数稳定(数据接口)–稳定排序数据
-
函数字符串(一个[]字符串)–排序[]字符串
-
func strings aresorted(a[]string)bool–测试是否已经排序
-
func 反转(数据接口)接口–反转数据
Type Interface (一个接口,不是最好的名字选择)定义了用于排序的方法。类型需要实现此接口才能排序。这就像 Java 的Comparable接口:
-
len()int–支持集合的长度
-
Less(i,j int)bool–比较 I 和 j 处的元素
-
Swap(i,j int)–交换 I 和 j 处的元素
Float64Slice 充当实现Interface接口的[]float64:
-
func (p Float64Slice)搜索(x float64) int
-
func (p Float64Slice)排序()
IntSlice 充当实现Interface接口的[]int:
-
func (p IntSlice)搜索(x int) int
-
func (p IntSlice)排序()
StringSlice 充当实现Interface接口的[]字符串:
-
func (p StringSlice)搜索(x string) int
-
func (p 字符串片)排序)
例如,要对一段字符串进行排序:
in :=[...]string{"32", "-1", "0", "a"}
out :=[...]string{"32", "-1", "0", "a"}
var xout = sort.StringSlice(out[:])
xout.Sort()
fmt.Printf("in: %v\nout: %v\n", in, xout)
这产生了
in: [32 -1 0 a]
out: [-1 0 32 a]
另一个简单的特例是对一段字符串进行排序:
var sortable = []string{"32", "-1", "0", "a"}
sort.Strings(sortable)
fmt.Printf("out: %v\n", sortable)
这产生了
out: [-1 0 32 a]
上下文包
Go 对异步行为的支持与 Java 不同。Java 没有标准的方法来观察或取消这样的动作;每个库都有不同的做法。同样,在 Java 中,类似的支持是由库和/或框架提供的,比如 Spring 框架,标准库中不包括它。
在 Go 中,context包支持这样做,其中上下文类型携带超时、中断和跨本地和可能远程 API 边界和可能进程的作用域值。许多长期运行的 Go APIs(通常期望在 goroutine 中运行)接受一个上下文参数,允许它们被异步取消或在完成时通过通道通知调用者。
context包具有以下类型和功能:
-
func WithCancel(父上下文)(ctx 上下文,cancel cancel func)-添加一个取消函数
-
func WithDeadline(父上下文,d 时间。Time) (Context,cancel func)-添加截止日期
-
func WithTimeout(父上下文,超时时间。Duration)(上下文,cancel func)-添加超时
在哪里
-
Cancel 函数——调用此函数(由客户端)取消操作或(由自己)在操作完成时释放资源;应该被称为“CancelOrDoneFunc ”,因为这更好地反映了它的作用。
-
截止时间–设置未来中止未完成操作的时间。
-
超时–设置延迟,在此之后中止未完成的操作(替代截止时间)。
上下文保存上下文状态。它提供以下功能:
-
func Background()Context–返回用作 With…操作的第一个输入的基本上下文;最常用的。
-
func TODO()Context–返回一个 TODO(需要更多工作)上下文;用法很少。
-
func WithValue(父上下文,键,val 接口{})上下文–向上下文添加值。
上下文具有以下特殊功能:
-
done()–返回一个通道,该通道将在操作完成时接收消息
-
err()–返回操作中发生的任何错误;通常为零
清单 14-3 演示了一个简单的使用上下文来取消一个无限值生成器。
func generateIntValues(ctx context.Context, values chan<- int) {
loop: for {
v, err := genIntValue()
if err != nil {
fmt.Printf("genIntValue error: %v\n", err)
close(values)
break
}
select {
case values <- v: // output value
fmt.Printf("generateIntValues sent: %v\n", v)
case <-ctx.Done():
break loop // done when something received
}
}
}
func genIntValue() (v int, err error) {
test := rand.Intn(20) % 5
if test == 0 {
err = errors.New(fmt.Sprintf("fake some error"))
return
}
v = rand.Intn(100)
fmt.Printf("genIntValue next: %d\n", v)
return
}
Listing 14-3Random Int Generator (Part 1)
通过清单 14-4 中所示的代码运行。
values := make(chan int, 10)
ctx, cf := context.WithTimeout(context.Background(), 5 * time.Second)
go generateIntValues(ctx, values)
for v := range values { // get all generated
fmt.Printf("generateIntValues received: %d\n", v)
}
cf()
fmt.Printf("generateIntValues done\n")
Listing 14-4Random Int Generator (Part 2)
它会产生这样的结果:
genIntValue next: 87
generateIntValues sent: 87
genIntValue next: 59
generateIntValues sent: 59
genIntValue next: 18
generateIntValues sent: 18
genIntValue error: fake some error
generateIntValues received: 87
generateIntValues received: 59
generateIntValues received: 18
generateIntValues done
注意超时确保生成在某个时候结束;在这个例子中没有出现这种情况。注意,因为通道有许多(比如 100 个)槽,所以生成都发生在处理一个值之前。如果通道容量设置为零,处理顺序会变得更加混杂:
genIntValue next: 87
generateIntValues sent: 87
genIntValue next: 59
generateIntValues received: 87
generateIntValues received: 59
generateIntValues sent: 59
genIntValue next: 18
generateIntValues sent: 18
generateIntValues received: 18
genIntValue error: fake some error
generateIntValues done
密码术、散列法和数据编码
Go 内置了重要的加密和散列函数。这包括对多种算法和功能的支持。每个都有自己的包装。本书不会详细介绍这些子包。请参见在线软件包文档。
-
adler32提供 Adler-32 校验和。 -
aes提供 AES 加密。 -
cipher提供标准的分组密码模式,包装较低级别的密码实现。 -
crc32提供 32 位循环冗余校验校验和。 -
crc64提供 64 位循环冗余校验校验和。 -
crypto提供加密常数。 -
des提供数据加密标准和三重数据加密算法。 -
dsa提供数字签名算法。 -
ecdsa提供椭圆曲线数字签名算法。 -
ed25519提供 Ed25519 签名算法。 -
elliptic提供了素数域上的几条标准椭圆曲线。 -
fnv提供 FNV 哈希函数。 -
hash为哈希函数提供接口。 -
hmac提供键控散列消息认证码。 -
maphash提供字节序列的哈希函数。 -
md5提供 MD5 哈希算法。 -
pkix提供 ASN.1 解析。 -
rand提供密码安全的随机数生成器。 -
rc4提供 RC4 加密。 -
rsa提供 RSA 加密。 -
sha1提供 SHA 哈希算法。 -
sha256提供了几种 SHA 哈希算法。 -
sha512提供了几种 SHA 哈希算法。 -
subtle为密码代码提供帮助函数。 -
tls提供 TLS 1.2 和 TLS 1.3。 -
x509提供 X.509 编码的密钥和证书。
编码包
encoding包提供了定义如何在字节级和类似字符串的表示之间转换数据的接口。有几个不同支持的子包。本书将只详细介绍其中的几个子包:
-
ascii85提供 ascii85 数据编码。 -
asn1提供 ASN.1 数据结构的解析。 -
base32提供 base32 编码。 -
base64提供 base64 编码。 -
binary提供数字和字节序列之间的转换。 -
csv读写逗号分隔值(CSV)文件。 -
管理 gob 流,一种二进制交换的形式。
-
hex提供十六进制编码和解码。 -
pem提供 PEM 数据编码。 -
json提供 JSON 编码和解码。 -
xml提供支持 XML 名称空间的 XML 解析器。
csv包有这些类型和功能。
读取器解析 CSV 输入:
-
func NewReader(r io。读者)*读者–成为读者
-
func(r * Reader)Read()(record[]string,err error)-读取一行
-
func(r * Reader)Read all()(records[][]string,err error)-读取所有行
Writer 生成 CSV 输出:
-
func NewWriter(w io。作家)*作家–成为作家
-
func(w * Writer)Flush()–提交写入的内容
-
func(w * Writer)Write(record[]string)错误–写入一行
-
func(w * Writer)Write all(records[][]string)错误–写入多行
hex包具有以下功能:
-
func NewDecoder(r io。读者)io。读者——成为读者
-
func NewEncoder(w io。作家)木卫一。作家——成为作家
-
func Decode(dst,src []byte) (int,error)-src 十六进制字符串到 dst 字节
-
函数解码(s 字符串)([]字节,错误)–src 十六进制字符串到 dst 字节
-
func decodelen(x int)int–总是 x / 2
-
func Dump(data []byte)字符串–格式化十六进制转储
-
功能转储器(带 io。作家)木卫一。write closer–格式化十六进制转储
-
func Encode(dst,src[]byte)int–src 字节到 dst 十六进制字符串
-
func EncodeToString(src []byte)字符串–src 字节到十六进制字符串
-
func 编码器(n int)-始终 n * 2
json包具有以下类型和功能:
-
func Compact(dst *字节。Buffer,src []byte)错误–删除无关紧要的空白
-
func html scape(dst *字节。Buffer,src[]byte)–使嵌入 HTML 变得安全
-
func 缩进(dst *字节。Buffer,src []byte,prefix,indent string)错误–缩进 JSON
-
func Marshal(v 接口{ })([]字节,错误)-基于传递的类型生成 JSON
-
func MarshalIndent(v interface{},prefix,indent string) ([]byte,error)-根据传递的类型生成缩进的 JSON
-
func 解组(data []byte,v interface{})错误–将 JSON 解析为传递的类型
-
func Valid(data[]byte)bool–测试 JSON 字符串的有效性
解码器解码/解析 JSON 字符串。它提供以下功能:
-
func NewDecoder(r io。阅读器)*解码器–制作解码器
-
func(dec * Decoder)Decode(v interface { })error–解码下一个 JSON 值
-
func(dec * Decoder)DisallowUnknownFields()–导致未知键出错
-
func(dec * Decoder)input offset()int 64–输入文本中的位置
-
func(dec * Decoder)More()bool–测试是否有更多数据要解析
-
func (dec *Decoder) Token() (Token,error)-获取下一个令牌
编码器编码/构建 JSON 字符串。它提供以下功能:
-
func NewEncoder(w io。writer)* Encoder–制作编码器
-
func(enc * Encoder)Encode(v interface { })错误–将值格式化为 JSON
-
func (enc *Encoder) SetEscapeHTML(在 bool 上)–转义 HTML 控制字符
-
func (enc *Encoder) SetIndent(前缀,缩进字符串)-设置缩进空格
有关使用 JSON 和 XML 编码器的示例,请参见 capstone 程序。
Unicode 编码包
unicode包提供了检查和操作流行编码中的 Unicode 字符(即,符文)的功能。这个包有常量和变量,它们定义了主要的 Unicode 字符类别,比如Letter、Digit、Punct、Space等等。
它具有以下功能。许多人通过 Unicode 分类来测试符文的类型。这就像 Java 的Character.isXxx(...)方法。
-
函数在(r rune,ranges...* range table)bool–测试符文的成员资格
-
func Is(rangeTab *RangeTable,r rune)bool–测试成员的 Rune
-
func isco control(r rune)bool
-
func IsDigit(r rune) bool
-
func IsGraphic(r rune) bool
-
func IsLetter(s rune) bool
-
func ispower(r rune)bool
-
func ismak(r rune)bool
-
func IsNumber(r rune) bool
-
func is of(ranges[]* range table,r rune) bool
-
func IsPrint(r rune) bool
-
func IsPunct(r rune) bool
-
func IsSpace(r rune) bool
-
func 此符号(r rune) bool
-
func isttle(r rune)bool
-
func isper(r rune)bool
-
func SimpleFold(r rune) rune
-
Func ToLower(s rune) 符文
-
func ToTitle(r rune) rune
-
func ToUpper(r rune)符文
unicode包有子包:
-
为 UTF-8 提供编码和解码符文。
-
utf16为 UTF-16 提供编码和解码符文。
utf8包提供了这些功能:
-
func DecodeLastRune(p[]byte)(r rune,size int)-获取最后一个符文和长度
-
func DecodeLastRuneInString(s string)(r rune,size int)-获取最后一个符文和长度
-
func DecodeRune(p []byte) (r rune,size int)-获取第一个符文和长度
-
获得第一个符文和长度
-
func EncodeRune(p []byte,r rune)int–在 UTF-8 中制作一个符文
-
func full rune(p[]byte)bool–测试 p 是否以有效的 UTF-8 符文开始
-
测试 s 是否以有效的 UTF-8 符文开始
-
func rune Count(p[]byte)int–计算 p 中的字符数
-
func rune Count instring(s string)(n int)-以 s 为单位计算符文数
-
func rune len(r rune)int–rune UTF-8 中有多少字节
-
func RuneStart(b 字节)bool–b 是有效的 RuneStart 吗
-
func Valid(p[]byte)bool–测试 p 是一个值 rune 序列
-
一个符文可以用 UTF8 表示吗
-
func valid string(s string)bool–Test s 是一个有效的符文序列
utf16包提供了这些功能:
-
func Decode(s[]uint 16)[]符文–转换为符文
-
符文——将一对符文转换成一个符文
-
func Encode(s[]rune)[]uint 16–从 rune 转换而来
-
func EncodeRune(r rune) (r1,R2 rune)-转换成一对
-
测试一个符文是否需要一对