Tag: 函数

开始Swift编程第5部分-函数,枚举和作用域

在上一篇文章中,我们介绍了if语句,while循环和for-in循环(通常仅称为for循环)。 开始进行Swift编程第4部分-决策和循环 在上一篇文章中,我们介绍了运算符,可选值和nil值。 medium.com 其中一些if语句非常大,如果我们想在该if语句中做多个事情怎么办? 它们将变得庞大且难以阅读。 这就是今天的全部。 让我们潜入。 功能 实际上,您可以在Swift中编写任何功能的程序。 我敢肯定,来自其他语言的人们正在思考,哦,是的! 事实是您真的不知道。 我们将在作用域部分中对此进行更多讨论,但是在全局范围内编写的代码将用作程序的入口点 。 入口点只是一种说法,这是程序启动时首先运行的代码。 很容易,对吧? 我们编写函数是因为它破坏了我们的代码,使其更易于阅读。 我们可以遵循一些编程原则,这些原则实际上只是为了使您的工作更轻松的准则,虽然列表并不详尽,但是足以让您思考如何使代码变得更好: 关注点分离 —如果您对字符串中的字母进行计数然后将两个数字相加,则可以采用这两个单独的函数,一个函数对字符串中的字母进行计数,另一个函数对数字进行累加。 单一责任原则 -概括为以下短语:每件事都有一份工作,每件事都做得很好。 不要重复自己(DRY) -这很明显,为什么要多次输入相同的文本? 为什么要多次输入相同的文本? 这让您发疯,知道我曾经做过,如果您是A型性格,但是当A型开发人员看到一遍又一遍写相同的东西时,他们就会发疯,这是个坏消息,几乎每个阅读您的代码的开发人员都在使用当他们这样做时,请输入心态。 你明白了吗? 好! 我们将在以后再讲更多,但是现在,这是一个很好的基础。 让我们开始向您展示一个用Swift编写的函数的示例。 语法可能看起来很奇怪,但我们将介绍所有内容。 我知道这乍看起来可能会令人困惑,但让我们来看一下。 首先,我们使用func关键字定义一个函数。 这让编译器知道,嘿,我希望下一个代码块可重复使用。 接下来,我们给函数命名为addTwoNumbers 。 函数名称后带有括号,如果没有参数,则将其保留为空: func doStuff() { /* doing stuff */ } 如果有参数(可以传递给函数的东西),则将它们包括在声明中。 在上面的示例中,我们确实有参数,确切地说是两个,我们有number和otherNumber 。 这些在示例中不是很具描述性,但应该是 。 您可能会注意到,我使用了number firstNumber和otherNumber secondNumber 。 number和otherNumber是我们在以后的调用中将引用这些参数的内容,因此我们知道我们要为哪个参数设置值。 […]

泛型函数

我最近使用了map函数,并注意到它的默认返回类型是“ T”。经过一番调查(例如Stackoverflow搜索),我发现“ T”代表一个占位符类型,并且map函数是通用的。 起初,我对自己说“太棒了!”,然后我的下一个想法是“但是,等等,什么是通用函数……🤔”如果您想知道同一件事,请继续阅读! 在分解通用函数之前,让我们首先(简要地)讨论通用代码。 根据Apple的文档,“通用代码使您可以编写灵活,可重用的函数和类型,这些函数和类型可以根据您定义的要求使用任何类型。”您可能熟悉的两个泛型是数组或字典-两种集合类型均允许您可以使用任何类型。 例如,一个字典可能是[String:String]类型,而另一个字典可能是[String:Double]类型。 同样,数组可以是[Int]类型,也可以是[Float]…类型。 按照这种逻辑, 泛型函数是接受任何类型的参数并返回任何类型的函数。 如果您看一下上面的函数,您可能会注意到calculateMinimum函数仅适用于Int类型。 如果我想对Float类型或Double类型使用完全相同的逻辑,则我必须为每种类型创建两个附加函数。 多次重复相同的代码似乎很愚蠢,对吧? 苹果公司也这么认为,这就是引入泛型功能概念的原因。 通用参数和通用返回类型 上面的genericCalculateMinimum函数与calculateMinimum完全相同,但有两个例外。 首先,genericCalculateMinimum而不是接受Int类型的参数并返回Int类型,而是接受类型“ T”的参数并返回类型“ T”。用编写的“ T”告诉Swift,类型“ T”的参数为实际上只是一个占位符类型。 因此,Swift知道在调用函数时根据函数内的输入来推断类型。 例如,如果我们看一下上面的第一个print语句,输入为4和2,Swift推断4和2为Int类型。 由于该函数返回“ T”,因此Swift对参数类型的推断也使其可以返回正确的类型。 因此,在这种情况下,它返回Int类型的值。 在函数内,如果尝试将valueToReturn设置为Bool,则会收到错误消息,因为Bool无法转换为该函数的正确Int返回类型。 同样,Swift从最后一个打印语句推断出参数的类型为String,因此它返回的值为String。 您可能想知道为什么将“ hello”打印为最小值而不是“ yes”。这是因为Swift会根据字符串的哈希值计算字符串的“值”。 根据Apple的文档,“…哈希值是一个Int值,对于所有相等比较的对象来说都是相同的……”用简单的英语来说,哈希值可以比较两个相同类型的变量。 默认情况下,String,Int,Double和Bool类型都可以访问hashValue属性。 查阅Alex的博客,以了解有关哈希值和哈希协议的更多信息。 上面两个函数之间的第二个区别是,genericCalculateMinimum符合Comparable协议。

@autoclosure什么,为什么以及何时

对约翰和帕维尔说“早上好” : 让我们对罗伯特说“早上好” : 让我们传递false作为第一个参数:罗伯特没有“早安” 。 但是输出窗口仍然显示出GiveAname函数: 预期:调用GiveAname()获得一个字符串,并将该字符串传递给goodMorning 。 第一个参数为false ,因此在这种情况下不使用第二个参数。 但是会调用功能GiveAname 。 如果我不希望调用GiveAname ,则应该使用闭包: @autoclosure可能很有用。 例如,这是一个断言函数: func assert(_条件:@autoclosure()->布尔,_消息:@autoclosure()->字符串) 这两个参数都可以是常量,变量或闭包: 让我们将此断言函数更改为仅在允许调试时才起作用: 在现实生活中,它看起来有些复杂,但含义相同: 公共功能断言 1.函数中的参数可以用不带参数的闭包代替,并返回与参数相同类型的值。 2.可以使用@autoclosure属性标记此类关闭参数。 3.无需在此类@ autoclosure-d参数周围加上括号。 值,传递的另一个函数或表达式自动用花括号包装。 4.用作已标记的关闭参数的另一个函数只有在从函数体中显式调用之前,才执行。 闭包– Swift编程语言(Swift 4.2) 注意如果您不熟悉捕获的概念,请不要担心。 下面在捕获中详细说明… docs.swift.org

Swift中的函数命名

在本文中,我们将面临一个问题,即编写函数时应始终问自己: 我应该如何命名这个功能? 尽管这个问题看起来很简单,但正确回答它却决定了我们作为软件开发人员的职业生涯中至关重要的方面。 正如我们将看到的,它使我们的代码库更清洁,更易于使用。 如果要使用第三方库中的函数,那么可以说创建了精美标签,您会发现以下两个选项: // 一种 静态函数makeLabel(withTitle标题:String)-> FancyLabel // B 静态函数configure(_ text:String)-> FancyLabel 您会更喜欢哪一个? A还是B? 如果您仍在犹豫,我会给您一个线索:常识也使我想到了选项A。 那么为什么选择A? 首先,让我们分析一下为什么B不那么好:选项B不能告诉我们我们到底在配置什么。 它是否存在? 它会创建一个新的吗? 它会返回新事物吗? 它也没有告诉我们它期望的String的含义是什么。 我们可以事先告诉我们的是,它接收一个String并返回一个FancyLabel ,但我们FancyLabel知道它的作用。 存在歧义和缺乏信息,这是我们应该避免的事情。 另一方面,选项A 对于这三件事完全是明确的 : 工作需要什么 -标题 它的作用 *- 使其成为标签 结果如何 – 创建的标签 *我们关心它做什么 (或应该做什么),而不是它如何做那件事。 我们不在乎函数的内部工作原理。 封装就是这样工作的。 仅需清楚这三点, 就可以很自然地使用此函数,因为这样我们就可以毫无误解地知道函数的作用。 就这么简单。 当我们看一下这些函数的调用方式时,将会更加清楚: let labelA = FancyLabel.makeLabel(withTitle:“ Hello world”)// clearlet labelB = FancyLabel.configure(“ […]

函数与计算属性-使用什么?

如果任何调用被认为是昂贵的,会在多次调用时引发错误或返回不同的结果-首选函数。 如果调用便宜,则不会引发错误,不会返回相同的结果,也不会缓存第一次调用的结果-计算属性可能会满足您的需求。 – – – – – – – – – – – – – – 要么 – – – – – – – – – – – – – – 如果您的代码执行了某个动作并返回了例如该动作的结果的描述,那么您应该首选函数。 如果您的代码计算出一个属性,但是从用户的角度来看,这可能是一个存储的属性,或者可能是一个存储的属性,需要先更新某些缓存的值,那么您应该更喜欢计算的属性。 例如 ,我们有CookieFactory类来烘烤一些cookie。 我们需要它来查看成分并决定要制作哪种曲奇。 它需要检查有多少成分可用以确定批次大小。 然后,它将需要分割并创建cookie。 听起来很复杂,所以要使用函数是这里的方法。 遵循统一访问原则 模块提供的所有服务都应通过统一的符号表示,无论是通过存储还是通过计算实现,都不应背叛。 —伯特兰·迈耶(Bertrand Meyer) 属性表示实例的固有质量,而方法则执行操作。 方法有参数; 属性没有。 对于有副作用的任何调用,最好使用方法。 如果某个方法执行某些操作(例如,它加载,解析,切换或打印)或具有动词名称,则它不应是属性。 首选属性以获取和/或设置简单值。 属性应表示类型实例的语义固有质量。 错误的计算属性示例: –随机值 – 今天的日期 –来自另一个对象或单例的值 […]

映射,过滤,减少,拖放Swift。 简单的高阶函数。

我已经对本文的主题进行了很多思考,并想向您介绍一些有用的且经常使用的简单高阶函数。 今天,我想整理一切,即使初学者也可以理解。 高阶函数对我来说很有趣,我将在这四个方面停下来:过滤,映射,缩小,删除。 当然,有4个以上,但是这些是最基本,最有趣的。 过滤器将此类元素返回给您的数组,并通过某个过滤器。 现在,我将向您展示过滤器如何在原始示例上工作: 传统方式 在emptyArray中,我们将具有以下数字:1、3、5、7、9。 代替这么长的代码,让我们使用filter : 结果,我们得到的答案是相同的,但是我们没有将空对象变成大量,也没有摆脱代码堆。 对数组中的每个元素执行操作以构建另一个数组。 想象一下,首先我们有很多成果: 现在让我们再创建一个由这些水果组成的数组。 传统方式 如果要使用map,我们将提供以下代码: 在此示例中,我们创建了一个名为fruitLowercase的空数组,该数组保留字符串值,并将simpleFruits的每个元素添加到fruitLowercase。 我向您展示了地图上最好和最短的版本,如果您想了解更多有关地图的信息,可以这样做,并将其留在下面的评论中。 过滤器帮助我们合并数组中的所有值并获得单个结果。 假设我们有一个任务要计算该数组中的所有字母。 这是一种传统方式: 传统方式 让我们看看,如果使用reduce将会怎样: 通过使用reduce将4行变成1。 0表示我们将开始增加多少。 当condition返回true时,从数组中抛出元素,返回false时停止。 之前: 传统方式 后: 它比以前容易得多。 好了,仅此而已! 我真的希望您能在项目中使用它,并使您的雇主惊奇。 今天,我向您展示了3种不同的高阶函数。 它们可以缩短您的代码并提高其可读性。 在评论中写下您希望我添加的内容,或在下一篇文章中写下。

Swift中的泛型函数

泛型是Swift最强大的功能之一,许多Swift标准库都是使用泛型代码构建的。 Swift 4语言提供“通用”功能来编写灵活且可重用的函数和类型。 泛型用于避免重复并提供抽象。 现在让我们看看快速语言中泛型函数的用法以及如何使用它。 例如,考虑使用以下程序交换值。 如果我们看上面的程序,该函数仅接受Int值。 因此,如果我们要编写用于接受“ String”或“ Double”值的函数,则必须编写两个类似的函数,用“ String”或“ Double”替换“ Int”。 因此,如果我们要编写一个接受任何类型的函数(无论是Int , Double还是String) ,该怎么办。 ? 为此,我们需要编写通用函数。 如何编写泛型函数? Swift 4提供作为通用类型参数名称 func swapTwoValues(_ a: inout T, _ b: inout T) { let temporaryA = a a = b b = temporaryA } swapTwoValues(_:_:)函数的主体与swapTwoInts(_:_:)函数的主体相同。 但是, swapTwoValues(_:_:)的第一行与swapTwoValues(_:_:)略有不同。 以下是第一行的比较: func swapTwoInts(_ a: inout Int, _ b: inout […]