在 Golang 中有一个问题困扰着我。 假设我有 2 个结构:
type Dog struct {
Name string
Breed string
Age int
}
type Cat struct {
Name string
FavoriteFood string
Age int
}
当我尝试按 Age 对 []*Dog 和 []*Cat 进行排序时,我必须定义 2 个不同的排序结构喜欢:
type SortCat []*Cat
func (c SortCat) Len() int {//..}
func (c SortCat) Swap(i, j int) {//..}
func (c SortCat) Less(i, j int) bool {//..}
type SortDog []*Dog
func (c SortDog) Len() int {//..}
func (c SortDog) Swap(i, j int) {//..}
func (c SortDog) Less(i, j int) bool {//..}
一个自然的想法是实现一些SortableByAge 接口(interface)并使用接口(interface)函数创建一个Less 函数。喜欢:
type SortableByAge interface {
AgeValue() int
}
然后:
type SortAnimal []SortableByAge
func (c SortDog) Less(i, j int) bool {
return c[i].AgeValue() < c[j].AgeValue()
}
然而,根据: http://golang.org/doc/faq#convert_slice_of_interface
dogs := make([]*Dogs, 0 , 1)
//add dogs here
sort.Sort(SortAnimal(dogs))
以上是不可能的。
所以我想知道这个案例的最佳实践是什么
是否有任何其他技术可以减少为我错过的类似结构一次又一次地实现 sort.Interface 的需要?
编辑: 我意识到我的例子很糟糕:(
在现实生活中,这两个结构非常不同,它们之间唯一的共同点是我希望通过一个共同的数值对它们进行排序。
一个更好的例子是:
type Laptop {//...}
type Pizza {//...}
这 2 个结构的唯一共同点是我希望按价格对它们的 slice (啊……在示例中不应该使用 Pizza)进行排序。
因此,在很多情况下,将它们组合成一个通用结构并不适用。 但会研究 go generate。
最佳答案
在这种特定情况下,您不应使用 2 种不同的类型,因为它们是相同的,只需使用常见的 Animal 类型即可:
type Animal struct {
Name string
Age int
}
func (a Animal) String() string { return fmt.Sprintf("%s(%d)", a.Name, a.Age) }
type SortAnim []*Animal
func (c SortAnim) Len() int { return len(c) }
func (c SortAnim) Swap(i, j int) { c[i], c[j] = c[j], c[i] }
func (c SortAnim) Less(i, j int) bool { return c[i].Age < c[j].Age }
func main() {
dogs := []*Animal{&Animal{"Max", 4}, &Animal{"Buddy", 3}}
cats := []*Animal{&Animal{"Bella", 4}, &Animal{"Kitty", 3}}
fmt.Println(dogs)
sort.Sort(SortAnim(dogs))
fmt.Println(dogs)
fmt.Println(cats)
sort.Sort(SortAnim(cats))
fmt.Println(cats)
}
输出(Go Playground):
[Max(4) Buddy(3)]
[Buddy(3) Max(4)]
[Bella(4) Kitty(3)]
[Kitty(3) Bella(4)]
一般来说,如果您愿意放弃具体类型并改用接口(interface)类型,那么您只能使用通用的排序实现。
创建您希望 slice 包含的接口(interface)类型:
type Animal interface {
Name() string
Age() int
}
你可以有一个通用的实现:
type animal struct {
name string
age int
}
func (a *animal) Name() string { return a.name }
func (a *animal) Age() int { return a.age }
func (a animal) String() string { return fmt.Sprintf("%s(%d)", a.name, a.age) }
您的特定动物类型:
type Dog struct {
animal // Embed animal (its methods and fields)
}
type Cat struct {
animal // Embed animal (its methods and fields)
}
您在 SortAnim 上实现了 sort.Interface:
type SortAnim []Animal
func (c SortAnim) Len() int { return len(c) }
func (c SortAnim) Swap(i, j int) { c[i], c[j] = c[j], c[i] }
func (c SortAnim) Less(i, j int) bool { return c[i].Age() < c[j].Age() }
使用它:
dogs := SortAnim{&Dog{animal{"Max", 4}}, &Dog{animal{"Buddy", 3}}}
cats := SortAnim{&Cat{animal{"Bella", 4}}, &Cat{animal{"Kitty", 3}}}
fmt.Println(dogs)
sort.Sort(SortAnim(dogs))
fmt.Println(dogs)
fmt.Println(cats)
sort.Sort(SortAnim(cats))
fmt.Println(cats)
输出(Go Playground):
[Max(4) Buddy(3)]
[Buddy(3) Max(4)]
[Bella(4) Kitty(3)]
[Kitty(3) Bella(4)]
关于go - 如何避免为类似的 golang 结构重新实现 sort.Interface,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30336616/
我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div
总的来说,我对ruby还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用
关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。
给定这段代码defcreate@upgrades=User.update_all(["role=?","upgraded"],:id=>params[:upgrade])redirect_toadmin_upgrades_path,:notice=>"Successfullyupgradeduser."end我如何在该操作中实际验证它们是否已保存或未重定向到适当的页面和消息? 最佳答案 在Rails3中,update_all不返回任何有意义的信息,除了已更新的记录数(这可能取决于您的DBMS是否返回该信息)。http://ar.ru
我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t
我想将html转换为纯文本。不过,我不想只删除标签,我想智能地保留尽可能多的格式。为插入换行符标签,检测段落并格式化它们等。输入非常简单,通常是格式良好的html(不是整个文档,只是一堆内容,通常没有anchor或图像)。我可以将几个正则表达式放在一起,让我达到80%,但我认为可能有一些现有的解决方案更智能。 最佳答案 首先,不要尝试为此使用正则表达式。很有可能你会想出一个脆弱/脆弱的解决方案,它会随着HTML的变化而崩溃,或者很难管理和维护。您可以使用Nokogiri快速解析HTML并提取文本:require'nokogiri'h
我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚
Rackup通过Rack的默认处理程序成功运行任何Rack应用程序。例如:classRackAppdefcall(environment)['200',{'Content-Type'=>'text/html'},["Helloworld"]]endendrunRackApp.new但是当最后一行更改为使用Rack的内置CGI处理程序时,rackup给出“NoMethodErrorat/undefinedmethod`call'fornil:NilClass”:Rack::Handler::CGI.runRackApp.newRack的其他内置处理程序也提出了同样的反对意见。例如Rack
在选择我想要运行操作的频率时,唯一的选项是“每天”、“每小时”和“每10分钟”。谢谢!我想为我的Rails3.1应用程序运行调度程序。 最佳答案 这不是一个优雅的解决方案,但您可以安排它每天运行,并在实际开始工作之前检查日期是否为当月的第一天。 关于ruby-如何每月在Heroku运行一次Scheduler插件?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/8692687/
我有一个对象has_many应呈现为xml的子对象。这不是问题。我的问题是我创建了一个Hash包含此数据,就像解析器需要它一样。但是rails自动将整个文件包含在.........我需要摆脱type="array"和我该如何处理?我没有在文档中找到任何内容。 最佳答案 我遇到了同样的问题;这是我的XML:我在用这个:entries.to_xml将散列数据转换为XML,但这会将条目的数据包装到中所以我修改了:entries.to_xml(root:"Contacts")但这仍然将转换后的XML包装在“联系人”中,将我的XML代码修改为