2017-09-16 85 views
0

是否可以隐式传递self作为inout参数来修改参考变量?Swift作为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? 
+0

“*它可以将抽象基类转换为其具体子类之一*” - 为什么您有抽象基类的实例开始?你通常不想首先实例化一个抽象类。 – Hamish

回答

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

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

您不是“修改”或“转换”任何东西。你是代替一个对象换另一个。因此,没有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参数正在做什么。

+0

谢谢。目的还在于将原始对象的参数复制到新对象,同时取代该类型。将更新我的代码 – MH175

+0

“目的还在于将原始对象的参数复制到新对象”尽管如此,我没有看到这对我所说的有丝毫的区别。你可以将原件传递给原件,或者将原件发送给原件,但是出来的是另一个object_,并且你将它替换为原始的 – matt

0

我将提出一种完全不同的方式来看待你想要做的事情。

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

因此,要更改功能,只需将助手设置为不同类型的助手即可。基本上,你给你的对象个性化移植。

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

+0

这实际上是我一直在做的 - 我使用枚举定义了不同的特性。它实际上很有意义,因为这些类更像是没有父母(孤儿?)的兄弟姐妹。谢谢! – MH175

+0

这不是你在你展示的例子和你问的问题中所做的。 – matt