草庐IT

swift - 结构的闭包属性可以在没有显式引用的情况下引用结构实例吗?

coder 2023-09-17 原文

这是我想做的,但是 quantity 属性不可用。

struct MyStruct {
    var quantity: Int
    let valueFn: () -> (Int)
}
var s1 = MyStruct(quantity: 2) { () -> (Int) in
    return quantity * 2 // error: can't use `quantity`
}

它也不适用于类:

class MyClass {
    var quantity: Int
    let valueFn: () -> (Int)

    init(valueFn: () -> (Int)) {
        self.valueFn = valueFn
    }
}
var c1 = MyClass { () -> (Int) in
    return quantity // error: can't use quantity or self
}

这个有效,但我必须显式传递 struct 或 struct 属性。 我的问题是:我可以在没有第三个属性包装和传递引用的情况下执行此操作吗?是否有更 Swifty 的方法?

struct MyOtherStruct {
    var quantity: Int
    private let valueFn: (Int) -> (Int)
    var value: Int {
        return valueFn(quantity)
    }
}
var s3 = MyOtherStruct(quantity: 2) { (quantity) -> (Int) in
    return quantity * 2
}
s3.value // -> 4

最佳答案

我在过去 20 分钟里一直在胡说八道,我认为这不可能在您的 MyStruct 实例的初始化 中实现;因为在对初始化程序的调用(您使用上面的尾随闭包执行的操作)中,实例 尚不存在。但是,我将在下面展示类(class)的解决方法;一种很像上面的第三种方法,一种具有更通用的用法(但类实现非常糟糕),利用子类化 NSObject

无论如何,关于直接与以一种通用的方式初始化。


下面是

  1. 闭包“包装”方法是您的第三种解决方案:在初始化时发送的闭包上包装惰性闭包。这种方法的缺点是,对于不同的类实例,您无法选择要在闭包中使用哪些类属性,因为包装器(调用可变初始化闭包)已经在编译时设置。

  2. 子类化 NSObject:一种对于任何实际使用来说可能都过于复杂的方法(而且相当不敏捷),但是它可以让您更灵活地控制要在其中使用哪些类属性关闭。通过子类化 NSObject,您可以访问方法 .valueForKey 以应用于 self。为技术讨论/好奇添加。

方法一

class MyClass {
    var quantity: Int
    private let closure: (Int) -> (Int)

    init(quantity: Int, closure: (Int) -> (Int)) {
        self.quantity = quantity
        self.closure = closure
    }

    lazy var valueFn : () -> Int = {
        [unowned self] () -> Int in
        return self.closure(self.quantity)
    }
}

/* Example usage */
var c1 = MyClass(quantity: 2) { (a) -> (Int) in
    return a * 2
}

c1.valueFn() // 4
c1.quantity = 4
c1.valueFn() // 8

方法二

类设置(...):

class MyClass : NSObject {
    var quantity: Int = 0
    var anotherQuantity: Int = 0
    private var keyExists : Bool = true
    private let key : String
    private let foo: (Int) -> Int

    init(operateClosureOn: (propertyWithKey: String, withInitialValue: Int),
        closure: (Int) -> Int) {
        key = operateClosureOn.propertyWithKey
        foo = closure

        super.init()

        let val = operateClosureOn.withInitialValue
        if let _ = (Mirror(reflecting: self).children.filter{ $0.label == key }).first {
            self.setValue(val, forKey: key)
        }
        else { keyExists = false }
    }

    lazy var valueFn: () -> Int = {
        [unowned self] () -> Int in

        if !self.keyExists {
            return 0
        }

        guard let a = self.valueForKey(self.key) as? Int else {
            print("Unexpected: property for key '\(self.key)' is not if type 'Int'.")
            return 0
        }

        return self.foo(a)
    }
}

示例用法:

/* Example usage */
var c2 = MyClass(operateClosureOn: ("quantity", 2)) {
    (val) -> Int in
    return 2 * val
}

c2.valueFn() // 4
c2.quantity = 4
c2.valueFn() // 8

var c3 = MyClass(operateClosureOn: ("anotherQuantity", 20)) {
    (val) -> Int in
    return val / 2
}

c3.valueFn() // 10
c3.anotherQuantity = 40
c3.valueFn() // 20


var c4 = MyClass(operateClosureOn: ("aTypo", 20)) {
    (val) -> Int in
    return val / 2
}

c4.valueFn() // 0, OK, at least no runtime exception with this non-safe non-swifty solution :0)

关于swift - 结构的闭包属性可以在没有显式引用的情况下引用结构实例吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35205520/

有关swift - 结构的闭包属性可以在没有显式引用的情况下引用结构实例吗?的更多相关文章

  1. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

    类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

  2. ruby - 使用 ruby​​ 将 HTML 转换为纯文本并维护结构/格式 - 2

    我想将html转换为纯文本。不过,我不想只删除标签,我想智能地保留尽可能多的格式。为插入换行符标签,检测段落并格式化它们等。输入非常简单,通常是格式良好的html(不是整个文档,只是一堆内容,通常没有anchor或图像)。我可以将几个正则表达式放在一起,让我达到80%,但我认为可能有一些现有的解决方案更智能。 最佳答案 首先,不要尝试为此使用正则表达式。很有可能你会想出一个脆弱/脆弱的解决方案,它会随着HTML的变化而崩溃,或者很难管理和维护。您可以使用Nokogiri快速解析HTML并提取文本:require'nokogiri'h

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

  4. ruby - 使用 Vim Rails,您可以创建一个新的迁移文件并一次性打开它吗? - 2

    使用带有Rails插件的vim,您可以创建一个迁移文件,然后一次性打开该文件吗?textmate也可以这样吗? 最佳答案 你可以使用rails.vim然后做类似的事情::Rgeneratemigratonadd_foo_to_bar插件将打开迁移生成的文件,这正是您想要的。我不能代表textmate。 关于ruby-使用VimRails,您可以创建一个新的迁移文件并一次性打开它吗?,我们在StackOverflow上找到一个类似的问题: https://sta

  5. ruby-on-rails - 如果为空或不验证数值,则使属性默认为 0 - 2

    我希望我的UserPrice模型的属性在它们为空或不验证数值时默认为0。这些属性是tax_rate、shipping_cost和price。classCreateUserPrices8,:scale=>2t.decimal:tax_rate,:precision=>8,:scale=>2t.decimal:shipping_cost,:precision=>8,:scale=>2endendend起初,我将所有3列的:default=>0放在表格中,但我不想要这样,因为它已经填充了字段,我想使用占位符。这是我的UserPrice模型:classUserPrice回答before_val

  6. ruby - 我可以使用 Ruby 从 CSV 中删除列吗? - 2

    查看Ruby的CSV库的文档,我非常确定这是可能且简单的。我只需要使用Ruby删除CSV文件的前三列,但我没有成功运行它。 最佳答案 csv_table=CSV.read(file_path_in,:headers=>true)csv_table.delete("header_name")csv_table.to_csv#=>ThenewCSVinstringformat检查CSV::Table文档:http://ruby-doc.org/stdlib-1.9.2/libdoc/csv/rdoc/CSV/Table.html

  7. ruby-on-rails - 在混合/模块中覆盖模型的属性访问器 - 2

    我有一个包含模块的模型。我想在模块中覆盖模型的访问器方法。例如:classBlah这显然行不通。有什么想法可以实现吗? 最佳答案 您的代码看起来是正确的。我们正在毫无困难地使用这个确切的模式。如果我没记错的话,Rails使用#method_missing作为属性setter,因此您的模块将优先,阻止ActiveRecord的setter。如果您正在使用ActiveSupport::Concern(参见thisblogpost),那么您的实例方法需要进入一个特殊的模块:classBlah

  8. 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(

  9. ruby - 默认情况下使选项为 false - 2

    这是在Ruby中设置默认值的常用方法:classQuietByDefaultdefinitialize(opts={})@verbose=opts[:verbose]endend这是一个容易落入的陷阱:classVerboseNoMatterWhatdefinitialize(opts={})@verbose=opts[:verbose]||trueendend正确的做法是:classVerboseByDefaultdefinitialize(opts={})@verbose=opts.include?(:verbose)?opts[:verbose]:trueendend编写Verb

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

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

随机推荐