2014-11-19 13:32:55 linshaolie 阅读数 895

首先我们定义一个结构体

struct Point {

    var x = 0.0

    var y = 0.0

}



Point 的两个变量相加时,我们需要这样做:

let p1 = Point(x: 1.0, y: 2.0)

let p2 = Point(x: 4.0, y: 3.0)

let p3 = Point(x: p1.x + p2.x, y: p1.y + p2.y)

如果这样的运算用到多次的话会显得很麻烦,swift提供了类似C++的操作符重载方法,下面实现一个 + 运算符的重载。

func + (left: Point, right: Point) -> Point {

    returnPoint(x: left.x + right.x, y: left.y + right.y)

}


这样,就让这个相加运算跟基本类型的写法一致了。

let p1 = Point(x: 2.0, y: 3.0)

let p2 = Point(x: 1.0, y: 2.0)

let p3 = p1+p2

重载操作使运算变得简单,但 swift 有规定:等号运算符 = 和三木运算符 (a ? b : c) 不可被重载。


当标准的操作符不满足我们的要求时,我们就可用自定义一些操作符。

新的操作符需要用 operator 关键字声明在全局变量中,可以用 prefixinfixpostfix 声明

例如:

prefix operator infix operator postfix operator⋅ {}

现在我们定义一个新的操作符使结构体 Point 做相乘

infixoperator • {

    associativity none

    precedence 160

}


infix     —>  表示定义的是一个双目操作符

prefix     —> 表示定义一个左操作符,如取反操作符!

postfix     —> 表示定义一个右操作符,如a++


associativity

定义了结合律,即如果多个同类的操作符顺序出现的计算顺序。比如常见的加法和减法都是left,就是说多个加法同时出现时按照从左往右的顺序计算(因为加法满足交换律,所以这个顺序无所谓,但是减法的话计算顺序就很重要了)。点乘的结果是一个Double,不再会和其他点乘结合使用,所以这里写成none;详见:https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/AdvancedOperators.html#//apple_ref/doc/uid/TP40014097-CH27-XID_65


precedence

运算的优先级,越高的话优先进行计算。swift 中乘法和除法的优先级是 150 ,加法和减法的优先级是 140 ,定义点积的优先级为 160 ,就是说应该早于普通的乘除进行运算。

func • (left: Point, right: Point) -> Double {

    return left.x * right.x + left.y + right.y;

}


let value = v1 ⋅ v2      // 23.0

这样就可以进行点积运算了。



Equatable,和Comparable协议

在说Equatable之前,我们先实现上面Point == 运算。如下:

func == (left:Point, right: Point) -> Bool {

    return left.x==right.x && left.y == right.y

}

这样,我们同样就可以使用 == 来判断两个Point变量是否相等了,如:

let v4 = Point(x: 2.0, y: 3.0)

let rst = v1==v4          //yes


然后,我们又想实现 = 运算,如:

func != (left:Point, right: Point) -> Bool {

    return !(left == right)

}

然后,假设我们又依次去实现了 ‘>=‘ ‘<=‘ ‘<‘’>’等运算

这样显得太麻烦了。其实这些运算只要实现了其中的一个,那其他的都可以根据这个来进行取反或其他的操作来得到想要的结果,好在swift提供了两个协议:Equatable, Comparable

只要遵循Equatable协议,并实现 '=='方法,那么自动的 '!=‘也就生成了,无需我们手动再重载。

Comparable协议继承于Equatable协议,且定义了它自身的规则。遵循Comparable后,必须实现小于号(“<“)操作符,然后再实现Equatable协议的是否等于(”==“)方法。实现了这两个方法之后,“>”, “>=“, “<=”等方法也会自动生成。

如下:

struct Point :Comparable{          //遵循了Comparable也同时遵循了Equatable协议

    var x = 0.0

    var y = 0.0

}


func == (left:Point, right: Point) -> Bool {

    return left.x==right.x && left.y == right.y

}


func < (left:Point, right: Point) -> Bool {

    returnpow(left.x, 2)+pow(left.y,2) < pow(right.x, 2) + pow(right.y, 2)

}


这样,我们就相当于把所有方法实现了。


总结:

swift的运算符重载是从C++中引入的,如果能够灵活使用的话,可以给编程带来很多便利。

2019-07-27 13:58:17 weixin_42433480 阅读数 37

溢出运算符

  • Swift的算数运算符出现溢出时会抛出运行时错误
  • Swift有溢出运算符(&+、&-、&*),用来支持溢出运算
var umin = UInt8.min //0
var umax = UInt8.max //255

var min = Int8.min  //-128
var max = Int8.max //127

print(umax &+ 1) //0
print(umax &* 2) //254

UInt8.max + 1图解:

 结果是0

UInt8.max * 2图解:

结果是127


运算符重载

  • 类,结构体,枚举可以为现有的运算符提供自定义的实现,这个操作叫做运算符重载

preifx:前缀运算符

postfix:后缀运算符


Equatable

  • 要想得知2个实例是否等价,一般做法是遵守Equatable 协议,重载== 运算符 
  • 与此同时,等价于重载了 != 运算符

  • Swift为以下类型提供默认的Equatable 实现 :
  1. 没有关联类型的枚举
enum Answer {
    case wrong
    case right
}

var s1 = Answer.wrong
var s2 = Answer.right
print(s1 == s2)

有关联类型会报错:

    2.  只拥有遵守 Equatable 协议关联类型的枚举 

//Int, String都遵守Equatable协议
enum Answer : Equatable {
    case wrong(Int, String)
    case right
}

var s1 = Answer.wrong(10, "Jack")
var s2 = Answer.wrong(10, "Jack")
print(s1 == s2)

   //Cat()类型不遵守Equatable协议,会报错

    

    3.   只拥有遵守 Equatable 协议存储属性的结构体

 

  • 引用类型比较存储的地址值是否相等(是否引用着同一个对象),使用恒等运算符=== 、!==
class Person : Equatable {
    
    var age: Int
    init(age: Int) {
        self.age = age
    }
    static func == (lhs: Person, rhs: Person) -> Bool{
        return lhs.age == rhs.age
    }
}

var p1 = Person(age: 10)
var p2 = Person(age: 10)

print(p1 == p2) //true
print(p1 === p2) //false : ===比较的是存储地址值,看是否是同一个对象,虽然p1和p2的age属性值相同,但不是同一个对象,所以为false

Comparable

  • 要想比较2个实例的大小,一般做法是:
  1. 遵守Comparable协议
  2. 重载相应的运算符


自定义运算符(Customer Operator)

  • 可以自定义新的运算符,在全局作用域使用operator进行声明

associativity: left表示从左到右进行计算,right表示从右到左进行计算,none表示不能有两个以上自定义的运算符在一条运算语句中同时使用

assignment:

class Person {
    var age = 0
    var point: Point = Point()
}
var p: Person? = Person()
p?.point +- Point(x: 10, y: 20) //这个运算符跟赋值运算符一样当可选项p为nil时,不会继续进行运算,也就是Point(x: 10, y: 20)不会初始化

  •  Apple文档参考:
  1. https://developer.apple.com/documentation/swift/swift_standard_library/operator_declarations
  2. https://docs.swift.org/swift- book/ReferenceManual/Declarations.html#ID380
prefix operator +++

prefix func +++ (_ i: inout Int) {
    i += 2
}

var age = 10
+++age
print(age) //12
infix operator +- : PlusMinusPrecedence

precedencegroup PlusMinusPrecedence {
    associativity: none
    higherThan: AdditionPrecedence
    lowerThan: MultiplicationPrecedence
    assignment: true
}

struct Point {
    var x: Int, y: Int
    static func +- (left: Point, right: Point) -> Point{
        return Point(x: left.x + right.x, y: left.y + right.y)
    }
    static func +- (left: Point?, right: Point) -> Point {
        print("+-")
        return Point(x: left?.x ?? 0 + right.x, y: left?.y ?? 0 + right.y)
    }
}

struct Person {
    var point : Point
}

var person: Person? = Person(point: Point(x: 11, y: 22))
var p1 = person?.point +- Point(x: 10, y: 20)
print(p1 ?? Point(x: 0, y: 0)) // Point(x: 21, y: 42)

var personOther: Person = Person(point: Point(x: 12, y: 23))
var p2 = personOther.point +- Point(x: 10, y: 20)
print(p2) // Point(x: 22, y: 43)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

2017-08-24 11:12:48 u014696025 阅读数 411

Swift 比较运算符

动机

Swift 升级至 3.0 以后,Swift 标准库中移除了对可选类型比较运算符的实现,当我们升级 Swift 版本的时候,可能会出现若干问题,为了代码重构需要,所以重写比较运算符。

代码变更记录

Swift2.3 时代的代码如下

if (self?.monthParams.filter{ return $0.length == 0 })?.count > 0 {
    self?.showTip("请输入日期")
}

升级到 Swift3.0 以后,需要这样写

if ((self?.monthParams.filter{ return $0.length == 0 })?.count ?? 0) > 0 {
    self?.showTip("请输入日期")
}
  • Tips

    • 这里的 > 左右两边的操作数,必须是非可选类型!所以会出现大量的类似于?? 0这样的代码!
    • 只修改一处无关紧要,一旦涉及到整个项目,可想而知有多么的蛋疼……
  • 分析

    • 出现这个问题的根本原因是 Swift3.0 后,运算符两边的操作数必须是非可选类型
    • 我们可以重写比较运算符,让它接受可选类型的操作数,这样代码就不需要修改了!

☆ 重写运算符

public func > <T : Comparable>(lhs: T?, rhs: T?) -> Bool {
    switch (lhs, rhs) {
    case let (l?, r?):
        return l > r
    case (nil, _):
        return false
    case (_, nil):
        return true
    default:
        return false
    }
}
public func < <T : Comparable>(lhs: T?, rhs: T?) -> Bool {
    return rhs > lhs
}
public func >= <T : Comparable>(lhs: T?, rhs: T?) -> Bool {
    return lhs > rhs || lhs == rhs
}
public func <= <T : Comparable>(lhs: T?, rhs: T?) -> Bool {
    return rhs >= lhs
}

这样就可以愉快地玩耍了,哈哈哈!

附录

Swift 标准库中的部分比较运算符

public func <(lhs: Int, rhs: Int) -> Bool
public func <=(lhs: Int, rhs: Int) -> Bool
public func >(lhs: Int, rhs: Int) -> Bool
public func >=(lhs: Int, rhs: Int) -> Bool

public func ==<T>(lhs: T?, rhs: T?) -> Bool where T : Equatable
2016-03-07 18:27:43 IT_DS 阅读数 1932

在Swift中延伸了一种和C++类似的新特性,Swift的运算符提供了良好的可拓展性,我们可以对运算符进行操作,对运算符的操作其实就是对运算函数的重写或者重载。注意运算符操作一般被操做的参数往往要加上In-Out模式。

+、-(运算符重载)

我们在实际开发中,Swift可自定义运算符,并不限于预设的运算符,我们可以对+进行重载,使其完成Int与Double或者Flaot相加。
Swift提供了如下的函数,使得Int与Int可以相加:

       func + (left:Int,right:Int)->Int{
       return left+right

}
我们完全可以进行重构

func + (left:Int,right:Double)->Double
{
 return Double(left)+right

}

实现+运算符对数组进行添加元素

      func +<T>(var left:[T],right:T)->[T]
  {
       left.append(right)
       return left
  } 

经过实验,貌似Swift不支持对 = 的重构

++、–(前、后置运算符)

前面我们说的+以及没有说的-是双目运算符,而对于单目运算符,如++,–,Swift规定操作数放在单目运算符前面,这种运算符被称为前置运算符,操作数放在单目运算符后面,这种运算符被称为后置运算符。

重置前置运算符函数必须使用prefix关键字修饰,重置后置运算符必须使用postfix关键字修饰。

    prefix  func  ++ (operator:Type)->Type
{

 let result=++operator

}

                 `前置运算符函数`

postfix  func  -- (operator:Type)->Type
{

         let result=operator--
}

                 `后置运算符函数` 

例子:

      prefix func ++ <T> (inout array:[T])->[T] {
         array.append(array[array.count-1])
         return array
    }

    var strArr=["iOS","Android","WP"]
    print(++strArr)

+=(赋值运算符)

在C语言中提供了+=赋值运算符,实际就是把第二个值相加给第一个值,这里的第一个值就需要使用In-Out模式。

 func += <T>(inout left:[T],right:T)
{
left.append(right)
}

var myList=["iOS","Android"];
myList += "WP"
print(myList)

比较运算符

Swift中的Int、Double、String等类型都支持比较运算符,但如果自己定义的类型需要比较大小,则需要为自定义类型满足如下两个特征:

  • 遵守Equatable、Comparable两个协议。
  • 对自定义类型重载==和<两个运算符。
    只需要对自定义类型重载了==和<两个运算符,Swift即可以自动推断出!=、<=、>、>=这四种结果。

    格式如下:

      func  <(las:Type,hrs:Type)->Bool
      {
           let result=lhs<rhs
      }
    

    例子

     struct WXrect:Equatable,Comparable
     {
         var left:Double
         var top:Double
     var width:Double
         var height:double
        }
    fun ==(las:WXrect,hrs:WXrect)->Bool
    {
     return lhs.width*lhs.height==rhs.width*rhs.height
        }
    fun < (las:WXrect,hrs:WXrect)->Bool
    {
    return ls.width`*`ls.height`<`rhs.width*rhs.height
    }
        let rect1=WXrect(left:2.0,top:3.0,width:5.0,height:4.0)
        let rect2=WXrect(left:8.0,top:23.0,width:2.0,height:8.0)
                          letrect3=WXrect(left:7.0,top:3.0,width:10.0,height:10.0)
    
    print(rect1<rect2)
    print(rect1<=rect2)
    print(rect1!=rect2)
    print(rect1>rect2)
    

进阶—开发自己的运算符

经过上边的积累,我们已经掌握了运算符的操作,最后我们进行自己的运算符开发

两步搞定一个自定义运算符

  1. 声明 新的运算符。

    格式如下:

    prefix|infix|postfix operator 运算符名{} 
    
    prefix:代表前置运算符
    infix:代表双目运算符
    postfix:代表后置运算符
    
  2. 为新的运算符提供多个重载的运算符函数

如果重载的运算符是前置运算符,则需要在func关键字添加prefix关键字
如果重载的运算符是后置运算符,则需要在func关键字添加postfix关键字

下面抛砖引玉的开发一个乘方运算符:**

由于乘法应该是双目运算符,所以首先声明新的运算符:**

infix operator **{}

为新的运算符提供重载函数

     func ** (base:Int,exponent:Int)->Int
{
   var result = 1
  for _ in 1...exponent
{
 result *= base
}
return result
}

let a=5
let b=3
print("\(a)的\(b)次方为:\(a ** b)")

怎样?Swift强大吧!自己自定义运算符

下面我们看一道数学题

              20+10-5*5*5*2-30

这道题怎么做?我有些不会了!O(∩_∩)O哈哈~

这道数学题侧面反映了运算符是有先后执行顺序的,那么我们自定义第运算符不应该也有运算规则呢!

结合性(associativity)的值可取的值有left,right和none。左结合运算符跟其他优先级相同的左结合运算符写在一起时,会跟左边的操作数结合。同理,右结合运算符会跟右边的操作数结合。而非结合运算符不能跟其他相同优先级的运算符写在一起。默认优先性为100

infix operator **= { associativity left precedence 140 }
fun ** (base:Int,exponent:Int)
 {

}
2016-10-28 11:37:16 qq_23613747 阅读数 259
/**
 *  下标的使用
 */
struct Vector3{
    var x:Double = 0.0
    var y:Double = 0.0
    var z:Double = 0.0
    //设置下标
    subscript(index:Int) -> Double?{
        get{
            switch index{
            case 0:return x
            case 1:return y
            case 2:return z
            default:return nil
            }
        }
        set{
            guard let newValue = newValue else {return}
            switch index{
            case 0:x = newValue
            case 1:y = newValue
            case 2:z = newValue
            default:return
            }
        }
    }
}
var v = Vector3(x: 1.0, y: 2.0, z: 3.0)
v[0] = 100

////////////////////////////////////

struct Matrix {
    var data:[[Double]]
    let r:Int
    let c:Int
    
    init(row:Int,col:Int){
        self.r = row
        self.c = col
        data = [[Double]]()
        for _ in 0..<r{
            let aRow = Array(count: col, repeatedValue: 0.0)
            data.append(aRow)
        }
    }
    subscript(x:Int,y:Int) -> Double{
        get{
            //断言
            assert(x >= 0 && x < r && y >= 0 && y < c,"Index out of Range")
            return data[x][y]
        }
    }
}
//运算符的重载
func + (left:Vector3,right:Vector3) -> Vector3{
    return Vector3(x: left.x+right.x, y: left.y+right.y, z: left.z+right.z)
}

/**
 *  自定义运算符
 */
postfix operator +++{}//后置运算符,前置运算符prefix
postfix func +++(inout vector:Vector3) -> Vector3{
    return Vector3(x: vector.x+1, y: vector.y+1, z: vector.z+1)
}
va+++

//双目运算符,associativity结合性,precedence 优先级
infix operator ^{associativity left precedence 140}
func ^(left:Vector3,right:Vector3) -> Vector3{
    return right
}


Swift 运算符重载

阅读数 3322

没有更多推荐了,返回首页