ios - style - ¿Por qué un operador de protocolo debe implementarse como una función global?
pwa safari icon (5)
El hecho de que su implementación debe ser declarada a un alcance global, hace que parezca incidental y distinto de un protocolo, incluso si se adoptó Equatable.
Esto se aplica a todos los protocolos, ya sea que requiera funciones globales, métodos de clase o métodos de instancia. Siempre puede implementar cosas independientemente de si existe un protocolo que lo requiera.
¿Cómo es el protocolo Equatable algo más que el azúcar sintáctica que simplemente le permite (a nosotros y) al compilador saber con seguridad que nuestro tipo implementó el método requerido del protocolo?
Eso no es azúcar. Esa es la definición de un protocolo y todo el punto de los protocolos. Le dice que este tipo tiene disponibles estas cosas que se pueden aplicar a él.
¿Por qué la implementación del operador tiene que ser declarada globalmente, incluso para un protocolo? ¿Esto se debe a alguna forma diferente en que se despacha un operador?
Porque esa es la sintaxis Swift. Las implementaciones de la función del operador tienen que ser funciones globales. El equipo de Swift ha mostrado interés en cambiar esto para hacerlo más consistente, pero hoy en día así es como funciona Swift.
He visto la respuesta a esta pregunta de Swift Equatable Protocol que menciona cómo debe declararse el método ==
en el ámbito global.
Si no adopto Equatable
, todavía podría declarar ==
para probar la igualdad entre dos de mis tipos.
// extension Foo: Equatable {}
func ==(lhs: Foo, rhs: Foo) -> Bool {
return lhs.bar == rhs.bar
}
struct Foo {
let bar:Int
}
El hecho de que su implementación debe ser declarada a un alcance global, hace que parezca incidental y distinto de un protocolo, incluso si se adoptó Equatable
.
¿Cómo es el protocolo Equatable
algo más que el azúcar sintáctica que simplemente le permite (a nosotros y) al compilador saber con seguridad que nuestro tipo implementó el método requerido del protocolo?
¿Por qué la implementación del operador tiene que ser declarada globalmente, incluso para un protocolo? ¿Esto se debe a alguna forma diferente en que se despacha un operador?
ACTUALIZAR
De las notas de lanzamiento de Xcode 8 beta 4:
Los operadores pueden definirse dentro de los tipos o extensiones de los mismos. Por ejemplo:
struct Foo: Equatable { let value: Int static func ==(lhs: Foo, rhs: Foo) -> Bool { return lhs.value == rhs.value } }
Dichos operadores deben ser declarados como
static
(o, dentro de una clase,class final
) y tienen la misma firma que sus contrapartes globales. Como parte de este cambio, los requisitos del operador declarados en los protocolos también deben declararse explícitamente comostatic
:
protocol Equatable { static func ==(lhs: Self, rhs: Self) -> Bool }
ORIGINAL
Esto se discutió recientemente en la lista de evolución rápida (2016-01-31 hasta 2016-02-09 hasta el momento). Esto es lo que dijo Chris Lattner, con respecto a la declaración de operadores en una estructura o ámbito de clase:
Sí, esta es una característica generalmente deseable (al menos para operadores simétricos). Esto también sería genial para obtener un envío dinámico de operadores dentro de las declaraciones de clase. Sin embargo, no creo que tengamos una propuesta firme para determinar cómo funciona la búsqueda de nombres con esto.
Y más tarde (respondiendo a Haravikk):
¿Cuáles son los problemas de búsqueda de nombres? ¿Se refiere a los casos en que existe un operador para Foo == Foo en más de una ubicación?
Sí. La búsqueda de nombres debe tener un orden de búsqueda bien definido, que defina el seguimiento y las reglas de definición múltiple inválidas.
Personalmente, me limito a seguir con lo que tenemos ahora, es decir, tratar las implementaciones de operadores dentro de una clase / estructura específica como si estuvieran definidas globalmente de todos modos y emitir un error si la misma firma se declara más de una vez.
Necesitamos múltiples módulos para poder definir instancias de un operador, necesitamos operadores en extensiones y necesitamos conformidad retroactiva para trabajar, como con cualquier otro miembro.
Antes era un poco de azúcar, es decir, porque necesitaba realizar manualmente la implementación de Equatable
. A pesar de que Rob Napier planteó un buen punto, para eso son los protocolos.
Pero ese ya no es el caso, es decir, solo por conformidad, se obtiene la Síntesis automatizada y ya no se necesita el código de repetición.
struct Country: Equatable {
let name: String
let capital: String
var visited: Bool
}
¡Eso es! El compilador hará el resto.
let france = Country(name: "France", capital: "Paris", visited: true)
let spain = Country(name: "Spain", capital: "Madrid", visited: true)
if france == spain { ... } // false
Dicho esto, si lo desea, puede anular la implementación de la función ==
.
Para mas ver here
En la biblioteca estándar de Swift, se define el operador ''==''. No tiene asociatividad para un lado u otro de la comparación y tiene una prioridad numerada en el orden general del operador Swift. Puede examinar esto si presiona CMD haciendo clic en Swift en ''importar Swift''
infix operator == {
associativity none
precedence 130
}
Para Int, la biblioteca ya tiene Int / Int8 / Int16 / Int32 / Int64 como Equatable:
public func ==(lhs: Int, rhs: Int) -> Bool
como lo hace para muchos otros tipos.
Int se convierte en Hashable en una extensión (donde para ajustarse a ese protocolo, debe crear un var hashValue: Int {get} que cambia para cada ejecución de la aplicación:
extension Int : Hashable {
public var hashValue: Int { get }
}
El operador ''=='' y los protocolos, en general, deben declararse fuera de struct / enum / class en el nivel superior porque está extendiendo el idioma y, por ahora, así es como se compila Swift; Todos los operadores de Swift son atributos definidos en el ámbito global.
Para su ''Foo'', adoptó Equatable al agregar la función:
func ==(lhs: Foo, rhs: Foo) -> Bool {
return lhs.bar == rhs.bar
}
que utiliza las variables locales ''Self'' en el protocolo:
public protocol Equatable {
public func ==(lhs: Self, rhs: Self) -> Bool
}
Explicación de la documentation
La función de operador se define como una función global con un nombre de función que coincide con el operador a sobrecargar.
La función se define globalmente, en lugar de como un método en la clase o estructura de destino, de modo que se puede utilizar como un operador de infijo entre las instancias existentes de la clase o estructura de destino.
Reemplazé el nombre de la estructura concreta ( Vector2D
) en la cita por una expresión genérica clase o estructura objetivo