Swift Language
Operadores Avanzados
Buscar..
Operadores personalizados
Swift soporta la creación de operadores personalizados. Los nuevos operadores se declaran a nivel global utilizando la palabra clave del operator
.
La estructura del operador está definida por tres partes: ubicación de operandos, precedencia y asociatividad.
Los modificadores de
prefix
,infix
ypostfix
se utilizan para iniciar una declaración de operador personalizada. Los modificadoresprefix
ypostfix
declaran si el operador debe ser antes o después, respectivamente, del valor sobre el que actúa. Dichos operadores son urnarios, como8
y3++
** , ya que solo pueden actuar sobre un objetivo. Elinfix
declara un operador binario, que actúa sobre los dos valores entre ellos, como2+3
.Los operadores con mayor precedencia se calculan primero. La precedencia del operador por defecto es solo mayor que
?
...:
(un valor de 100 en Swift 2.x). La precedencia de los operadores Swift estándar se puede encontrar aquí .La asociatividad define el orden de las operaciones entre operadores de la misma precedencia. Los operadores asociativos izquierdos se calculan de izquierda a derecha (orden de lectura, como la mayoría de los operadores), mientras que los operadores asociativos derechos calculan de derecha a izquierda.
A partir de Swift 3.0, uno definiría la precedencia y la asociatividad en un grupo de precedencia en lugar del operador mismo, de modo que múltiples operadores puedan compartir fácilmente la misma precedencia sin hacer referencia a los números crípticos. La lista de grupos de precedencia estándar se muestra a continuación .
Los operadores devuelven valores basados en el código de cálculo. Este código actúa como una función normal, con parámetros que especifican el tipo de entrada y la palabra clave de return
especifica el valor calculado que el operador devuelve.
Aquí está la definición de un operador exponencial simple, ya que Swift estándar no tiene un operador exponencial.
import Foundation
infix operator ** { associativity left precedence 170 }
func ** (num: Double, power: Double) -> Double{
return pow(num, power)
}
El infix
dice que el operador **
trabaja entre dos valores, como 9**2
. Debido a que la función tiene asociatividad izquierda, 3**3**2
se calcula como (3**3)**2
. La prioridad de 170
es más alta que todas las operaciones Swift estándar, lo que significa que 3+2**4
calcula a 19
, a pesar de la asociatividad a la izquierda de **
.
import Foundation
infix operator **: BitwiseShiftPrecedence
func ** (num: Double, power: Double) -> Double {
return pow(num, power)
}
En lugar de especificar explícitamente la precedencia y la asociatividad, en Swift 3.0 podríamos usar el grupo de precedencia integrado BitwiseShiftPrecedence que proporciona los valores correctos (igual que <<
, >>
).
**: El incremento y la disminución están en desuso y se eliminarán en Swift 3.
Sobrecarga + para Diccionarios
Como actualmente no existe una forma sencilla de combinar diccionarios en Swift, puede ser útil sobrecargar los operadores +
y +=
para agregar esta funcionalidad usando genéricos .
// Combines two dictionaries together. If both dictionaries contain
// the same key, the value of the right hand side dictionary is used.
func +<K, V>(lhs: [K : V], rhs: [K : V]) -> [K : V] {
var combined = lhs
for (key, value) in rhs {
combined[key] = value
}
return combined
}
// The mutable variant of the + overload, allowing a dictionary
// to be appended to 'in-place'.
func +=<K, V>(inout lhs: [K : V], rhs: [K : V]) {
for (key, value) in rhs {
lhs[key] = value
}
}
A partir de Swift 3, inout
debe colocarse antes del tipo de argumento.
func +=<K, V>(lhs: inout [K : V], rhs: [K : V]) { ... }
Ejemplo de uso:
let firstDict = ["hello" : "world"]
let secondDict = ["world" : "hello"]
var thirdDict = firstDict + secondDict // ["hello": "world", "world": "hello"]
thirdDict += ["hello":"bar", "baz":"qux"] // ["hello": "bar", "baz": "qux", "world": "hello"]
Operadores conmutativos
Añadamos un operador personalizado para multiplicar un CGSize.
func *(lhs: CGFloat, rhs: CGSize) -> CGSize{
let height = lhs*rhs.height
let width = lhs*rhs.width
return CGSize(width: width, height: height)
}
Ahora esto funciona
let sizeA = CGSize(height:100, width:200)
let sizeB = 1.1 * sizeA //=> (height: 110, width: 220)
Pero si intentamos hacer la operación a la inversa, obtenemos un error.
let sizeC = sizeB * 20 // ERROR
Pero es lo suficientemente simple como para agregar:
func *(lhs: CGSize, rhs: CGFloat) -> CGSize{
return rhs*lhs
}
Ahora el operador es conmutativo.
let sizeA = CGSize(height:100, width:200)
let sizeB = sizeA * 1.1 //=> (height: 110, width: 220)
Operadores de Bitwise
Los operadores de Swwise Bitwise le permiten realizar operaciones en la forma binaria de números. Puede especificar un literal binario prefijando el número con 0b
, por lo que, por ejemplo, 0b110
es equivalente al número binario 110 (el número decimal 6). Cada 1 o 0 es un bit en el número.
Bitwise NO ~
:
var number: UInt8 = 0b01101100
let newNumber = ~number
// newNumber is equal to 0b01101100
Aquí, cada bit se cambia a su opuesto. Declarar el número como explícitamente UInt8
garantiza que el número sea positivo (para que no tengamos que lidiar con los negativos en el ejemplo) y que solo sea de 8 bits. Si 0b01101100
fuera un UInt más grande, habría 0 iniciales que se convertirían a 1 y serían significativos tras la inversión:
var number: UInt16 = 0b01101100
// number equals 0b0000000001101100
// the 0s are not significant
let newNumber = ~number
// newNumber equals 0b1111111110010011
// the 1s are now significant
- 0 -> 1
- 1 -> 0
Bitwise Y &
var number = 0b0110
let newNumber = number & 0b1010
// newNumber is equal to 0b0010
Aquí, un bit dado será 1 si y solo si los números binarios en ambos lados del operador &
contienen un 1 en esa ubicación de bit.
- 0 y 0 -> 0
- 0 y 1 -> 0
- 1 y 1 -> 1
Bitwise o |
:
var number = 0b0110
let newNumber = number | 0b1000
// newNumber is equal to 0b1110
Aquí, un bit dado será 1 si y solo si el número binario en al menos un lado de la |
El operador contenía un 1 en esa ubicación de bit.
- 0 | 0 -> 0
- 0 | 1 -> 1
- 1 | 1 -> 1
Bitwise XOR (O exclusivo) ^
:
var number = 0b0110
let newNumber = number ^ 0b1010
// newNumber is equal to 0b1100
Aquí, un bit dado será 1 si y solo si los bits en esa posición de los dos operandos son diferentes.
- 0 ^ 0 -> 0
- 0 ^ 1 -> 1
- 1 ^ 1 -> 0
Para todas las operaciones binarias, el orden de los operandos no hace ninguna diferencia en el resultado.
Operadores de desbordamiento
Desbordamiento se refiere a lo que sucede cuando una operación resultaría en un número que es más grande o más pequeño que la cantidad designada de bits para que ese número pueda contener.
Debido a la forma en que funciona la aritmética binaria, después de que un número se vuelve demasiado grande para sus bits, el número se desborda hasta el número más pequeño posible (para el tamaño de bit) y luego continúa contando desde allí. De manera similar, cuando un número se vuelve demasiado pequeño, se desborda hasta el número más grande posible (por su tamaño de bit) y continúa contando desde allí.
Debido a que este comportamiento no es a menudo deseado y puede llevar a serios problemas de seguridad, los operadores aritméticos Swift +
, -
y *
generarán errores cuando una operación cause un desbordamiento o subdesbordamiento. Para permitir explícitamente el desbordamiento y el desbordamiento, use &+
, &-
, y &*
lugar.
var almostTooLarge = Int.max
almostTooLarge + 1 // not allowed
almostTooLarge &+ 1 // allowed, but result will be the value of Int.min
Precedencia de los operadores Swift estándar.
Los operadores que se unen más estrechamente (mayor prioridad) se enumeran primero.
Los operadores | Grupo de precedencia (≥3.0) | Precedencia | Asociatividad |
---|---|---|---|
. | ∞ | izquierda | |
? , ! , ++ , -- , [] , () , {} | (sufijo) | ||
! , ~ , + , - , ++ , -- | (prefijo) | ||
~> (swift ≤2.3) | 255 | izquierda | |
<< , >> | BitwiseShiftPrecedence | 160 | ninguna |
* , / , % , & , &* | Multiplicación precedencia | 150 | izquierda |
+ , - , | , ^ , &+ , &- | AdditionPrecedence | 140 | izquierda |
... , ..< | RangeFormationPrecedence | 135 | ninguna |
is as as? , as! | CastingPrecedence | 132 | izquierda |
?? | NilCoalescingPrecedence | 131 | Correcto |
< , <= , > , >= , == != , === !== , ~= | Comparacion precedencia | 130 | ninguna |
&& | Conexión lógicaPrincipio | 120 | izquierda |
|| | LogicDisjunctionPrecedence | 110 | izquierda |
DefaultPrecedence * | ninguna | ||
? ... : | TernariaPrecedencia | 100 | Correcto |
= , += , -= , *= , /= , %= , <<= , >>= , &= , |= , ^= | AsignacionPredecencia | 90 | derecho, asignación |
-> | FunctionArrowPrecedence | Correcto |
- El grupo de precedencia de
DefaultPrecedence
es más alto queTernaryPrecedence
, pero no está ordenado con el resto de los operadores. Aparte de este grupo, el resto de las precedentes son lineales.
- Esta tabla también se puede encontrar en la referencia API de Apple.
- La definición real de los grupos de precedencia se puede encontrar en el código fuente en GitHub