在我的实际代码中,我正在使用 encoding/xml 解析一个 XML 文档,我基本上有一堆如下形式的嵌套结构——所有这些都可能出现多次,除了顶级 statements 元素:
statements
statement
opcode
args
pre
post
我是 Go 的新手,我显然误解了 interface{}(空接口(interface))的工作原理:
.\stmtgen.go:58: cannot use print_name (type func(Statement)) as type func(interface {}) in argument to performAction
.\stmtgen.go:58: cannot use slist (type []Statement) as type []interface {} in argument to performAction
相关示例代码:
package main
import "fmt"
// Actually a structure in my code, but this suffices for demonstration.
type Opcode int
// A Statement has a Name and multiple Opcodes may use this Name.
type Statement struct {
Name string
Opcodes []Opcode
}
// Print the statement name.
func print_name(stmt Statement) {
fmt.Println(stmt.Name)
}
// Perform an action on each item of a collection.
func performAction(action func(interface{}), v []interface{}) {
for i := range v {
action(v[i])
}
}
func main() {
slist := make([]Statement, 3)
slist[0] = Statement{"Statement 1"}
slist[1] = Statement{"Statement 2"}
slist[2] = Statement{"Statement 3"}
//ERROR HERE
performAction(print_name, slist)
}
我必须创建函数来打印每种类型的值吗?
最佳答案
一个空的 interface{} 可以包含任何值并作为 interface{} 类型传递。当你需要它的值时,你可以像这样执行类型断言:
var anyValue interface{}
anyValue = "hello"
strValue := anyValue.(string)
如果 anyValue 不是被断言的类型,那么它将导致 panic
如果接口(interface)是具有多重返回的类型,则类型断言也可用于返回 bool
strValue, ok := anyValue.(string)
if ok {
//anyValue contains a string!
}
如果你不知道接口(interface)的类型,你可以像这样使用一个开关来确定它的类型:
switch val := anyValue.(type) {
case string:
// anyValue contains a string
// and val is a string
break
case int:
// anyValue contains an int
// and val is and int
break
default:
//unhandled interface type
}
希望这能让空接口(interface){}类型更清晰。
interfaces{...} 其中声明了方法是不同的,它们不能有成员(就像结构可以),只有方法,并且它们的底层类型必须实现接口(interface)中声明的所有方法。你可以有一个接口(interface) actionPerformer(接口(interface)名称应该有后缀“er”,因为它们正在做某事)
type actionPerformer interface {
action(interface{})
}
可以将实现接口(interface)中所有方法的类型强制转换为该接口(interface)类型,然后如果您在接口(interface)上调用这些方法之一,它将在基础类型上运行该方法。
例如,如果 Statement 结构实现了 action(interface{}) 方法,则 Statement 结构可以转换为 actionPerformer 类型,如果 action(interface {}) 函数在 actionPerformer 上被调用,Statement 结构上的 Action 函数被运行。因此,您可以拥有多种类型,它们都具有 action(interface{}) 方法,并且它们都可以转换为 actionPerformer,您可以在其上调用操作函数。
func (code Opcode) action(arg interface{}) {
fmt.Println(arg.(int) + int(code))
}
func (stmt Statement) action(arg interface{}) {
fmt.Println(arg.(string), stmt.Name)
}
stmt := Statement{"Statement 1", nil}
stmtActionPerformer := actionPerformer(stmt)
opcode := Opcode(5)
opcodeActionPerformer := actionPerformer(opcode)
stmtActionPerformer.action("hello") // will print "hello "+whatever the statements name is
opcodeActionPerformer.action(2) //will print be 7
类型断言仍然可以用在这些类型的接口(interface)上,例如
stmt := stmtActionPerformer.(Statement)
fmt.Println(stmt.Name)
这是一个人为的示例,但考虑到这一点,您可能希望使用这样的接口(interface)编写代码。 请记住,接口(interface)之间的转换成本很高,因此应谨慎进行,但如果使用得当,它们是一个强大的工具。
对于您的示例,一个简单的 printNames 函数将比所有接口(interface)转换更有效(请注意,在 golang 中,名称应采用 CamelCase 格式,而不是使用下划线)
func printNames(stmts []Statement) {
for _, stmt := range stmts {
fmt.Println(stmt.Name)
}
}
拥有一个类型 StatementList 并向其添加方法可能也很有用:
type StatementList []Statement
func (list StatementList) printNames() {
for _, stmt := range list {
fmt.Println(stmt.Name)
}
}
掌握这些东西会让 golang 变得更加有趣,希望这对您有所帮助:)
关于go - 对项目集合执行操作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36880335/
我在使用omniauth/openid时遇到了一些麻烦。在尝试进行身份验证时,我在日志中发现了这一点:OpenID::FetchingError:Errorfetchinghttps://www.google.com/accounts/o8/.well-known/host-meta?hd=profiles.google.com%2Fmy_username:undefinedmethod`io'fornil:NilClass重要的是undefinedmethodio'fornil:NilClass来自openid/fetchers.rb,在下面的代码片段中:moduleNetclass
如何在buildr项目中使用Ruby?我在很多不同的项目中使用过Ruby、JRuby、Java和Clojure。我目前正在使用我的标准Ruby开发一个模拟应用程序,我想尝试使用Clojure后端(我确实喜欢功能代码)以及JRubygui和测试套件。我还可以看到在未来的不同项目中使用Scala作为后端。我想我要为我的项目尝试一下buildr(http://buildr.apache.org/),但我注意到buildr似乎没有设置为在项目中使用JRuby代码本身!这看起来有点傻,因为该工具旨在统一通用的JVM语言并且是在ruby中构建的。除了将输出的jar包含在一个独特的、仅限ruby
我在我的Rails项目中使用Pow和powifygem。现在我尝试升级我的ruby版本(从1.9.3到2.0.0,我使用RVM)当我切换ruby版本、安装所有gem依赖项时,我通过运行railss并访问localhost:3000确保该应用程序正常运行以前,我通过使用pow访问http://my_app.dev来浏览我的应用程序。升级后,由于错误Bundler::RubyVersionMismatch:YourRubyversionis1.9.3,butyourGemfilespecified2.0.0,此url不起作用我尝试过的:重新创建pow应用程序重启pow服务器更新战俘
我遵循了教程http://gettingstartedwithchef.com/,第1章。我的运行list是"run_list":["recipe[apt]","recipe[phpap]"]我的phpapRecipe默认Recipeinclude_recipe"apache2"include_recipe"build-essential"include_recipe"openssl"include_recipe"mysql::client"include_recipe"mysql::server"include_recipe"php"include_recipe"php::modul
我已经像这样安装了一个新的Rails项目:$railsnewsite它执行并到达:bundleinstall但是当它似乎尝试安装依赖项时我得到了这个错误Gem::Ext::BuildError:ERROR:Failedtobuildgemnativeextension./System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/bin/rubyextconf.rbcheckingforlibkern/OSAtomic.h...yescreatingMakefilemake"DESTDIR="cleanmake"DESTDIR="
我在用Ruby执行简单任务时遇到了一件奇怪的事情。我只想用每个方法迭代字母表,但迭代在执行中先进行:alfawit=("a".."z")puts"That'sanalphabet:\n\n#{alfawit.each{|litera|putslitera}}"这段代码的结果是:(缩写)abc⋮xyzThat'sanalphabet:a..z知道为什么它会这样工作或者我做错了什么吗?提前致谢。 最佳答案 因为您的each调用被插入到在固定字符串之前执行的字符串文字中。此外,each返回一个Enumerable,实际上您甚至打印它。试试
假设我有这个范围:("aaaaa".."zzzzz")如何在不事先/每次生成整个项目的情况下从范围中获取第N个项目? 最佳答案 一种快速简便的方法:("aaaaa".."zzzzz").first(42).last#==>"aaabp"如果出于某种原因你不得不一遍又一遍地这样做,或者如果你需要避免为前N个元素构建中间数组,你可以这样写:moduleEnumerabledefskip(n)returnto_enum:skip,nunlessblock_given?each_with_indexdo|item,index|yieldit
如何检查Ruby文件是否是通过“require”或“load”导入的,而不是简单地从命令行执行的?例如:foo.rb的内容:puts"Hello"bar.rb的内容require'foo'输出:$./foo.rbHello$./bar.rbHello基本上,我想调用bar.rb以不执行puts调用。 最佳答案 将foo.rb改为:if__FILE__==$0puts"Hello"end检查__FILE__-当前ruby文件的名称-与$0-正在运行的脚本的名称。 关于ruby-检查是否
//1.验证返回状态码是否是200pm.test("Statuscodeis200",function(){pm.response.to.have.status(200);});//2.验证返回body内是否含有某个值pm.test("Bodymatchesstring",function(){pm.expect(pm.response.text()).to.include("string_you_want_to_search");});//3.验证某个返回值是否是100pm.test("Yourtestname",function(){varjsonData=pm.response.json
我从Ubuntu服务器上的RVM转移到rbenv。当我使用RVM时,使用bundle没有问题。转移到rbenv后,我在Jenkins的执行shell中收到“找不到命令”错误。我内爆并删除了RVM,并从~/.bashrc'中删除了所有与RVM相关的行。使用后我仍然收到此错误:rvmimploderm~/.rvm-rfrm~/.rvmrcgeminstallbundlerecho'exportPATH="$HOME/.rbenv/bin:$PATH"'>>~/.bashrcecho'eval"$(rbenvinit-)"'>>~/.bashrc.~/.bashrcrbenvversions