programacion - swift functions parameters
¿Cómo obtener el nombre del valor de enumeración en Swift? (9)
Si tengo una enumeración con valores crudos Integer
:
enum City: Int {
case Melbourne = 1, Chelyabinsk, Bursa
}
let city = City.Melbourne
¿Cómo puedo convertir el valor de una city
en una cadena Melbourne
? ¿Este tipo de introspección de nombre de tipo está disponible en el idioma?
Algo como (este código no funcionará):
println("Your city is /(city.magicFunction)")
> Your city is Melbourne
A partir de Xcode 7 beta 5 ahora puede imprimir nombres de tipos y casos de enum de forma predeterminada utilizando print(_:)
, o convertir a String
usando el init(_:)
String o la sintaxis de interpolación de cadenas. Entonces para tu ejemplo:
enum City: Int {
case Melbourne = 1, Chelyabinsk, Bursa
}
let city = City.Melbourne
print(city)
// prints "Melbourne"
let cityName = "/(city)" // or `let cityName = String(city)`
// cityName contains "Melbourne"
Por lo tanto, ya no es necesario definir y mantener una función de conveniencia que active cada caso para devolver un literal de cadena. Además, esto funciona automáticamente para cualquier enumeración, incluso si no se especifica ningún tipo de valor sin formato.
debugPrint(_:)
& String(reflecting:)
se puede usar para un nombre completamente calificado:
debugPrint(city)
// prints "App.City.Melbourne" (or similar, depending on the full scope)
let cityDebugName = String(reflecting: city)
// cityDebugName contains "App.City.Melbourne"
Tenga en cuenta que puede personalizar lo que se imprime en cada uno de estos escenarios:
extension City: CustomStringConvertible {
var description: String {
return "City /(rawValue)"
}
}
print(city)
// prints "City 1"
extension City: CustomDebugStringConvertible {
var debugDescription: String {
return "City (rawValue: /(rawValue))"
}
}
debugPrint(city)
// prints "City (rawValue: 1)"
(No he encontrado una forma de invocar este valor "predeterminado", por ejemplo, para imprimir "La ciudad es Melbourne" sin recurrir a una declaración de cambio. Usar /(self)
en la implementación de description
/ debugDescription
causa una recursión infinita)
Los comentarios anteriores String
init(_:)
& init(reflecting:)
String
describen exactamente lo que se imprime, dependiendo de a qué se ajuste el tipo reflejado:
extension String {
/// Initialize `self` with the textual representation of `instance`.
///
/// * If `T` conforms to `Streamable`, the result is obtained by
/// calling `instance.writeTo(s)` on an empty string s.
/// * Otherwise, if `T` conforms to `CustomStringConvertible`, the
/// result is `instance`''s `description`
/// * Otherwise, if `T` conforms to `CustomDebugStringConvertible`,
/// the result is `instance`''s `debugDescription`
/// * Otherwise, an unspecified result is supplied automatically by
/// the Swift standard library.
///
/// - SeeAlso: `String.init<T>(reflecting: T)`
public init<T>(_ instance: T)
/// Initialize `self` with a detailed textual representation of
/// `subject`, suitable for debugging.
///
/// * If `T` conforms to `CustomDebugStringConvertible`, the result
/// is `subject`''s `debugDescription`.
///
/// * Otherwise, if `T` conforms to `CustomStringConvertible`, the result
/// is `subject`''s `description`.
///
/// * Otherwise, if `T` conforms to `Streamable`, the result is
/// obtained by calling `subject.writeTo(s)` on an empty string s.
///
/// * Otherwise, an unspecified result is supplied automatically by
/// the Swift standard library.
///
/// - SeeAlso: `String.init<T>(T)`
public init<T>(reflecting subject: T)
}
Consulte las notas de la versión para obtener información sobre este cambio.
Además del soporte de String (...) (CustomStringConvertible) para las enumeraciones en Swift 2.2, también hay un soporte de reflexión algo roto para ellos. Para los casos enum con valores asociados, es posible obtener la etiqueta del caso enum utilizando la reflexión:
enum City {
case Melbourne(String)
case Chelyabinsk
case Bursa
var label:String? {
let mirror = Mirror(reflecting: self)
return mirror.children.first?.label
}
}
print(City.Melbourne("Foobar").label) // prints out "Melbourne"
Al romperse, sin embargo signifiqué que para las enumeraciones "simples", la propiedad calculada de label
basada en la reflexión anterior simplemente devuelve nil
(boo-hoo).
print(City.Chelyabinsk.label) // prints out nil
La situación con la reflexión debería mejorar después de Swift 3, al parecer. La solución por ahora es String(…)
, como se sugiere en una de las otras respuestas:
print(String(City.Chelyabinsk)) // prints out Cheylabinsk
En Swift-3 (probado con XCode 8.1) puede agregar los siguientes métodos en su enumeración:
/**
* The name of the enumeration (as written in case).
*/
var name: String {
get { return String(describing: self) }
}
/**
* The full name of the enumeration
* (the name of the enum plus dot plus the name as written in case).
*/
var description: String {
get { return String(reflecting: self) }
}
Luego puede usarlo como una llamada a método normal en su instancia enum. También podría funcionar en versiones anteriores de Swift, pero no lo he probado.
En tu ejemplo:
enum City: Int {
case Melbourne = 1, Chelyabinsk, Bursa
var name: String {
get { return String(describing: self) }
}
var description: String {
get { return String(reflecting: self) }
}
}
let city = City.Melbourne
print(city.name)
// prints "Melbourne"
print(city.description)
// prints "City.Melbourne"
Si desea proporcionar esta funcionalidad a todas sus enumeraciones, puede hacer que sea una extensión:
/**
* Extend all enums with a simple method to derive their names.
*/
extension RawRepresentable where RawValue: Any {
/**
* The name of the enumeration (as written in case).
*/
var name: String {
get { return String(describing: self) }
}
/**
* The full name of the enumeration
* (the name of the enum plus dot plus the name as written in case).
*/
var description: String {
get { return String(reflecting: self) }
}
}
Esto solo funciona para enums de Swift.
Esto es tan decepcionante
Para el caso en que necesita esos nombres (que el compilador conoce perfectamente la ortografía exacta de, pero se niega a permitir el acceso, ¡gracias Swift team!), Pero no quiere o no puede hacer que String sea la base de su enumeración, una La alternativa detallada y engorrosa es la siguiente:
enum ViewType : Int, Printable {
case Title
case Buttons
case View
static let all = [Title, Buttons, View]
static let strings = ["Title", "Buttons", "View"]
func string() -> String {
return ViewType.strings[self.rawValue]
}
var description:String {
get {
return string()
}
}
}
Puede usar lo anterior de la siguiente manera:
let elementType = ViewType.Title
let column = Column.Collections
let row = 0
println("fetching element /(elementType), column: /(column.string()), row: /(row)")
Y obtendrá el resultado esperado (el código de la Columna es similar, pero no se muestra)
fetching element Title, column: Collections, row: 0
En lo anterior, hice que la propiedad de description
vuelva a referirse al método de string
, pero esta es una cuestión de gusto. También tenga en cuenta que las llamadas variables static
deben ser clasificadas por alcance por el nombre de su tipo adjunto, ya que el compilador es demasiado amnésico y no puede recordar el contexto por sí mismo ...
El equipo de Swift debe ser realmente comandado. Crearon una enumeración que no puedes enumerate
y en la que puedes usar enumerate
son "Secuencias" pero no enumerate
.
No hay introspección en los casos enum en este momento. Deberá declararlos de forma manual:
enum City : String, Printable {
case Melbourne = "Melbourne"
case Chelyabinsk = "Chelyabinsk"
case Bursa = "Bursa"
var description : String {
get {
return self.rawValue
}
}
}
Nota : El protocolo Printable
actualmente no funciona en áreas de juego. Si quieres ver la cuerda en un patio de recreo, deberás llamar aRaw () manualmente
Si necesita que el tipo sin procesar sea un Int, tendrá que hacer un cambio usted mismo:
enum City : Int, Printable {
case Melbourne = 1, Chelyabinsk, Bursa
var description : String {
get {
switch(self) {
case Melbourne:
return "Melbourne"
case Chelyabinsk:
return "Chelyabinsk"
case Bursa:
return "Bursa"
}
}
}
}
Para Objective-C enum
s la única manera actualmente parece ser, por ejemplo, extender la enumeración con CustomStringConvertible
terminando con algo como:
extension UIDeviceBatteryState: CustomStringConvertible {
public var description: String {
switch self {
case Unknown:
return "Unknown"
case Unplugged:
return "Unplugged"
case Charging:
return "Charging"
case Full:
return "Full"
}
}
}
Y luego lanzando la enum
como String
:
String(UIDevice.currentDevice().batteryState)
Para rápido:
extension UIDeviceBatteryState: CustomStringConvertible {
public var description: String {
switch self {
case .unknown:
return "unknown"
case .unplugged:
return "unplugged"
case .charging:
return "charging"
case .full:
return "full"
}
}
}
si su variable "batteryState" llame:
self.batteryState.description
Simple pero funciona ...
enum ViewType : Int {
case Title
case Buttons
case View
}
func printEnumValue(enum: ViewType) {
switch enum {
case .Title: println("ViewType.Title")
case .Buttons: println("ViewType.Buttons")
case .View: println("ViewType.View")
}
}
Swift ahora tiene lo que se conoce como Valor bruto implícitamente asignado . Básicamente, si no le da valores brutos a cada caso y la enumeración es de tipo String, deduce que el valor en bruto del caso es él mismo en formato de cadena. Vamos, dale una oportunidad.
enum City: String {
case Melbourne, Chelyabinsk, Bursa
}
let city = City.Melbourne.rawValue
// city is "Melbourne"