简体   繁体   English

在 Swift 中获取泛型类型的名称(字符串)

[英]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+ Swift 中的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.selftype(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.它包含用于获取包含类型名称的代码。

Example including class and struct示例包括类和结构

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)

Console Output控制台输出

/*
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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM