【问题标题】:Swift: limit classes only supported protocolSwift:限制类仅支持协议
【发布时间】:2016-04-07 15:28:56
【问题描述】:

我想实现只采用类支持协议的方法。为此,我定义了一个协议:

protocol TestProt {
    func testMe() -> String
}

让我们做一个类声明:

class TestClass: TestProt {
    func testMe() -> String {
        return "test"
    }
}

但是,我如何才能实现注册类,仅支持 TestProt 的类?

class FabricaClass {
    // it is func take any classes :(
    func registerMe(context: MyContext, class: AnyClass) -> String {
    }
    // i want something like this =)
    // to the method took only classes supported protocols
    // but it don't work for swift...
    func registerMe(context: MyContext, class: AnyClass <TestProt>) -> String {
    }

}

UPD:回答

protocol TestProt {
    static func testMe() -> String
}

class TestClass: TestProt {
    class func testMe() -> String {
        return "test"
    }
}

class MyContext {
}

class FactoryClass {
    init<T: TestProt>(context: MyContext, regClass: T.Type) {
        regClass.testMe()
    }
}

let context = MyContext()
let factory = FactoryClass(context: context, regClass: TestClass.self)

感谢@dfri

【问题讨论】:

标签: swift


【解决方案1】:

你需要在你的函数中包含一个泛型类型,并为这个泛型类型添加一个类型约束,其中类型约束确保使用该函数的类型符合用作类型约束的协议.例如:

/* add :class keyword to constrain this protocol only
 to be conformable to by class types */
protocol ProtocolOnlyIntendedForClasses: class {
    func foo() -> String
    init() // to make use of metaType for initialization in generic function
}

class Foo: ProtocolOnlyIntendedForClasses {
    func foo() -> String {
        return "foo"
    }
    required init() { }
}

/* function taking class type objects that conforms
   to ProtocolOnlyIntendedForClasses */
func bar<T: ProtocolOnlyIntendedForClasses>(foo: T) -> String {
    return foo.foo()
}

/* as above, but making use of metatype representation
   of generic T rather than an instance of it */
func barWithMetaType<T: ProtocolOnlyIntendedForClasses>(fooMetaType: T.Type) -> String {

    // ..

    return fooMetaType.init().foo()
}

/* example usage */
let foo = Foo()
let baz = bar(foo)
let bax = barWithMetaType(Foo.self)
print(baz, bax) // foo foo

我们使用T.TypeT 的类型作为元类型访问。

应用于您的具体示例:

// ...

class FabricaClass {

    // ...

    // as specified in comments, you want the class (meta)type,
    // rather than an instance of it
    func registerMe<T: TestProt>(context: MyContext, someMetaType: T.Type) -> String {

        // ...

        return someMetaType.init().testMe()
            // given that you added blueprint for 'init()' in protocol TestProt
    }

}

但是请注意,使用元类型(上述registerMe(..) 函数中的someMetaType)非常有限,并不等同于使用静态(编译时已知)类型。


更多详情,请参考

【讨论】:

  • 不,我需要在方法中获取 Class,而不是 Instans
  • @EvGeniyIlyin 用 metatypes 类型约束泛型而不是类型约束泛型实例更新了答案。
  • @EvGeniyIlyin 很高兴为您提供帮助!
【解决方案2】:

你试过了吗?

func registerMe(context: MyContext, class: TestProt) -> String {
}

【讨论】:

    【解决方案3】:

    我不确定您是否真的希望将其限制在课程中,还是您的意思是:

    我如何实现注册类,仅支持类型 测试Prot?

    无论如何,如果您想限制类,请参阅@dfri 的回复。对于剩下的问题,有两种方法。有通用的方法:

    fund registerMe<T: TestProt>(context: MyContext, class:T) -> String {}
    

    其中 T 采用它传递的类型。例如,如果此方法要返回与 class 相同类型的类型(而不是 String),则编译器会知道正在返回 TestClass 实例。但另一方面:

    func registerMe(context: MyContext, class:TestProt) -> String {}
    

    您正在转换为 TestProt,因此虽然 dynamicType 在运行时仍将是 TestClass,但您无法返回与传递给该方法的类型相同的类型。您只能将实例作为符合 TestProt 的实例发回。然后你需要转换回实际的类。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-03-21
      • 2013-07-13
      • 2014-10-02
      • 2021-12-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多