Swift隐式传递self作为引用类型的inout参数

时间:2017-09-16 17:25:32

标签: swift

是否可以隐式传递self作为inout参数来修改参考变量?

这是一个可以将抽象基类转换为其具体子类之一的方法。我的问题是,我是否必须始终拥有第一个论点obj: inout AbstractBaseClass,或者我可以隐含地传递自我。我意识到这也可以表示为静态方法。

    func convertTo(_ obj: inout AbstractBaseClass, _ type: ConcreteClassTypes) {
        switch type {
        case .concreteClass1: obj = ConreteClass1()
        case .concreteClass2: obj = ConcreteClass2()
        }
    }

以下是完整代码:

class AbstractClass {

    enum ConcreteType {
        case concreteClass1
        case concreteClass2
    }

    var id: Int = 0

    fileprivate init() { }

    func convert(_ obj: inout AbstractClass, to type: ConcreteType) {

        let oldId = obj.id

        switch type {
        case .concreteClass1: obj = ConcreteClass1()
        case .concreteClass2: obj = ConcreteClass2()
        }

        obj.id = oldId
    }

    class ConcreteClass1: AbstractClass {

        override init() { super.init() }
    }

    class ConcreteClass2: AbstractClass {

        override init() { super.init() }

    }

}

var obj: AbstractClass = AbstractClass.ConcreteClass1()
obj.convert(&obj, to: .concreteClass2) //is there any way to eliminate this first argument?

3 个答案:

答案 0 :(得分:2)

像亚特一样,在这种情况下,我不相信inout是适合这项工作的工具。

虽然如此,如果你坚持下去,实现你想要的一种方法是(ab)使用协议扩展。它们允许定义mutating方法,它将隐式self参数传递为inout(以允许采用值类型的变异)。

所以你可以说:

protocol AbstractClassProtocol {}

class AbstractClass : AbstractClassProtocol {

    enum ConcreteType {
        case concreteClass1
        case concreteClass2
    }

    fileprivate init() {}

    class ConcreteClass1: AbstractClass {
        override init() { super.init() }
    }

    class ConcreteClass2: AbstractClass {
        override init() { super.init() }
    }
}

extension AbstractClassProtocol where Self == AbstractClass {

    mutating func convert(to type: AbstractClass.ConcreteType) {
        switch type {
        case .concreteClass1:
            self = AbstractClass.ConcreteClass1()
        case .concreteClass2:
            self = AbstractClass.ConcreteClass2()
        }
    }
}

var obj: AbstractClass = AbstractClass.ConcreteClass1()
obj.convert(to: .concreteClass2)
print(obj) // AbstractClass.ConcreteClass2

但这有点像黑客,我对使用它很谨慎。

答案 1 :(得分:1)

  

...修改参考变量到位?这是一个可以将抽象基类转换为其具体子类之一的方法......

您没有“修改”或“转换”任何内容。您一个对象替换为另一个对象。因此,没有self可以通过这里;你正在做的事情的想法是销毁一个self并在其位置提供另一个。

那就是说,inout变量的含义有点不清楚。为什么不直接分配新对象来代替旧对象?

func giveMeA( _ type: AbstractClass.ConcreteType) -> AbstractClass {
    switch type {
    case .concreteClass1: return AbstractClass.ConcreteClass1()
    case .concreteClass2: return AbstractClass.ConcreteClass2()
    }
}

var obj: AbstractClass = AbstractClass.ConcreteClass1()
obj = giveMeA(.concreteClass2)

效果与您正在做的事情完全相同。如果您认为不是,那么您只是在嘲笑inout参数正在做什么。

答案 2 :(得分:0)

我将提出一种完全不同的方式来看待你正在尝试做的事情。

没有抽象的超类。没有多个子类。拥有一个具有多个功能变体的类。函数变体由辅助对象表示 - 一个由类实例拥有的结构。

因此,要更改功能,只需将帮助程序设置为其他类型的帮助程序即可。基本上,你给对象一个人格移植。

我有一个以这种方式运作的应用程序。我有四个视图控制器,以略微不同的方式呈现略有不同的信息。但实际上它们是一个视图控制器和一个枚举,其中有四个案例决定了这些差异。因此,在任何时候,视图控制器都可以将其自身表现为四种类型中的任何一种。