values switch enum computed swift enums language-features

switch - ¿Por qué los enumerados tienen propiedades computadas pero no almacenadas en Swift?



switch self swift (4)

Soy nuevo en Swift y acabo de encontrar esto en la documentación:

Las propiedades calculadas son proporcionadas por clases, estructuras y enumeraciones. Las propiedades almacenadas son proporcionadas solo por clases y estructuras.

¿Porqué es eso? ¿Los valores asociados para la enumeración funcionan como las propiedades almacenadas? Parece que inicialmente tenían propiedades almacenadas. ¿Por qué no hay propiedades de tipo almacenadas para las clases en swift?


Las enumeraciones que no permiten propiedades de instancia almacenadas son una opción de diseño. Tener enumeración con las propiedades de instancia almacenadas lo hace como una estructura (con superpoderes de enumeración), pero solo desde la perspectiva de tipo ahora las enumeraciones actuarán como multiplicadores de tipo. Basicamente considera

enum Set1 { case a case b case c } enum Times { case x case y var k: Set1 }

Lo que realmente significa que Enum Times nos permite tener cualquier combinación de elementos de Set1 y Set2 lo que Set2 resultado 6 casos distintos, pero espera, sabemos que en realidad este es un propósito de un tipo de tupla como (Set1, Set2) , donde se pueden declarar los Times como

typealias Times = (Set1, Set2)

Espero que esto sirva como una razón razonable para no permitir el caso anterior.

Dicho esto, los enums rápidos nos permiten asociar un n-tuple arbitrario a cada caso , lo que nos permite declarar lo que se conoce como unión discriminada en la programación funcional. Llámelo una propiedad almacenada adjunta al caso si lo desea. Desde perspectivas de tipos ahora actúa como sumador de tipo.

enum Add { case lhs(Set1) case rhs(Set2) }

Ahora tenemos 5 casos diferentes. Si ahora almacenamos 2-tuplas:

enum AddTimes { case lhs(Set1, Set2) case rhs(Set3, Set4) }

ahora tenemos básicamente la suma de la multiplicación (Set1 * Set2 + Set3 * Set4). Esta es una herramienta muy poderosa cuando se trata de la coincidencia de patrones.

SIN EMBARGO , existen algunos casos reales cuando realmente desea emular la forma de propiedad almacenada dentro de la enumeración. Considera esto:

public enum Service { case registerNewUser(username: String, password: String, language: String) case login(username: String, password: String, deviceTokenº: String?) case logout(sessionToken: String) case sendForgotPassword(email: String) }

es una forma declarativa de definir los puntos finales REST (en un marco como Moya ) Cuando desea enviar una solicitud, debería hacer algo como

MoyaProvider<Service>.request(.sendForgotPassword(email: "[email protected]"))

Pero ahora imagine que desea diferenciar entre su producción y su servidor de prueba. Si agrega un servidor como otro elemento de tupla en cada caso:

case forgotPassword(sessionToken: String, serverBaseURLString: String)

esto tendrá una semántica incorrecta, ya que originalmente pretendía que cada tupla almacenara los parámetros de solicitud, pero ahora almacena una dirección base del servidor.

Para evitar este tipo de cosas, podemos parametrizar nuestro tipo de la siguiente manera. En lugar de tener el servidor definido como decir:

enum Server: String { case production = "https://service.info" case test = "http://test.service.info" }

Podemos definirlo con tipo distinto para cada caso como:

public struct ProductionServer: ServerType { public static var baseURLString: String { return "https://service.info" } } public struct TestServer: ServerType { public static var baseURLString: String { return "http://test.service.info" } } public protocol ServerType { static var baseURLString: String { get } }

y finalmente parametrizar nuestro ServiceType como

public enum Service<T> where T: ServerType { case registerNewUser(username: String, password: String, language: String) case login(username: String, password: String, deviceTokenº: String?) case logout(sessionToken: String) case sendForgotPassword(email: String) var serverURL: URL { return T.baseURL } } public typealias ProdutionService = Service<ProductionServer> public typealias TestService = Service<TestServer>


Una enumeración se considera como un tipo de datos estructurado que se puede modificar sin necesidad de cambiar, digamos, String o Int, varias veces dentro de su código y con una enumeración, nunca debemos preocuparnos por cambiar la misma cosa más de una vez. Por ejemplo, menú desplegable:

enum DropDownMenuOptions: String { case MenuOptionOne case MenuOptionTwo case MenuOptionThree }

Con las propiedades almacenadas, puede precalcular la información necesaria y reducir el código en su función principal. El mejor ejemplo es calcular el tamaño de rect por ejemplo:

struct Point { var x = 0.0, y = 0.0 } struct Size { var width = 0.0, height = 0.0 } struct Rect { var origin = Point() var size = Size() var center: Point { get { let centerX = origin.x + (size.width / 2) let centerY = origin.y + (size.height / 2) return Point(x: centerX, y: centerY) } set(newCenter) { origin.x = newCenter.x - (size.width / 2) origin.y = newCenter.y - (size.height / 2) } } } var square = Rect(origin: Point(x: 0.0, y: 0.0), size: Size(width: 10.0, height: 10.0))


Utilizo un pequeño truco para almacenar propiedades que no son accesibles en la inicialización.

Primero, creo una clase Future que almacenará la propiedad almacenada en el futuro:

class Future<T> { var value: T? init(value: T? = nil) { self.value = value } }

Entonces creo mi enumeración:

enum Sample { case Test(future: Future<String>) }

Instanciar

let enumTest = Sample.Test(future: Future())

Más adelante en el código:

switch enumTest { case let .Test(future): future.value = "Foo" }

Y más adelante, puede acceder al valor:

switch enumTest { case let .Test(future): // it will print Optional("Foo") print("/(future.value)") }

Esto no es algo que deba abusar, pero puede ser útil en algunos casos.

Espero eso ayude.


enum s tienen propiedades de tipo almacenadas, es decir, propiedades static . No tienen propiedades de instancia almacenadas. No sé si hay una razón técnica por la que las propiedades de las instancias almacenadas no estén disponibles para las enum . Es posible que tenga que hacer su pregunta en el foro de desarrolladores si desea una respuesta técnica para "por qué".

En su pregunta, usted pregunta si los valores asociados funcionan como propiedades almacenadas. De hecho, lo hacen, y son más flexibles (de alguna manera) que las propiedades almacenadas para struct y class . Cada case en una enum puede tener su propio conjunto especializado de datos que está asociado con él. En lugar de tener un conjunto de propiedades almacenadas que se aplican a todos los case , puede individualizar las propiedades almacenadas para cada case .