Существует ли Swift-эквивалент функции nameof() в C# для получения переменной или имени члена?

Хорошо, здесь есть вопрос о S/O со следующим заголовком:

Swift: получить фактическое имя переменной в виде строки

По его названию, кажется, это именно то, что я хочу. Однако, глядя на принятый ответ (и другие непринятые), они имеют в виду манипулирование ключевыми путями, а это не то, что мне нужно. (т.е. это не дубликат!)

В моем случае я хочу, чтобы имя одной переменной было сохранено во второй переменной типа string.

В C# это тривиально nameof, вот так...

int someVar = 3

string varName = nameof(someVar)
// 'varName' now holds the string value "someVar"

Я полагаю, что это происходит во время компиляции, а не во время выполнения, поэтому не требуется никакого отражения или чего-либо еще, а также имена символов не должны быть в исполняемом файле. Компилятор просто подписывается именем переменной.

Это очень удобно, например, когда вы хотите определить объект запроса, в котором имена ваших членов соответствуют параметрам запроса, переданным в URL.

Вот пример псевдокода (т. Е. Он явно не скомпилируется, но показывает, что мне нужно):

struct queryObject{

    let userName  : String
    let highScore : Int

    var getUrl:String{
        return "www.ScoreTracker.com/postScore?\(nameof(userName))=\(userName)&\(nameof(highScore))=\(highScore)"
    }
}

Вот как бы вы использовали это и что бы оно вернуло:

let queryObject = QueryObject(userName:"Maverick", highScore:123456)

let urlString = queryObject.getUrl

Возвращаемое значение будет:

www.ScoreTracker.com/postScore?userName=Maverick&highScore=123456

Преимущества наличия доступа к строковому представлению переменной вместо использования строковых констант:

  1. Имена ваших членов используются в качестве параметров запроса, сохраняя простоту использования структуры
  2. Нет необходимости определять константы для хранения имен параметров запроса, поскольку они неявны от имен членов
  3. Вы получаете полную поддержку рефакторинга реальных символов, а не поиск-замена строк

Например, скажем, API изменил параметр запроса с userName в userId, Все, что мне нужно было бы сделать, это соответственно изменить рефакторинг моего имени члена, и результат теперь будет...

www.ScoreTracker.com/postScore?userId=Maverick&highScore=123456

... без меня, чтобы изменить любые строковые константы.

Примечание. Приведенный выше пример приведен просто для наглядности, так как вы можете использовать имя переменной. Это не то, как мы на самом деле работаем с управляющими URL-адресами и не добавляем к ним параметры запроса; обсуждение, которое было бы слишком многословным, и не по теме для этого поста.

Так можно ли это сделать в Swift? Можете ли вы получить фактическое имя переменной и сохранить его во второй переменной?

2 ответа

Да, ты можешь. Я использовал это как решение для следующего сценария: когда я печатаю объект / структуру в консоли, мне нравится видеть имена переменных вместе со связанными значениями:

      extension CustomStringConvertible {
    var description: String {
        var description = "\n          *****  \(type(of: self)) *****\n"
        let mirrorS = Mirror(reflecting: self)
        for child in mirrorS.children {
            if let propertyName = child.label {
                description += "   \(getSpaces(forWord: propertyName))\(propertyName):  \(child.value)\n"
            }
        }

        return description
    }
}

И чтобы использовать это, давайте возьмем в качестве примера следующую структуру:

      public struct FavoriteApp: Codable, CustomStringConvertible, Hashable {
    let appId: String
    let appName: String
    let bundleId: String
    let image: NSImage
    let isMacApp: Bool
    let rating: String
    let screenshotUrls: [String]
    let sellerName: String
    let sellerUrl: String
    let releaseDate: String
    let genres: String
    let latestVersion: String

}

let anApp:FavoriteApp = getTheAppInfoFromServer()
print(anApp) 

// This will print into console: 
    //        *****  FavoriteApp *****
    //        appId:          1438547269
    //        appName:        Dynamic wallpaper
    //        bundleId:        com.minglebit.DynamicWallpaper
    //        image:           -not visible- (but is there, trust me :))
    //        isMacApp         true
    //        rating:          0
    //
    //        screenshotUrls:  https://is1-ssl.mzstatic.com/image/thumb/Purple128/v4/5c/08/b8/5c08b824-12eb-e0b6-22fb-0e234f396b9e/pr_source.jpg/800x500bb.jpg
    //                        https://is1-ssl.mzstatic.com/image/thumb/Purple128/v4/f3/34/0e/f3340e21-714c-0a17-4437-73ba1828cbba/pr_source.jpg/800x500bb.jpg
    //        sellerName:      MingleBit SRL
    //        sellerUrl:       https://minglebit.com/products/dynamicwallpaper.php
    //        releaseDate:     2018-10-18T14:59:47Z
    //        genres:          Entertainment, Lifestyle
    //        latestVersion:   2.3

Итак, чтобы сконцентрировать ответ, используйте Mirror(reflecting: object) чтобы получить то, что вы хотите.

Если вы имеете дело только с URL-адресами, рекомендуется использовать URLComponents, что лучше.

модель:

      struct QueryObject{

    var params = [String: String]()

    var getUrl: String{
        let result = "www.ScoreTracker.com/postScore"
        guard var url = URL(string: result) else { return result}
        url.appendQueryParameters(params)
        return url.absoluteString
    }

    init(params: [String: String]) {
        self.params = params
    }

}

тогда:

          let params = ["userName": "Maverick", "highScore": "123456"]
    let queryObject = QueryObject(params: params)
    let urlString = queryObject.getUrl
    DDLog(urlString) //www.ScoreTracker.com/postScore?userName=Maverick&highScore=123456

GithubСсылка на

Другие вопросы по тегам