【问题标题】:What is this syntax in swift? factoryMethod()(self)swift中的这种语法是什么?工厂方法()(自我)
【发布时间】:2014-08-20 17:57:42
【问题描述】:

所以我在 Swift 中玩惰性实例化,并尝试在 swift 中完全复制以下 Objective C 范式

//A Getter for a strong property
- (SomeObject)lazilyLoadedObject {
    if (!_lazilyLoadedObject) {
        _lazilyLoadedObject = [[SomeObject alloc] init];
        __weak typeOf(self) weakSelf = self;
        _lazilyLoadedObject.blockProperty = ^(){//Some block which relies on weakSelf};
    }
    return _lazilyLoadedObject;
}

然后我尝试执行以下操作,并惊讶地发现编译失败并显示 Global is external, but doesn't have external or weak linkage!

lazy var lazilyLoadedObject: SomeObject = {
    var instance = SomeObject()
    instance.closureProperty = {[weak self] in
        //Do something with weak self
    }
    return instance
}()

所以我的第一个问题是,当我们需要对 self 的引用时,上述用于惰性实例化的 sn-p 有什么问题?

确定之后我遇到了以下 sn-p(主要是由于代码完成)。

lazy var lazilyLoadedObject: SomeObject = instantiateLazilyLoadedObject(self)()
func instantiateLazilyLoadedObject() -> SomeObject {
        var instance = SomeObject()
        instance.closureProperty = {[weak self] in
            //Do something with weak self
        }
    return instance
}

这到底是什么^ (self)()?一点谷歌搜索表明这是一个“咖喱函数”,但我真的不明白。什么方法将 self 作为参数并返回一个函数?是不是有些东西被抽象掉了,还有另一层我没有看到(也许有一种更冗长的方式来写这个?)。最后,这是将目标 C 的顶部片段转换为 swift 的正确方法吗?

【问题讨论】:

    标签: swift


    【解决方案1】:

    这看起来很像一个编译器错误(特别是因为它显示为链接故障而不是编译器故障)。我会打开雷达。你应该得到一个编译器错误(而不是一个链接错误),或者它应该编译。您现在可能无法将其翻译成 Swift。

    但我可以回答第二个问题。正如你所说,这是一个柯里化函数。

    每个方法实际上都是一个函数,它以柯里化的方式将“对象”作为其第一个参数(等待它;我会解释)。

    考虑一下:

    struct X {
      func doit() { println("Yes") }
    }
    

    简单。现在让我们做一个:

    let x = X()
    x.doit()
    

    正如您所期望的那样输出“是”。但x.doit() 正是如下:

    X.doit(x)()
    

    疯了,双括号是怎么回事? doit 方法实际上是一个具有以下签名的函数:

    func doit(self: X) -> (() -> Void)
    

    这是一个接受X 并返回一个不接受任何内容且不返回任何内容的函数。再读一遍。它是一个返回函数的函数。

    Currying(以 Haskell Curry 命名)是将一个接受多个参数的函数转换为一个只接受一个参数的函数并返回一个接受下一个参数的函数的做法。在许多情况下,这非常方便,构造方法就是其中之一。

    所以,x.doit(注意没有括号;我指的是实际方法本身)完全X.doit(x)(返回一个函数)相同。我可以将其中任何一个分配给另一个名称:

    let doitMethod = x.doit
    let doitFunc = X.doit(x)
    

    这两个是相同的。我可以将它们中的任何一个用作:

    doitMethod()
    doitFunc()
    

    这让我们回到了这个问题。 instantiateLazilyLoadedObject 是一种方法。或者它是一个接受一个对象并返回一个函数的函数。这两个陈述的意思完全相同。也就是说,instantiateLazilyLoadedObject 几乎可以肯定是一个私有实现细节,因为它不在 Swift 标头中(而且它真的,真的听起来像是一个内部实现细节)。最后,您几乎肯定会遇到编译器错误,应该对此展开关注。

    【讨论】:

    • 有趣且很有帮助。是否有明显/合乎逻辑的原因为什么会以这种方式设计语言(所有函数都是柯里化函数的抽象),还是只是为了允许使用柯里化而采取的设计决策的意外副作用?
    • 这是一种非常简单灵活的方法,可以将方法视为函数,因此可以将它们作为一等对象传递。这在 ObjC 中一直是一件很难实现的事情。您可以传递函数指针,但不能传递方法指针。我怀疑 currying 已经被选为一个特性,所以它应该是一个合理的 currying 应用,而不是发明一些新技术来实现它。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-09-24
    • 1970-01-01
    • 1970-01-01
    • 2010-10-30
    • 2016-01-21
    • 1970-01-01
    相关资源
    最近更新 更多