我想实现只接受类支持的协议的方法。为此,我定义了一个协议:
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
答案 0 :(得分:3)
您需要在函数中包含泛型类型并向此泛型类型添加类型约束,其中类型约束确保使用该函数的类型符合用作类型约束的协议。 E.g:
/* 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
将T.Type
的类型作为元数据类型进行了访问。
适用于您的具体示例:
// ...
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
}
}
但请注意,使用元类型(someMetaType
函数中的registerMe(..)
}非常有限,并不等同于使用静态(编译时已知)类型。
有关其他详细信息,请参阅
答案 1 :(得分:0)
你试过这个吗?
func registerMe(context: MyContext, class: TestProt) -> String {
}
答案 2 :(得分:0)
我不确定你是否真的希望它仅限于课程或是否意味着:
我如何实现寄存器类,仅支持 types TestProt?
无论如何,如果你想限制课程,请参阅@ dfri的回复。对于其余问题,有两种方法。有通用的方法:
fund registerMe<T: TestProt>(context: MyContext, class:T) -> String {}
其中T采用传递的类型。例如,如果此方法返回与类相同类型的类型(而不是String
),则编译器将知道正在返回TestClass
实例。但另一方面:
func registerMe(context: MyContext, class:TestProt) -> String {}
您正在转换为TestProt,因此虽然dynamicType在运行时仍然是TestClass
,但您无法返回与传递给方法相同的类型。您只能将实例作为符合TestProt的实例发回。然后你需要回到实际的班级。