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.

  1. Los modificadores de prefix , infix y postfix se utilizan para iniciar una declaración de operador personalizada. Los modificadores prefix y postfix declaran si el operador debe ser antes o después, respectivamente, del valor sobre el que actúa. Dichos operadores son urnarios, como 8 y 3++ ** , ya que solo pueden actuar sobre un objetivo. El infix declara un operador binario, que actúa sobre los dos valores entre ellos, como 2+3 .

  2. 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í .

  3. 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.

3.0

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 ** .

3.0
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
    }
}
3.0

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
3.0
  • El grupo de precedencia de DefaultPrecedence es más alto que TernaryPrecedence , pero no está ordenado con el resto de los operadores. Aparte de este grupo, el resto de las precedentes son lineales.


Modified text is an extract of the original Stack Overflow Documentation
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow