[英]Get the name (string) of a generic type in Swift
I have a generic class of type T and I would like to get the name of the type that passed into the class when instantiated.我有一个类型为 T 的泛型类,我想获取实例化时传入该类的类型的名称。 Here is an example.
这是一个例子。
class MyClass<T> {
func genericName() -> String {
// Return the name of T.
}
}
I have been looking around for hours and I can't seem to find any way to do this.我已经环顾了几个小时,但似乎找不到任何方法来做到这一点。 Has anyone tried this yet?
有没有人试过这个?
Any help is greatly appreciated.任何帮助是极大的赞赏。
Thanks谢谢
You can return any types' name by using string interpolation:您可以使用字符串插值返回任何类型的名称:
class MyClass<T> {
func genericName() -> String {
return "\(T.self)"
}
}
You can try it in a playground and it works as expected:您可以在操场上尝试它,它按预期工作:
var someClass = MyClass<String>()
someClass.genericName() // Returns "Swift.String"
String(describing: T.self)
in Swift 3+ String(describing: T.self)
3+var genericTypeName: String {
return String(describing: T.self)
}
Within the generic type, get the name of type T
by converting T.self
or type(of: T.self)
to a String
.在泛型类型中,通过将
T.self
或type(of: T.self)
转换为String
来获取类型T
的名称。 I found that type(of:)
was not necessary but it's worth being aware of since in other cases it removes other details about the Type.我发现
type(of:)
不是必需的,但值得注意,因为在其他情况下它会删除有关 Type 的其他详细信息。
The following example demonstrates getting the name of the generic type T
within a struct and a class.以下示例演示如何在结构和类中获取泛型类型
T
的名称。 It includes code to get the name of the containing type.它包含用于获取包含类型名称的代码。
struct GenericStruct<T> {
var value: T
var genericTypeName: String {
return String(describing: T.self)
}
var genericTypeDescription: String {
return "Generic Type T: '\(genericTypeName)'"
}
var typeDescription: String {
// type(of:) is necessary here to exclude the struct's properties from the string
return "Type: '\(type(of: self))'"
}
}
class GenericClass<T> {
var value: T
var genericTypeName: String {
return String(describing: T.self)
}
var genericTypeDescription: String {
return "Generic Type T: '\(genericTypeName)'"
}
var typeDescription: String {
let typeName = String(describing: self)
return "Type: '\(typeName)'"
}
init(value: T) {
self.value = value
}
}
enum TestEnum {
case value1
case value2
case value3
}
let intGenericStruct: GenericStruct<Int> = GenericStruct(value: 1)
print(intGenericStruct.typeDescription)
print(intGenericStruct.genericTypeDescription)
let enumGenericStruct: GenericStruct<TestEnum> = GenericStruct(value: .value2)
print(enumGenericStruct.typeDescription)
print(enumGenericStruct.genericTypeDescription)
let intGenericClass: GenericClass<Int> = GenericClass(value: 1)
print(intGenericClass.typeDescription)
print(intGenericClass.genericTypeDescription)
let enumGenericClass: GenericClass<TestEnum> = GenericClass(value: .value2)
print(enumGenericClass.typeDescription)
print(enumGenericClass.genericTypeDescription)
/*
Type: 'GenericStruct<Int>'
Generic Type T: 'Int'
Type: 'GenericStruct<TestEnum>'
Generic Type T: 'TestEnum'
Type: 'GenericClass<Swift.Int>'
Generic Type T: 'Int'
Type: 'GenericClass<TestEnum>'
Generic Type T: 'TestEnum'
*/
A pure swift way to achieve that is not possible.实现这一目标的纯粹快捷方式是不可能的。
A possible workaround is:一个可能的解决方法是:
class MyClass<T: AnyObject> {
func genericName() -> String {
let fullName: String = NSStringFromClass(T.self)
let range = fullName.rangeOfString(".", options: .BackwardsSearch)
if let range = range {
return fullName.substringFromIndex(range.endIndex)
} else {
return fullName
}
}
}
The limitations relies on the fact that it works with classes only.限制依赖于它仅适用于类的事实。
If this is the generic type:如果这是泛型类型:
class TestClass {}
NSStringFromClass()
returns the full name (including namespace): NSStringFromClass()
返回全名(包括命名空间):
// Prints something like "__lldb_expr_186.TestClass" in playground
NSStringFromClass(TestClass.self)
That's why the func searches for the last occurrence of the .
这就是为什么 func 搜索最后一次出现的
.
character.特点。
Tested as follows:测试如下:
var x = MyClass<TestClass>()
x.genericName() // Prints "TestClass"
UPDATE Swift 3.0更新斯威夫特 3.0
func genericName() -> String {
let fullName: String = NSStringFromClass(T.self)
let range = fullName.range(of: ".")
if let range = range {
return fullName.substring(from: range.upperBound)
}
return fullName
}
It's possible if your type parameter implements a common naming protocol.如果您的类型参数实现了通用命名协议,则有可能。
In the example below the protocol Named
ensures that the generic type implements the name
class property.在下面的示例中,
Named
协议确保泛型类型实现name
类属性。
Note that this works with both classes and value types since the latter can also be extended to conform to protocols, as illustrated with the Int
below.请注意,这适用于类和值类型,因为后者也可以扩展以符合协议,如下面的
Int
所示。
protocol Named {
class var name: String { get }
}
class MyClass<T: Named> {
func genericName() -> String {
return T.name
}
}
extension Int: Named {
static var name: String { return "I am an Int" }
}
class Foo: Named {
class var name: String { return "I am a Foo" }
}
enum Drink: Named {
static var name: String { return "I am a Drink" }
}
MyClass<Int>().genericName() // I am an Int
MyClass<Foo>().genericName() // I am a Foo
MyClass<Drink>().genericName() // I am a Drink
Another possible solution that might help somebody:另一种可能对某人有所帮助的可能解决方案:
Playground操场
import Foundation
class ClassType<T> {
static func name () -> String
{
return "\(T.self)".componentsSeparatedByString(".").last!
}
}
class MyClass {
}
func testClassName(){
let className = ClassType<MyClass>.name()
print(className)
}
testClassName()
works for me:对我有用:
class MyClass<T> {
func genericName() -> String {
return "\(type(of: self))"
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.