草庐IT

ios - 有没有办法在调用 SequenceType.forEach 时引用实例函数?

coder 2023-09-06 原文

考虑 Foo 类型:

class Foo {

    var isBaz: Bool {
        return false
    }

    func bar() {
        print("some boring print")
    }
}

现在假设我想遍历类实例的集合并对它们中的每一个调用一些函数:

let someFoos: [Foo] = [Foo(), Foo(), Foo()]

someFoos.forEach { $0.bar() }

这个语法挺简洁的,但是感觉有点别扭。此外,它不能在任何地方使用。例如,在 if 语句条件中:

if someFoos.contains { $0.isBaz } { 
    // compiler error: statement cannot begin with a closure expression
}

if someFoos.contains($0.isBaz) { 
    // compiler error: anonymous closure argument not contained in a closure
}

if someFoos.contains({ $0.isBaz }) { 
    // this is correct, but requires extra pair of parentheses
}

理想情况下,写这样的东西会很好

someFoos.forEach(Foo.bar)

但是从 Swift 2.1 开始,这不是一个正确的语法。这种引用函数的方式类似于以下内容:

func bar2(foo: Foo) -> Void {
    print("some boring print")
}

someFoos.forEach(bar2)

有没有更好的方法来引用实例函数?你喜欢怎么写这样的表达方式?

最佳答案

这里有两个不同的问题。 尾随闭包语法 可以在调用函数时使用,最后一个参数是闭包, 所以

let b1 = someFoos.contains({ $0.isBaz })
let b2 = someFoos.contains { $0.isBaz }

完全等价。但是,尾随闭包语法在 if 语句的条件下可能会出现问题:

if someFoos.contains({ $0.isBaz }) { }  // OK
if someFoos.contains { $0.isBaz } { }   // Compiler error
if (someFoos.contains { $0.isBaz }) { } // OK, as noted by R Menke

我们只能推测为什么第二个不起作用。可能是编译器 将第一个 { 作为 if-body 的开始。也许这会 在 Swift 的 future 版本中进行更改,但可能不值得 努力。


另一个问题是关于柯里化(Currying)函数

someFoos.forEach(bar2)

编译是因为 bar2 的类型是 Foo -> Void,这正是 forEach() 方法需要什么。 Foo.bar 另一方面, 是一个 curry 函数(参见 http://oleb.net/blog/2014/07/swift-instance-methods-curried-functions/ ),它将实例作为第一个 争论。它的类型为 Foo -> () -> ()。所以

Foo.bar(someFoo)

是类型为 () -> () 的闭包,并且

Foo.bar(someFoo)()

someFoo 实例上调用 bar 方法。

(注意:以下内容并非实际建议, 但仅作为有关柯里化(Currying)函数和乐趣的演示 有闭包!)

要将 Foo.bar 作为参数直接传递给 forEach() 我们需要 “交换”参数的顺序。为此,Haskell 有一个“翻转”功能, 在 Swift 中也是可能的(参见例如 How to write a flip method in Swift? ):

func flip<A, B, C>(f: A -> B ->C) -> B -> A ->C {
    return { b in { a in f(a)(b) } }
}

那么 flip(Foo.bar) 的类型是 () -> Foo -> (),所以 可以应用 bar 方法的 void 参数

flip(Foo.bar)()

获取 Foo -> () 闭包,以及

flip(Foo.bar)()(someFoo)

someFoo 实例上调用 bar 方法。 现在我们可以调用

someFoos.forEach (flip(Foo.bar)())

不使用闭包表达式 { .. } !!

如果 isBaz 是一个方法而不是一个属性

func isBaz() -> Bool { return false }

那你 可以在 if 表达式中做同样的事情:

if someFoos.contains(flip(Foo.isBaz)()) { 
    // ...
}

再次声明,这只是一个演示。还有属性 不是 curry 函数,所以这不能用 你的 isBaz 属性。

关于ios - 有没有办法在调用 SequenceType.forEach 时引用实例函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34049116/

有关ios - 有没有办法在调用 SequenceType.forEach 时引用实例函数?的更多相关文章

  1. ruby - 难道Lua没有和Ruby的method_missing相媲美的东西吗? - 2

    我好像记得Lua有类似Ruby的method_missing的东西。还是我记错了? 最佳答案 表的metatable的__index和__newindex可以用于与Ruby的method_missing相同的效果。 关于ruby-难道Lua没有和Ruby的method_missing相媲美的东西吗?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/7732154/

  2. ruby-on-rails - rails 目前在重启后没有安装 - 2

    我有一个奇怪的问题:我在rvm上安装了ruby​​onrails。一切正常,我可以创建项目。但是在我输入“railsnew”时重新启动后,我有“程序'rails'当前未安装。”。SystemUbuntu12.04ruby-v"1.9.3p194"gemlistactionmailer(3.2.5)actionpack(3.2.5)activemodel(3.2.5)activerecord(3.2.5)activeresource(3.2.5)activesupport(3.2.5)arel(3.0.2)builder(3.0.0)bundler(1.1.4)coffee-rails(

  3. ruby-on-rails - 如何使用 instance_variable_set 正确设置实例变量? - 2

    我正在查看instance_variable_set的文档并看到给出的示例代码是这样做的:obj.instance_variable_set(:@instnc_var,"valuefortheinstancevariable")然后允许您在类的任何实例方法中以@instnc_var的形式访问该变量。我想知道为什么在@instnc_var之前需要一个冒号:。冒号有什么作用? 最佳答案 我的第一直觉是告诉你不要使用instance_variable_set除非你真的知道你用它做什么。它本质上是一种元编程工具或绕过实例变量可见性的黑客攻击

  4. ruby 正则表达式 - 如何替换字符串中匹配项的第 n 个实例 - 2

    在我的应用程序中,我需要能够找到所有数字子字符串,然后扫描每个子字符串,找到第一个匹配范围(例如5到15之间)的子字符串,并将该实例替换为另一个字符串“X”。我的测试字符串s="1foo100bar10gee1"我的初始模式是1个或多个数字的任何字符串,例如,re=Regexp.new(/\d+/)matches=s.scan(re)给出["1","100","10","1"]如果我想用“X”替换第N个匹配项,并且只替换第N个匹配项,我该怎么做?例如,如果我想替换第三个匹配项“10”(匹配项[2]),我不能只说s[matches[2]]="X"因为它做了两次替换“1fooX0barXg

  5. ruby - 在没有 sass 引擎的情况下使用 sass 颜色函数 - 2

    我想在一个没有Sass引擎的类中使用Sass颜色函数。我已经在项目中使用了sassgem,所以我认为搭载会像以下一样简单:classRectangleincludeSass::Script::FunctionsdefcolorSass::Script::Color.new([0x82,0x39,0x06])enddefrender#hamlengineexecutedwithcontextofself#sothatwithintemlateicouldcall#%stop{offset:'0%',stop:{color:lighten(color)}}endend更新:参见上面的#re

  6. ruby-on-rails - 在 ruby​​ 中使用 gsub 函数替换单词 - 2

    我正在尝试用ruby​​中的gsub函数替换字符串中的某些单词,但有时效果很好,在某些情况下会出现此错误?这种格式有什么问题吗NoMethodError(undefinedmethod`gsub!'fornil:NilClass):模型.rbclassTest"replacethisID1",WAY=>"replacethisID2andID3",DELTA=>"replacethisID4"}end另一个模型.rbclassCheck 最佳答案 啊,我找到了!gsub!是一个非常奇怪的方法。首先,它替换了字符串,所以它实际上修改了

  7. ruby - 在 Ruby 中有条件地定义函数 - 2

    我有一些代码在几个不同的位置之一运行:作为具有调试输出的命令行工具,作为不接受任何输出的更大程序的一部分,以及在Rails环境中。有时我需要根据代码的位置对代码进行细微的更改,我意识到以下样式似乎可行:print"Testingnestedfunctionsdefined\n"CLI=trueifCLIdeftest_printprint"CommandLineVersion\n"endelsedeftest_printprint"ReleaseVersion\n"endendtest_print()这导致:TestingnestedfunctionsdefinedCommandLin

  8. ruby-on-rails - Rails - 从另一个模型中创建一个模型的实例 - 2

    我有一个正在构建的应用程序,我需要一个模型来创建另一个模型的实例。我希望每辆车都有4个轮胎。汽车模型classCar轮胎模型classTire但是,在make_tires内部有一个错误,如果我为Tire尝试它,则没有用于创建或新建的activerecord方法。当我检查轮胎时,它没有这些方法。我该如何补救?错误是这样的:未定义的方法'create'forActiveRecord::AttributeMethods::Serialization::Tire::Module我测试了两个环境:测试和开发,它们都因相同的错误而失败。 最佳答案

  9. ruby - 如何验证 IO.copy_stream 是否成功 - 2

    这里有一个很好的答案解释了如何在Ruby中下载文件而不将其加载到内存中:https://stackoverflow.com/a/29743394/4852737require'open-uri'download=open('http://example.com/image.png')IO.copy_stream(download,'~/image.png')我如何验证下载文件的IO.copy_stream调用是否真的成功——这意味着下载的文件与我打算下载的文件完全相同,而不是下载一半的损坏文件?documentation说IO.copy_stream返回它复制的字节数,但是当我还没有下

  10. ruby-on-rails - RSpec:避免使用允许接收的任何实例 - 2

    我正在处理旧代码的一部分。beforedoallow_any_instance_of(SportRateManager).toreceive(:create).and_return(true)endRubocop错误如下:Avoidstubbingusing'allow_any_instance_of'我读到了RuboCop::RSpec:AnyInstance我试着像下面那样改变它。由此beforedoallow_any_instance_of(SportRateManager).toreceive(:create).and_return(true)end对此:let(:sport_

随机推荐