草庐IT

go - 对项目集合执行操作

coder 2024-07-08 原文

在我的实际代码中,我正在使用 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/

有关go - 对项目集合执行操作的更多相关文章

  1. ruby-openid:执行发现时未设置@socket - 2

    我在使用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

  2. ruby - 如何在 buildr 项目中使用 Ruby 代码? - 2

    如何在buildr项目中使用Ruby?我在很多不同的项目中使用过Ruby、JRuby、Java和Clojure。我目前正在使用我的标准Ruby开发一个模拟应用程序,我想尝试使用Clojure后端(我确实喜欢功能代码)以及JRubygui和测试套件。我还可以看到在未来的不同项目中使用Scala作为后端。我想我要为我的项目尝试一下buildr(http://buildr.apache.org/),但我注意到buildr似乎没有设置为在项目中使用JRuby代码本身!这看起来有点傻,因为该工具旨在统一通用的JVM语言并且是在ruby中构建的。除了将输出的jar包含在一个独特的、仅限ruby​​

  3. ruby-on-rails - 项目升级后 Pow 不会更改 ruby​​ 版本 - 2

    我在我的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服务器更新战俘

  4. ruby - Chef 执行非顺序配方 - 2

    我遵循了教程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

  5. ruby-on-rails - 新 Rails 项目 : 'bundle install' can't install rails in gemfile - 2

    我已经像这样安装了一个新的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="

  6. ruby - 为什么 Ruby 的 each 迭代器先执行? - 2

    我在用Ruby执行简单任务时遇到了一件奇怪的事情。我只想用每个方法迭代字母表,但迭代在执行中先进行:alfawit=("a".."z")puts"That'sanalphabet:\n\n#{alfawit.each{|litera|putslitera}}"这段代码的结果是:(缩写)abc⋮xyzThat'sanalphabet:a..z知道为什么它会这样工作或者我做错了什么吗?提前致谢。 最佳答案 因为您的each调用被插入到在固定字符串之前执行的字符串文字中。此外,each返回一个Enumerable,实际上您甚至打印它。试试

  7. Ruby 从大范围中获取第 n 个项目 - 2

    假设我有这个范围:("aaaaa".."zzzzz")如何在不事先/每次生成整个项目的情况下从范围中获取第N个项目? 最佳答案 一种快速简便的方法:("aaaaa".."zzzzz").first(42).last#==>"aaabp"如果出于某种原因你不得不一遍又一遍地这样做,或者如果你需要避免为前N个元素构建中间数组,你可以这样写:moduleEnumerabledefskip(n)returnto_enum:skip,nunlessblock_given?each_with_indexdo|item,index|yieldit

  8. ruby - 检查是否通过 require 执行或导入了 Ruby 程序 - 2

    如何检查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-检查是否

  9. postman——集合——执行集合——测试脚本——pm对象简单示例02 - 2

    //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

  10. ruby-on-rails - rbenv:从 RVM 移动到 rbenv 后,在 Jenkins 执行 shell 中找不到命令 - 2

    我从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

随机推荐