[英]Get the name (string) of a generic type in Swift
我有一个类型为 T 的泛型类,我想获取实例化时传入该类的类型的名称。 这是一个例子。
class MyClass<T> {
func genericName() -> String {
// Return the name of T.
}
}
我已经环顾了几个小时,但似乎找不到任何方法来做到这一点。 有没有人试过这个?
任何帮助是极大的赞赏。
谢谢
您可以使用字符串插值返回任何类型的名称:
class MyClass<T> {
func genericName() -> String {
return "\(T.self)"
}
}
您可以在操场上尝试它,它按预期工作:
var someClass = MyClass<String>()
someClass.genericName() // Returns "Swift.String"
String(describing: T.self)
3+var genericTypeName: String {
return String(describing: T.self)
}
在泛型类型中,通过将T.self
或type(of: T.self)
转换为String
来获取类型T
的名称。 我发现type(of:)
不是必需的,但值得注意,因为在其他情况下它会删除有关 Type 的其他详细信息。
以下示例演示如何在结构和类中获取泛型类型T
的名称。 它包含用于获取包含类型名称的代码。
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'
*/
实现这一目标的纯粹快捷方式是不可能的。
一个可能的解决方法是:
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
}
}
}
限制依赖于它仅适用于类的事实。
如果这是泛型类型:
class TestClass {}
NSStringFromClass()
返回全名(包括命名空间):
// Prints something like "__lldb_expr_186.TestClass" in playground
NSStringFromClass(TestClass.self)
这就是为什么 func 搜索最后一次出现的.
特点。
测试如下:
var x = MyClass<TestClass>()
x.genericName() // Prints "TestClass"
更新斯威夫特 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
}
如果您的类型参数实现了通用命名协议,则有可能。
在下面的示例中, Named
协议确保泛型类型实现name
类属性。
请注意,这适用于类和值类型,因为后者也可以扩展以符合协议,如下面的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
另一种可能对某人有所帮助的可能解决方案:
操场
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()
对我有用:
class MyClass<T> {
func genericName() -> String {
return "\(type(of: self))"
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.