前言

Swift统一的函数语法足够灵活,可以用来表示任何函数,包括从最简单的没有参数名字的 C 风格函数,到复杂的带局部和外部参数名的Objective-C风格函数。参数可以提供默认值,以简化函数调用。参数也可以既当做传入参数,也当做传出参数,也就是说,一旦函数执行结束,传入的参数值可以被修改。

在 Swift 中,每个函数都有一种类型,包括函数的参数值类型和返回值类型。你可以把函数类型当做任何其他普通变量类型一样处理,这样就可以更简单地把函数当做别的函数的参数,也可以从其他函数中返回函数。函数的定义可以写在在其他函数定义中,这样可以在嵌套函数范围内实现功能封装。

注明:Swift版本为2.1
测试环境:xcode 7.2

函数定义与调用(Defining and Calling Functions)

函数定义语法为:func 函数名(参数列表) ->返回值:

// 函数定义方式:func 函数名称(arg...) ->ReturnValue
func testFunc() ->Void {
  // 无参数,无返回值
}

若无返回值,可以直接省略 ->Void

func testArgFunc(arg: Int) {
  // 无返回值可以使用Void,其实是空元组
}
 


我们先来看看官方定义的Void是什么:

/// The empty tuple type.
///
/// This is the default return type of functions for which no explicit
/// return type is specified.
publictypealiasVoid=()


它其实就是一个空元组。它是作为函数无显示指定返回类型时的默认返回值类型。

参数列表可以使用可变参数:

// 可变参数
funccalSum(array: Int...)->Int{
  varsum=0
  
  foriteminarray{
    sum+=item
  }
  
  returnsum
}


函数调用就是通过我们的函数名称调用:

calSum(1,2,3)// 6
calSum(1,2)// 3


swift支持函数重载:

// 函数重载
funccalSum(array:[Int])->Int{
  varsum=0
  
  foriteminarray{
    sum+=item
  }
  
  returnsum
}
 
// 调用方式与上面一样,只是参数类型不一样
calSum([1,3])// 6
calSum([1,4,5])// 10


函数有多个参数时,使用逗号分开,像:(arg1: Int,arg2,Int,arg3: Int)

funcmultipleFunc(arg1: Int,_ arg2: Int)->Int{
  return0
}

多重返回值函数(Functions with Multiple Return Values)

当函数有多个返回值时,我们可以使用元组作为返回值,当然也可以使用数组、字典等,但是使用元组更简单,更明确:

funcminMax(array:[Int])->(min: Int,max: Int){
    varcurrentMin=array[0]
    varcurrentMax=array[0]
    forvalueinarray[1..<array.count]{
        ifvalue<currentMin{
            currentMin=value
        }elseifvalue>currentMax{
            currentMax=value
        }
    }
    return(currentMin,currentMax)
}


Optional返回值类型

当函数不一定有返回值时,可以返回可选类型,在类型后面添加个问号即可:

funcminMax(array:[Int])->(min: Int,max: Int)?{
    ifarray.isEmpty{returnnil}
    varcurrentMin=array[0]
    varcurrentMax=array[0]
    forvalueinarray[1..<array.count]{
        ifvalue<currentMin{
            currentMin=value
        }elseifvalue>currentMax{
            currentMax=value
        }
    }
    return(currentMin,currentMax)
}
 
// 调用的时候,通过值绑定来判断是否有值
ifletbounds=minMax([8,-6,109,3,71]){
    print("min is \(bounds.min) and max is \(bounds.max)")
}
// prints "min is -6 and max is 109"


指定外部参数名(Specifying External Parameter Names)

我们看看Dictonary的一个API:

publicmutatingfuncremoveAll(keepCapacitykeepCapacity: Bool=default)

我们可以看到这里一个参数有两个名字:keepCapacity,其中第一个叫外部参数名,第二个叫函数内部变量。

比如,with是外部参数名,用于在调用时显示的;而userId是函数内部变量名,用于内部使用:

funcfind(with userId: Int)->User?{
  
}
 
ifletuser=find(with:10){
  // find
}

默认参数值(Default Parameter Values)

默认参数要放在参数列表最后:

funcsomeFunction(parameterWithDefault: Int=12){
    // function body goes here
    // if no arguments are passed to the function call,// value of parameterWithDefault is 12
}
someFunction(6)// parameterWithDefault is 6
someFunction()// parameterWithDefault is 12


可变参数(Variadic Parameters)

可变参数可以接收多个参数:

// 可变参数  
// 可变参数接受0个或者多个指定类型的值。可变参数使用...表示  
// 函数最多只能有一个可变参数,并且如果有可变参数,这个可变参数必须出现在参数列表的最后  
// 如果参数列表中有一或多个参数提供默认值,且有可变参数,那么可变参数也要放到所有最后一个  
// 提供默认值的参数之后(先是默认值参数,才能到可变参数)  
funcarithmeticmean(numbers: Double...)->Double{  
  vartotal=0.0  
  fornumberinnumbers{  
    total+=number  
  }  
  returntotal/Double(numbers.count)  
}  
  
arithmeticmean(1,45)// return 3.0  
arithmeticmean(1,3)// return 2.0  


常量参数和变量参数(Constant and Variable Parameters)

函数参数默认是常量。试图在函数体中更改参数值将会导致编译错误。这意味着你不能错误地更改参数值。

如果要在函数内部修改参数值,那么需要手动声明为变量类型:

// 常量和变量参数  
// 在函数参数列表中,如果没有指定参数是常量还是变量,那么默认是let,即常量  
// 这里Str需要在函数体内修改,所以需要指定为变量类型,即用关键字var  
funcalignRight(var str: String,count: Int,pad: Character)->String{  
  letamountToPad=count-countElements(str)  
    
  // 使用_表示忽略,因为这里没有使用到  
  for_in1...amountToPad{  
    str=pad+str  
  }  
    
  returnstr  
}


输入输出参数(In-Out Parameters)

// 输入/输出参数  
// 有时候,在函数体内修改了参数的值,如何能直接修改原始实参呢?就是使用In-Out参数  
// 使用inout关键字声明的变量就是了  
// 下面这种写法,是不是很像C++中的传引用?  
funcswap(inout lhs: Int,inout rhs: Int){  
  lettmp=lhs  
  lhs=rhs  
  rhs=tmp  
}  
 
// 如何调用呢?调用的调用,对应的实参前面需要添加&这个符号  
// 因为需要修改,所以一定是var类型的  
varfirst=3  
varsecond=4  
// 这种方式会修改实参的值  
swap(&first,&second)// first = 4,second = 3 


函数类型(Function Types)

// 使用函数类型  
// 这里是返回Int类型  
// 函数类型是:(Int,Int) -> Int  
funcaddTwoInts(first: Int,second: Int)->Int{  
  returnfirst+second  
}  
 
// 函数类型是:(Int,Int) -> Int  
funcmultiplyTwoInts(first: Int,second: Int)->Int{  
  returnfirst*second  
}  

使用函数类型(Using Function Types)

函数类型也需要类型,也可以用于定义变量,只是它是函数指针类型变量:

varmathFunction:(Int,Int)->Int=addTwoInts  
 
mathFunction(1,2)// return 3  
 
mathFunction=multiplyTwoInts  
 
mathFunction(1,2)// return 2 


函数类型作为参数类型(Function Types as Parameter Types)

函数类型也是类型,也可以作为函数的形参:

// 函数类型可以作为参数  
funcprintMathResult(mathFunction:(Int,Int)->Int,first: Int,second: Int){  
  println("Result:\(mathFunction(first,second))")  
}  
  
printMathResult(addTwoInts,5)// prints "Result: 8"  
printMathResult(multiplyTwoInts,5)// prints "Result: 15"  


函数类型作为返回类型(Function Types as Return Types)

函数类型也可以作为返回值类型:

// 函数作为返回类型  
funcstepForward(input: Int)->Int{  
  returninput+1  
}  
  
funcstepBackward(intput: Int)->Int{  
  returninput-1  
}  
  
funcchooseStepFunction(backwards: Bool)->((Int)->Int){  
  returnbackwards? stepBackward : stepForward  
}  
  
varcurrentValue=3  
letmoveNearerToZero=chooseStepFunction(currentValue>0)// call stepBackward() function  
  
// 参数可以嵌套定义,在C、OC中是不可以嵌套的哦  
funcchooseStepFunction(backwards: Bool)->((Int)->Int){  
  funcstepForward(input: Int)->Int{  
    returninput+1  
  }  
    
  funcstepBackward(input: Int)->Int{  
    returninput+1  
  }  
    
  returnbackwards?stepBackward: stepForward  
}  
 


嵌套函数(nested Functions)

在Ojbective-C中,函数是不能嵌套定义的,但是在swift中是可以嵌套的:

funcchooseStepFunction(backwards: Bool)->(Int)->Int{
    funcstepForward(input: Int)->Int{returninput+1}
    funcstepBackward(input: Int)->Int{returninput-1}
    returnbackwards? stepBackward : stepForward
}
 
varcurrentValue=-4
letmoveNearerToZero=chooseStepFunction(currentValue>0)
// moveNearerToZero Now refers to the nested stepForward() function
whilecurrentValue!=0{
    print("\(currentValue)... ")
    currentValue=moveNearerToZero(currentValue)
}
print("zero!")
// -4...
// -3...
// -2...
// -1...
// zero!

Swift函数的更多相关文章

  1. ios – 声明NSDictionary并在Swift中添加键值对?

    我一直在尝试使用类类型键和值来声明一个NSDictionary,如下所示:这里,“Category”和“SubCategory”是全局类.我知道我不能将类类型用于关键字段.但是,无论如何,我应该做到这一点.有没有办法做到这一点?如何声明专门的NSDictionary或类似的东西来做到这一点?

  2. ios – Swift相当于`[NSDictionary initWithObjects:forKeys:]`

    Swift的原生字典是否与[NSDictionaryinitWithObjects:forKeys:]相当?假设我有两个带键和值的数组,并希望将它们放在字典中.在Objective-C中,我这样做:当然我可以通过两个数组迭代一个计数器,使用vardict:[String:Int]并逐步添加东西.但这似乎不是一个好的解决方案.使用zip和enumerate可能是同时迭代两者的更好方法.然而,这种方法

  3. ios – 如何从变量访问属性或方法?

    是否可以使用变量作为Swift中方法或属性的名称来访问方法或属性?在PHP中,您可以使用$object->{$variable}.例如编辑:这是我正在使用的实际代码:解决方法你可以做到,但不能使用“纯粹的”Swift.Swift的重点是防止这种危险的动态属性访问.你必须使用Cocoa的Key-ValueCoding功能:非常方便,它完全穿过你要穿过的字符串到属性名称的桥,但要注意:这里是龙.

  4. iOS &gt;&gt;块&gt;&gt;更改块外部的变量值

    我不是在处理一个Object并改变它,就像我的mString一样.我希望’center’属性的行为类似于myInt,因为它是直接访问的C结构,而不是指向对象的指针.我希望’backgroundColor’的行为类似于我的imstring,因为它是一个指向一个新对象的对象的指针,不是吗?

  5. ios – Xcode Bot:如何在post触发器脚本上获得.ipa路径?

    我正在使用机器人来存档iOS应用程序,我需要获取.ipa产品路径才能将其发布到我们的分发系统中.机器人设置:并使用脚本打印所有env变量,其中不包含ipa文件的路径.此外,一些变量指向不存在的目录,即:XCS_OUTPUT_DIR这里的env变量输出:除此之外,我还能够确认.ipa文件是在另一个文件夹中创建的(/IntegrationAssets//

  6. ios – 类型不符合协议

    我仍然无法理解Swift中泛型的一些微妙之处.我定义了以下类型:viewForValue现在我定义了以下功能.我希望T是一个符合协议SomeProtocol的UIView.但是,当我执行代码时,我收到以下编译错误:似乎在where子句中我不能指定不实现协议的类.这是为什么?

  7. ios – 使用附加字符串本地化Info.plist变量

    我正在尝试本地化应用程序的名称,同时仍然能够根据构建配置追加字符串.所以目前它被设置为:该设置定义为:通过这种方式,我们可以为应用程序添加后缀以用于不同的beta版本.问题是,当我们尝试本地化本地化的InfoPlist.strings中的应用程序显示名称时,就像这样我们覆盖存储在Info.plist中的值,并丢失后缀字符.这有什么好办法吗?

  8. iOS – 开始iOS教程 – 变量之前的下划线?

    这是正确的还是我做错了什么?

  9. ios – 静态计算变量被多次实例化

    我有一个日期格式化程序,我试图在UITableViewCell子类中创建一个单例,所以我创建了一个这样的计算属性:问题是我不止一次看到print语句,这意味着它不止一次被创建.我已经找到了其他方法,但我很想知道这里发生了什么.有任何想法吗?解决方法您的代码段相当于只获取属性,基本上它与以下内容相同:如果你只想运行一次,你应该像定义一个惰性属性一样定义它:

  10. ios – 将Swift项目转换为易于使用的Cocoapods框架

    编辑1:我更新了项目,因此它已经具有框架结构,我只需要弄清楚我将如何向开发人员提供对自定义部件的访问权限.编辑2:我得到了一个答案,但我认为这个问题可能很容易被误解.目标是使其行为和行为像UICollectionView(与委托,数据源,…

随机推荐

  1. Swift UITextField,UITextView,UISegmentedControl,UISwitch

    下面我们通过一个demo来简单的实现下这些控件的功能.首先,我们拖将这几个控件拖到storyboard,并关联上相应的属性和动作.如图:关联上属性和动作后,看看实现的代码:

  2. swift UISlider,UIStepper

    我们用两个label来显示slider和stepper的值.再用张图片来显示改变stepper值的效果.首先,这三个控件需要全局变量声明如下然后,我们对所有的控件做个简单的布局:最后,当slider的值改变时,我们用一个label来显示值的变化,同样,用另一个label来显示stepper值的变化,并改变图片的大小:实现效果如下:

  3. preferredFontForTextStyle字体设置之更改

    即:

  4. Swift没有异常处理,遇到功能性错误怎么办?

    本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请发送邮件至dio@foxmail.com举报,一经查实,本站将立刻删除。

  5. 字典实战和UIKit初探

    ios中数组和字典的应用Applicationschedule类别子项类别名称优先级数据包contactsentertainment接触UIKit学习用Swift调用CocoaTouchimportUIKitletcolors=[]varbackView=UIView(frame:CGRectMake(0.0,0.0,320.0,CGFloat(colors.count*50)))backView

  6. swift语言IOS8开发战记21 Core Data2

    上一话中我们简单地介绍了一些coredata的基本知识,这一话我们通过编程来实现coredata的使用。还记得我们在coredata中定义的那个Model么,上面这段代码会加载这个Model。定义完方法之后,我们对coredata的准备都已经完成了。最后强调一点,coredata并不是数据库,它只是一个框架,协助我们进行数据库操作,它并不关心我们把数据存到哪里。

  7. swift语言IOS8开发战记22 Core Data3

    上一话我们定义了与coredata有关的变量和方法,做足了准备工作,这一话我们来试试能不能成功。首先打开上一话中生成的Info类,在其中引用头文件的地方添加一个@objc,不然后面会报错,我也不知道为什么。

  8. swift实战小程序1天气预报

    在有一定swift基础的情况下,让我们来做一些小程序练练手,今天来试试做一个简单地天气预报。然后在btnpressed方法中依旧增加loadWeather方法.在loadWeather方法中加上信息的显示语句:运行一下看看效果,如图:虽然显示出来了,但是我们的text是可编辑状态的,在storyboard中勾选Editable,再次运行:大功告成,而且现在每次单击按钮,就会重新请求天气情况,大家也来试试吧。

  9. 【iOS学习01】swift ? and !  的学习

    如果不初始化就会报错。

  10. swift语言IOS8开发战记23 Core Data4

    接着我们需要把我们的Rest类变成一个被coredata管理的类,点开Rest类,作如下修改:关键字@NSManaged的作用是与实体中对应的属性通信,BinaryData对应的类型是NSData,CoreData没有布尔属性,只能用0和1来区分。进行如下操作,输入类名:建立好之后因为我们之前写的代码有些地方并不适用于coredata,所以编译器会报错,现在来一一解决。

返回
顶部