2022-08-04 06:59:33 +00:00
<!DOCTYPE HTML>
< html lang = "zh" class = "sidebar-visible no-js light" >
< head >
<!-- Book generated using mdBook -->
< meta charset = "UTF-8" >
< title > sort.Interface接口 - Go语言圣经< / title >
<!-- Custom HTML head -->
< meta content = "text/html; charset=utf-8" http-equiv = "Content-Type" >
< meta name = "description" content = "<The Go Programming Language>中文版" >
< meta name = "viewport" content = "width=device-width, initial-scale=1" >
< meta name = "theme-color" content = "#ffffff" / >
< link rel = "icon" href = "../favicon.svg" >
< link rel = "shortcut icon" href = "../favicon.png" >
< link rel = "stylesheet" href = "../css/variables.css" >
< link rel = "stylesheet" href = "../css/general.css" >
< link rel = "stylesheet" href = "../css/chrome.css" >
< link rel = "stylesheet" href = "../css/print.css" media = "print" >
<!-- Fonts -->
< link rel = "stylesheet" href = "../FontAwesome/css/font-awesome.css" >
< link rel = "stylesheet" href = "../fonts/fonts.css" >
<!-- Highlight.js Stylesheets -->
< link rel = "stylesheet" href = "../highlight.css" >
< link rel = "stylesheet" href = "../tomorrow-night.css" >
< link rel = "stylesheet" href = "../ayu-highlight.css" >
<!-- Custom theme stylesheets -->
< link rel = "stylesheet" href = "../style.css" >
< / head >
< body >
<!-- Provide site root to javascript -->
< script type = "text/javascript" >
var path_to_root = "../";
var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "navy" : "light";
< / script >
<!-- Work around some values being stored in localStorage wrapped in quotes -->
< script type = "text/javascript" >
try {
var theme = localStorage.getItem('mdbook-theme');
var sidebar = localStorage.getItem('mdbook-sidebar');
if (theme.startsWith('"') & & theme.endsWith('"')) {
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
}
if (sidebar.startsWith('"') & & sidebar.endsWith('"')) {
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
}
} catch (e) { }
< / script >
<!-- Set the theme before any content is loaded, prevents flash -->
< script type = "text/javascript" >
var theme;
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
if (theme === null || theme === undefined) { theme = default_theme; }
var html = document.querySelector('html');
html.classList.remove('no-js')
html.classList.remove('light')
html.classList.add(theme);
html.classList.add('js');
< / script >
<!-- Hide / unhide sidebar before it is displayed -->
< script type = "text/javascript" >
var html = document.querySelector('html');
var sidebar = 'hidden';
if (document.body.clientWidth >= 1080) {
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
sidebar = sidebar || 'visible';
}
html.classList.remove('sidebar-visible');
html.classList.add("sidebar-" + sidebar);
< / script >
< nav id = "sidebar" class = "sidebar" aria-label = "Table of contents" >
< div class = "sidebar-scrollbox" >
2023-03-31 10:23:29 +00:00
< ol class = "chapter" > < li class = "chapter-item expanded affix " > < a href = "../index.html" > Go语言圣经< / a > < / li > < li class = "chapter-item expanded affix " > < a href = "../preface.html" > 前言< / a > < / li > < li class = "chapter-item expanded " > < a href = "../ch1/ch1.html" > < strong aria-hidden = "true" > 1.< / strong > 入门< / a > < / li > < li > < ol class = "section" > < li class = "chapter-item expanded " > < a href = "../ch1/ch1-01.html" > < strong aria-hidden = "true" > 1.1.< / strong > Hello, World< / a > < / li > < li class = "chapter-item expanded " > < a href = "../ch1/ch1-02.html" > < strong aria-hidden = "true" > 1.2.< / strong > 命令行参数< / a > < / li > < li class = "chapter-item expanded " > < a href = "../ch1/ch1-03.html" > < strong aria-hidden = "true" > 1.3.< / strong > 查找重复的行< / a > < / li > < li class = "chapter-item expanded " > < a href = "../ch1/ch1-04.html" > < strong aria-hidden = "true" > 1.4.< / strong > GIF动画< / a > < / li > < li class = "chapter-item expanded " > < a href = "../ch1/ch1-05.html" > < strong aria-hidden = "true" > 1.5.< / strong > 获取URL< / a > < / li > < li class = "chapter-item expanded " > < a href = "../ch1/ch1-06.html" > < strong aria-hidden = "true" > 1.6.< / strong > 并发获取多个URL< / a > < / li > < li class = "chapter-item expanded " > < a href = "../ch1/ch1-07.html" > < strong aria-hidden = "true" > 1.7.< / strong > Web服务< / a > < / li > < li class = "chapter-item expanded " > < a href = "../ch1/ch1-08.html" > < strong aria-hidden = "true" > 1.8.< / strong > 本章要点< / a > < / li > < / ol > < / li > < li class = "chapter-item expanded " > < a href = "../ch2/ch2.html" > < strong aria-hidden = "true" > 2.< / strong > 程序结构< / a > < / li > < li > < ol class = "section" > < li class = "chapter-item expanded " > < a href = "../ch2/ch2-01.html" > < strong aria-hidden = "true" > 2.1.< / strong > 命名< / a > < / li > < li class = "chapter-item expanded " > < a href = "../ch2/ch2-02.html" > < strong aria-hidden = "true" > 2.2.< / strong > 声明< / a > < / li > < li class = "chapter-item expanded " > < a href = "../ch2/ch2-03.html" > < strong aria-hidden = "true" > 2.3.< / strong > 变量< / a > < / li > < li class = "chapter-item expanded " > < a href = "../ch2/ch2-04.html" > < strong aria-hidden = "true" > 2.4.< / strong > 赋值< / a > < / li > < li class = "chapter-item expanded " > < a href = "../ch2/ch2-05.html" > < strong aria-hidden = "true" > 2.5.< / strong > 类型< / a > < / li > < li class = "chapter-item expanded " > < a href = "../ch2/ch2-06.html" > < strong aria-hidden = "true" > 2.6.< / strong > 包和文件< / a > < / li > < li class = "chapter-item expanded " > < a href = "../ch2/ch2-07.html" > < strong aria-hidden = "true" > 2.7.< / strong > 作用域< / a > < / li > < / ol > < / li > < li class = "chapter-item expanded " > < a href = "../ch3/ch3.html" > < strong aria-hidden = "true" > 3.< / strong > 基础数据类型< / a > < / li > < li > < ol class = "section" > < li class = "chapter-item expanded " > < a href = "../ch3/ch3-01.html" > < strong aria-hidden = "true" > 3.1.< / strong > 整型< / a > < / li > < li class = "chapter-item expanded " > < a href = "../ch3/ch3-02.html" > < strong aria-hidden = "true" > 3.2.< / strong > 浮点数< / a > < / li > < li class = "chapter-item expanded " > < a href = "../ch3/ch3-03.html" > < strong aria-hidden = "true" > 3.3.< / strong > 复数< / a > < / li > < li class = "chapter-item expanded " > < a href = "../ch3/ch3-04.html" > < strong aria-hidden = "true" > 3.4.< / strong > 布尔型< / a > < / li > < li class = "chapter-item expanded " > < a href = "../ch3/ch3-05.html" > < strong aria-hidden = "true" > 3.5.< / strong > 字符串< / a > < / li > < li class = "chapter-item expanded " > < a href = "../ch3/ch3-06.html" > < strong aria-hidden = "true" > 3.6.< / strong > 常量< / a > < / li > < / ol > < / li > < li class = "chapter-item expanded " > < a href = "../ch4/ch4.html" > < strong aria-hidden = "true" > 4.< / strong > 复合数据类型< / a > < / li > < li > < ol class = "section" > < li class = "chapter-item expanded " > < a href = "../ch4/ch4-01.html" > < strong aria-hidden = "true" > 4.1.< / strong > 数组< / a > < / li > < li class = "chapter-item expanded " > < a href = "../ch4/ch4-02.html" > < strong aria-hidden = "true" > 4.2.< / strong > Slice< / a > < / li > < li class = "chapter-item expanded " > < a href = "../ch4/ch4-03.html" > < strong aria-hidden = "true" > 4.3.< / strong > Map< / a > < / li > < li class = "chapter-item expanded " > < a href = "../ch4/ch4-04.html" > < strong aria-hidden = "true" > 4.4.< / strong > 结构体< / a > < / li > < li class = "chapter-item expanded " > < a href = "../ch4/ch4-05.html" > < strong aria-hidden = "true" > 4.5.< / strong > JSON< / a > < / li > < li class = "chapter-item expanded " > < a href = "../ch4/ch4-06.html" > < strong aria-hidd
2022-08-04 06:59:33 +00:00
< div id = "sidebar-resize-handle" class = "sidebar-resize-handle" > < / div >
< / nav >
< div id = "page-wrapper" class = "page-wrapper" >
< div class = "page" >
< div id = "menu-bar-hover-placeholder" > < / div >
< div id = "menu-bar" class = "menu-bar sticky bordered" >
< div class = "left-buttons" >
< button id = "sidebar-toggle" class = "icon-button" type = "button" title = "Toggle Table of Contents" aria-label = "Toggle Table of Contents" aria-controls = "sidebar" >
< i class = "fa fa-bars" > < / i >
< / button >
< button id = "theme-toggle" class = "icon-button" type = "button" title = "Change theme" aria-label = "Change theme" aria-haspopup = "true" aria-expanded = "false" aria-controls = "theme-list" >
< i class = "fa fa-paint-brush" > < / i >
< / button >
< ul id = "theme-list" class = "theme-popup" aria-label = "Themes" role = "menu" >
< li role = "none" > < button role = "menuitem" class = "theme" id = "light" > Light (default)< / button > < / li >
< li role = "none" > < button role = "menuitem" class = "theme" id = "rust" > Rust< / button > < / li >
< li role = "none" > < button role = "menuitem" class = "theme" id = "coal" > Coal< / button > < / li >
< li role = "none" > < button role = "menuitem" class = "theme" id = "navy" > Navy< / button > < / li >
< li role = "none" > < button role = "menuitem" class = "theme" id = "ayu" > Ayu< / button > < / li >
< / ul >
< button id = "search-toggle" class = "icon-button" type = "button" title = "Search. (Shortkey: s)" aria-label = "Toggle Searchbar" aria-expanded = "false" aria-keyshortcuts = "S" aria-controls = "searchbar" >
< i class = "fa fa-search" > < / i >
< / button >
< / div >
< h1 class = "menu-title" > Go语言圣经< / h1 >
< div class = "right-buttons" >
< a href = "../print.html" title = "Print this book" aria-label = "Print this book" >
< i id = "print-button" class = "fa fa-print" > < / i >
< / a >
< a href = "https://github.com/gopl-zh/gopl-zh.github.com" title = "Git repository" aria-label = "Git repository" >
< i id = "git-repository-button" class = "fa fa-github" > < / i >
< / a >
< a href = "https://github.com/gopl-zh/gopl-zh.github.com/edit/master/./ch7/ch7-06.md" title = "Suggest an edit" aria-label = "Suggest an edit" >
< i id = "git-edit-button" class = "fa fa-edit" > < / i >
< / a >
< / div >
< / div >
< div id = "search-wrapper" class = "hidden" >
< form id = "searchbar-outer" class = "searchbar-outer" >
< input type = "search" id = "searchbar" name = "searchbar" placeholder = "Search this book ..." aria-controls = "searchresults-outer" aria-describedby = "searchresults-header" >
< / form >
< div id = "searchresults-outer" class = "searchresults-outer hidden" >
< div id = "searchresults-header" class = "searchresults-header" > < / div >
< ul id = "searchresults" >
< / ul >
< / div >
< / div >
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
< script type = "text/javascript" >
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
});
< / script >
< div id = "content" class = "content" >
<!-- Page table of contents -->
< div class = "sidetoc" > < nav class = "pagetoc" > < / nav > < / div >
< main >
<!-- 头部 -->
< ul dir = "auto" >
2022-08-24 10:48:15 +00:00
< li > < em > KusonStack一站式可编程配置技术栈(Go): < a href = "https://github.com/KusionStack/kusion" > https://github.com/KusionStack/kusion< / a > < / em > < / li >
< li > < em > KCL 配置编程语言(Rust): < a href = "https://github.com/KusionStack/KCLVM" > https://github.com/KusionStack/KCLVM< / a > < / em > < / li >
< li > < em > 凹语言™: < a href = "https://github.com/wa-lang/wa" > https://github.com/wa-lang/wa< / a > < / em > < / li >
2022-08-04 06:59:33 +00:00
< / ul >
< hr >
< h2 id = "76-sortinterface接口" > < a class = "header" href = "#76-sortinterface接口" > 7.6. sort.Interface接口< / a > < / h2 >
< p > 排序操作和字符串格式化一样是很多程序经常使用的操作。尽管一个最短的快排程序只要15行就可以搞定, 但是一个健壮的实现需要更多的代码, 并且我们不希望每次我们需要的时候都重写或者拷贝这些代码。< / p >
< p > 幸运的是, sort包内置的提供了根据一些排序函数来对任何序列排序的功能。它的设计非常独到。在很多语言中, 排序算法都是和序列数据类型关联, 同时排序函数和具体类型元素关联。相比之下, Go语言的sort.Sort函数不会对具体的序列和它的元素做任何假设。相反, 它使用了一个接口类型sort.Interface来指定通用的排序算法和可能被排序到的序列类型之间的约定。这个接口的实现由序列的具体表示和它希望排序的元素决定, 序列的表示经常是一个切片。< / p >
< p > 一个内置的排序算法需要知道三个东西: 序列的长度, 表示两个元素比较的结果, 一种交换两个元素的方式; 这就是sort.Interface的三个方法: < / p >
< pre > < code class = "language-go" > package sort
type Interface interface {
Len() int
Less(i, j int) bool // i, j are indices of sequence elements
Swap(i, j int)
}
< / code > < / pre >
< p > 为了对序列进行排序, 我们需要定义一个实现了这三个方法的类型, 然后对这个类型的一个实例应用sort.Sort函数。思考对一个字符串切片进行排序, 这可能是最简单的例子了。下面是这个新的类型StringSlice和它的Len, Less和Swap方法< / p >
< pre > < code class = "language-go" > type StringSlice []string
func (p StringSlice) Len() int { return len(p) }
func (p StringSlice) Less(i, j int) bool { return p[i] < p[j] }
func (p StringSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
< / code > < / pre >
< p > 现在我们可以通过像下面这样将一个切片转换为一个StringSlice类型来进行排序: < / p >
< pre > < code class = "language-go" > sort.Sort(StringSlice(names))
< / code > < / pre >
< p > 这个转换得到一个相同长度, 容量, 和基于names数组的切片值; 并且这个切片值的类型有三个排序需要的方法。< / p >
< p > 对字符串切片的排序是很常用的需要, 所以sort包提供了StringSlice类型, 也提供了Strings函数能让上面这些调用简化成sort.Strings(names)。< / p >
< p > 这里用到的技术很容易适用到其它排序序列中, 例如我们可以忽略大小写或者含有的特殊字符。( 本书使用Go程序对索引词和页码进行排序也用到了这个技术, 对罗马数字做了额外逻辑处理。) 对于更复杂的排序, 我们使用相同的方法, 但是会用更复杂的数据结构和更复杂地实现sort.Interface的方法。< / p >
< p > 我们会运行上面的例子来对一个表格中的音乐播放列表进行排序。每个track都是单独的一行, 每一列都是这个track的属性像艺术家, 标题, 和运行时间。想象一个图形用户界面来呈现这个表格, 并且点击一个属性的顶部会使这个列表按照这个属性进行排序; 再一次点击相同属性的顶部会进行逆向排序。让我们看下每个点击会发生什么响应。< / p >
< p > 下面的变量tracks包含了一个播放列表。( One of the authors apologizes for the other author’ s musical tastes.) 每个元素都不是Track本身而是指向它的指针。尽管我们在下面的代码中直接存储Tracks也可以工作, sort函数会交换很多对元素, 所以如果每个元素都是指针而不是Track类型会更快, 指针是一个机器字码长度而Track类型可能是八个或更多。< / p >
< p > < u > < i > gopl.io/ch7/sorting< / i > < / u > < / p >
< pre > < code class = "language-go" > type Track struct {
Title string
Artist string
Album string
Year int
Length time.Duration
}
var tracks = []*Track{
{" Go" , " Delilah" , " From the Roots Up" , 2012, length(" 3m38s" )},
{" Go" , " Moby" , " Moby" , 1992, length(" 3m37s" )},
{" Go Ahead" , " Alicia Keys" , " As I Am" , 2007, length(" 4m36s" )},
{" Ready 2 Go" , " Martin Solveig" , " Smash" , 2011, length(" 4m24s" )},
}
func length(s string) time.Duration {
d, err := time.ParseDuration(s)
if err != nil {
panic(s)
}
return d
}
< / code > < / pre >
< p > printTracks函数将播放列表打印成一个表格。一个图形化的展示可能会更好点, 但是这个小程序使用text/tabwriter包来生成一个列整齐对齐和隔开的表格, 像下面展示的这样。注意到< code > *tabwriter.Writer< / code > 是满足io.Writer接口的。它会收集每一片写向它的数据; 它的Flush方法会格式化整个表格并且将它写向os.Stdout( 标准输出) 。< / p >
< pre > < code class = "language-go" > func printTracks(tracks []*Track) {
const format = " %v\t%v\t%v\t%v\t%v\t\n"
tw := new(tabwriter.Writer).Init(os.Stdout, 0, 8, 2, ' ', 0)
fmt.Fprintf(tw, format, " Title" , " Artist" , " Album" , " Year" , " Length" )
fmt.Fprintf(tw, format, " -----" , " ------" , " -----" , " ----" , " ------" )
for _, t := range tracks {
fmt.Fprintf(tw, format, t.Title, t.Artist, t.Album, t.Year, t.Length)
}
tw.Flush() // calculate column widths and print table
}
< / code > < / pre >
< p > 为了能按照Artist字段对播放列表进行排序, 我们会像对StringSlice那样定义一个新的带有必须的Len, Less和Swap方法的切片类型。< / p >
< pre > < code class = "language-go" > type byArtist []*Track
func (x byArtist) Len() int { return len(x) }
func (x byArtist) Less(i, j int) bool { return x[i].Artist < x[j].Artist }
func (x byArtist) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
< / code > < / pre >
< p > 为了调用通用的排序程序, 我们必须先将tracks转换为新的byArtist类型, 它定义了具体的排序: < / p >
< pre > < code class = "language-go" > sort.Sort(byArtist(tracks))
< / code > < / pre >
< p > 在按照artist对这个切片进行排序后, printTrack的输出如下< / p >
< pre > < code > Title Artist Album Year Length
----- ------ ----- ---- ------
Go Ahead Alicia Keys As I Am 2007 4m36s
Go Delilah From the Roots Up 2012 3m38s
Ready 2 Go Martin Solveig Smash 2011 4m24s
Go Moby Moby 1992 3m37s
< / code > < / pre >
< p > 如果用户第二次请求“按照artist排序”, 我们会对tracks进行逆向排序。然而我们不需要定义一个有颠倒Less方法的新类型byReverseArtist, 因为sort包中提供了Reverse函数将排序顺序转换成逆序。< / p >
< pre > < code class = "language-go" > sort.Sort(sort.Reverse(byArtist(tracks)))
< / code > < / pre >
< p > 在按照artist对这个切片进行逆向排序后, printTrack的输出如下< / p >
< pre > < code > Title Artist Album Year Length
----- ------ ----- ---- ------
Go Moby Moby 1992 3m37s
Ready 2 Go Martin Solveig Smash 2011 4m24s
Go Delilah From the Roots Up 2012 3m38s
Go Ahead Alicia Keys As I Am 2007 4m36s
< / code > < / pre >
< p > sort.Reverse函数值得进行更近一步的学习, 因为它使用了( §6.3) 章中的组合, 这是一个重要的思路。sort包定义了一个不公开的struct类型reverse, 它嵌入了一个sort.Interface。reverse的Less方法调用了内嵌的sort.Interface值的Less方法, 但是通过交换索引的方式使排序结果变成逆序。< / p >
< pre > < code class = "language-go" > package sort
type reverse struct{ Interface } // that is, sort.Interface
func (r reverse) Less(i, j int) bool { return r.Interface.Less(j, i) }
func Reverse(data Interface) Interface { return reverse{data} }
< / code > < / pre >
< p > reverse的另外两个方法Len和Swap隐式地由原有内嵌的sort.Interface提供。因为reverse是一个不公开的类型, 所以导出函数Reverse返回一个包含原有sort.Interface值的reverse类型实例。< / p >
< p > 为了可以按照不同的列进行排序, 我们必须定义一个新的类型例如byYear: < / p >
< pre > < code class = "language-go" > type byYear []*Track
func (x byYear) Len() int { return len(x) }
func (x byYear) Less(i, j int) bool { return x[i].Year < x[j].Year }
func (x byYear) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
< / code > < / pre >
< p > 在使用sort.Sort(byYear(tracks))按照年对tracks进行排序后, printTrack展示了一个按时间先后顺序的列表: < / p >
< pre > < code > Title Artist Album Year Length
----- ------ ----- ---- ------
Go Moby Moby 1992 3m37s
Go Ahead Alicia Keys As I Am 2007 4m36s
Ready 2 Go Martin Solveig Smash 2011 4m24s
Go Delilah From the Roots Up 2012 3m38s
< / code > < / pre >
< p > 对于我们需要的每个切片元素类型和每个排序函数, 我们需要定义一个新的sort.Interface实现。如你所见, Len和Swap方法对于所有的切片类型都有相同的定义。下个例子, 具体的类型customSort会将一个切片和函数结合, 使我们只需要写比较函数就可以定义一个新的排序。顺便说下, 实现了sort.Interface的具体类型不一定是切片类型; customSort是一个结构体类型。< / p >
< pre > < code class = "language-go" > type customSort struct {
t []*Track
less func(x, y *Track) bool
}
func (x customSort) Len() int { return len(x.t) }
func (x customSort) Less(i, j int) bool { return x.less(x.t[i], x.t[j]) }
func (x customSort) Swap(i, j int) { x.t[i], x.t[j] = x.t[j], x.t[i] }
< / code > < / pre >
< p > 让我们定义一个多层的排序函数, 它主要的排序键是标题, 第二个键是年, 第三个键是运行时间Length。下面是该排序的调用, 其中这个排序使用了匿名排序函数: < / p >
< pre > < code class = "language-go" > sort.Sort(customSort{tracks, func(x, y *Track) bool {
if x.Title != y.Title {
return x.Title < y.Title
}
if x.Year != y.Year {
return x.Year < y.Year
}
if x.Length != y.Length {
return x.Length < y.Length
}
return false
}})
< / code > < / pre >
< p > 这下面是排序的结果。注意到两个标题是“Go”的track按照标题排序是相同的顺序, 但是在按照year排序上更久的那个track优先。< / p >
< pre > < code > Title Artist Album Year Length
----- ------ ----- ---- ------
Go Moby Moby 1992 3m37s
Go Delilah From the Roots Up 2012 3m38s
Go Ahead Alicia Keys As I Am 2007 4m36s
Ready 2 Go Martin Solveig Smash 2011 4m24s
< / code > < / pre >
< p > 尽管对长度为n的序列排序需要 O(n log n)次比较操作, 检查一个序列是否已经有序至少需要n-1次比较。sort包中的IsSorted函数帮我们做这样的检查。像sort.Sort一样, 它也使用sort.Interface对这个序列和它的排序函数进行抽象, 但是它从不会调用Swap方法: 这段代码示范了IntsAreSorted和Ints函数在IntSlice类型上的使用: < / p >
< pre > < code class = "language-go" > values := []int{3, 1, 4, 1}
fmt.Println(sort.IntsAreSorted(values)) // " false"
sort.Ints(values)
fmt.Println(values) // " [1 1 3 4]"
fmt.Println(sort.IntsAreSorted(values)) // " true"
sort.Sort(sort.Reverse(sort.IntSlice(values)))
fmt.Println(values) // " [4 3 1 1]"
fmt.Println(sort.IntsAreSorted(values)) // " false"
< / code > < / pre >
< p > 为了使用方便, sort包为[]int、[]string和[]float64的正常排序提供了特定版本的函数和类型。对于其他类型, 例如[]int64或者[]uint, 尽管路径也很简单, 还是依赖我们自己实现。< / p >
< p > < strong > 练习 7.8: < / strong > 很多图形界面提供了一个有状态的多重排序表格插件: 主要的排序键是最近一次点击过列头的列, 第二个排序键是第二最近点击过列头的列, 等等。定义一个sort.Interface的实现用在这样的表格中。比较这个实现方式和重复使用sort.Stable来排序的方式。< / p >
< p > < strong > 练习 7.9: < / strong > 使用html/template包( §4.6) 替代printTracks将tracks展示成一个HTML表格。将这个解决方案用在前一个练习中, 让每次点击一个列的头部产生一个HTTP请求来排序这个表格。< / p >
< p > < strong > 练习 7.10: < / strong > sort.Interface类型也可以适用在其它地方。编写一个IsPalindrome(s sort.Interface) bool函数表明序列s是否是回文序列, 换句话说反向排序不会改变这个序列。假设如果!s.Less(i, j) & & !s.Less(j, i)则索引i和j上的元素相等。< / p >
<!-- 公众号 -->
< hr >
< table >
< tr >
< td >
< img width = "222px" src = "https://chai2010.cn/advanced-go-programming-book/css.png" >
< / td >
< td >
< img width = "222px" src = "https://chai2010.cn/advanced-go-programming-book/cch.png" >
< / td >
< / tr >
< / table >
< div id = "giscus-container" > < / div >
< footer class = "page-footer" >
< span > © 2015-2016 | < a href = "https://github.com/gopl-zh" > Go语言圣经中文版< / a > , 仅学习交流使用< / span >
< / footer >
< / main >
< nav class = "nav-wrapper" aria-label = "Page navigation" >
<!-- Mobile navigation buttons -->
< a rel = "prev" href = "../ch7/ch7-05.html" class = "mobile-nav-chapters previous" title = "Previous chapter" aria-label = "Previous chapter" aria-keyshortcuts = "Left" >
< i class = "fa fa-angle-left" > < / i >
< / a >
< a rel = "next" href = "../ch7/ch7-07.html" class = "mobile-nav-chapters next" title = "Next chapter" aria-label = "Next chapter" aria-keyshortcuts = "Right" >
< i class = "fa fa-angle-right" > < / i >
< / a >
< div style = "clear: both" > < / div >
< / nav >
< / div >
< / div >
< nav class = "nav-wide-wrapper" aria-label = "Page navigation" >
< a rel = "prev" href = "../ch7/ch7-05.html" class = "nav-chapters previous" title = "Previous chapter" aria-label = "Previous chapter" aria-keyshortcuts = "Left" >
< i class = "fa fa-angle-left" > < / i >
< / a >
< a rel = "next" href = "../ch7/ch7-07.html" class = "nav-chapters next" title = "Next chapter" aria-label = "Next chapter" aria-keyshortcuts = "Right" >
< i class = "fa fa-angle-right" > < / i >
< / a >
< / nav >
< / div >
< script type = "text/javascript" >
window.playground_copyable = true;
< / script >
< script src = "../elasticlunr.min.js" type = "text/javascript" charset = "utf-8" > < / script >
< script src = "../mark.min.js" type = "text/javascript" charset = "utf-8" > < / script >
< script src = "../searcher.js" type = "text/javascript" charset = "utf-8" > < / script >
< script src = "../clipboard.min.js" type = "text/javascript" charset = "utf-8" > < / script >
< script src = "../highlight.js" type = "text/javascript" charset = "utf-8" > < / script >
< script src = "../book.js" type = "text/javascript" charset = "utf-8" > < / script >
< script type = "text/javascript" charset = "utf-8" >
var pagePath = "ch7/ch7-06.md"
< / script >
<!-- Custom JS scripts -->
< script type = "text/javascript" src = "../js/custom.js" > < / script >
< script type = "text/javascript" src = "../js/bigPicture.js" > < / script >
< / body >
< / html >