作为一等公民的vc 数组作为入参应该据有哪些操作

工具类服务
编辑部专用服务
作者专用服务
科学大数据云分析服务的性能优化技术研究
随着科学技术的发展,科学数据的爆炸式增长给其存储和分析带来了巨大的压力,如何高效的存储和分析科学数据成为一个巨大的难题。一方面,科学数据模型一般以数组为主,传统关系型数据库的数据模型是表结构,因此不能天然的支持数组模型,而是采用与分析型软件相结合的方式来进行科学分析。另一方面,采用RDBMS和分析软件相结合的方式会带来昂贵的成本;因此迫切需要一个能够有效存储和分析科学数据并能降低成本的系统。阵列数据库和云计算技术的兴起给科学大数据管理和分析需求带来了良机。阵列数据库以数组为一等公民,能天然支持科学数据的存储和分析;云计算采用先进的分布式计算及存储架构整合资源的方式向外提供资源服务,为用户降低了使用成本。&br&  因此,结合阵列数据库与云计算平台的优势为科学家和研究机构提供高性能科学大数据云分析服务,具有重要应用价值和现实意义。本文综合分析了当前多种阵列数据库和云平台架构,结合当前科学大数据管理系统的优缺点对科学大数据云分析处理系统进行了深入研究和性能优化。主要研究内容为:(1)构建了云平台 Proxmox VE,为云分析服务提供了平台环境;(2)在云平台上设计并实现了科学大数据云分析服务原型系统FASTDB;(3)对FASTDB系统进行了两个角度的性能评估实验,为后续 FASTDB的性能优化提供了基础;(4)提出了 FASTDB系统的存储块分割算法 CLD以及实现了简单的基于数组统计信息的 Cost-based查询优化器,提高了科学大数据云分析服务系统FASTDB的查询分析性能。
年,卷(期):
在线出版日期:
本文读者也读过
相关检索词
万方数据知识服务平台--国家科技支撑计划资助项目(编号:2006BAH03B01)(C)北京万方数据股份有限公司
万方数据电子出版社Swift学习总结 - 简书
Swift学习总结
Swift学习总结
程序是指令的集合,写程序就是写一系列的指令去控制计算机做我们想做的事情。编译:将程序设计语言转换成计算机能够理解的机器语言或者某种中间代码的过程。
冯诺依曼体系结构的计算机:1.使用二进制2.程序存储执行
变量和常量
定义变量和常量是为了保存数据。变量和常量就是某种类型的值的存储空间。
var a:Int = 10
var c = 10000
let d:Int = 10
//compiler error
let e = 1000
说明:1.Swift有非常强大的类型推断,所以定义变量或常量时如果可以的话应该直接使用类型推断不用手动指定类型
2.如果可以的话应该尽可能使用常量而不是变量。
var a:Int = 10
关键字:有特殊含义的单词标识符:始变量、常量、函数、类、结构、枚举、协议、方法属性等起的名字
数字、字母、下划线,数字不能开头
大小写敏感(区分大小写)
不能使用关键字做标识符
使用驼峰命名法(命名变量、常量、函数、方法、属性第一个单词小写,从第二个单词开始每个单词首字母大写;命名类、结构、协议、枚举每个单词首字母都要大写)
命名私有的属性和方法时以下划线开头
运算符:Swift中的运算符其实都是函数
1.赋值运算符:=、+=、-=2.算术运算符:+、-、*、/、%3.比较运算符:==、!=、&、&=、&、&=4.逻辑运算符:&&、||、!5.条件运算符:?:6.其它运算符:[]、.、??、?、!
字面(常)量
1.整数字面量:10、1_234_567、0x10、0o10、0b102.小数字面量:123.45、1.xab.cdp23.字符字面量:"c"、"\n"、"\u{41}"、"\u(9a86)"4.字符串字面量:"Hello"、"caf\u{e9}"5.布尔字面量:true、false6.空值字面量:nil7.类型字面量:String.self、UILable.self
分隔符:将不同的语言元素符号分开
说明:Swift中每个语句后面的分号可写可不写的,写代码时尽量保证一行只有一条语句这样就可以省略掉分号。
分支和循环
if...else...
下面的程序实现了对是否是闰年问题的判断。
let year = 2005
if year % 4 == 0 && year % 100 != 0 || year % 400 == 0{
print("\(year)是闰年")
print("\(year)不是闰年")
switch...case...default...
下面的程序实现了将百分制的成绩转换成不同级别。
let score = 85.5
let msg:String
switch score{
case 90...100:msg = "优秀"
case 80..&90:msg = "良好"
case 70..&80:msg = "中等"
case 60..&70:msg = "及格"
default:msg = "不及格"
print{msg}
下面的程序实现了1-100的求和。
var sum = 0
for i in 1...100{
print(sum)
下面的程序实现了1-100的求和。
var sum = 0
while i &= 100{
print(sum)
repeat...while...
下面的程序实现了1-100的求和。
var sum = 0
}while j &= 100
print(sum)
穷举法:穷尽所有可能性直到找到正确答案。
下面的程序实现了"百钱百鸡"问题的求解
for x in 0...20{
for y in 0...33{
let z = 100 - x - y
if 5 * x + 3 * y + z / 3 == 100 && z % 3 == 0{
print("公鸡:\(x),母鸡:\(y),小鸡:\(z)")
说明 在循环中可以使用break关键字来提前终止循环,也可以使用continue关键字使循环直接进入下一轮,但是应该尽量减少对break和continue的使用,因为它们不会让你的程序变得更好。
综合案例:Craps赌博游戏.
游戏规则:玩家摇两颗色子,如果第一次摇出了7点或11点,玩家胜;如果摇出了2点、3点、12点,庄家胜;摇出其它点数游戏继续。在继续的过程中玩家重新摇色子,如果摇出了第一次摇的点数,玩家胜;摇出7点,庄家胜;其它点数游戏继续直到一方获得胜利。
func roll() -& Int{
return Int(arc4random_uniform(6)) + 1
let firstPoint = roll() + roll()
print("玩家摇出了\(firstPoint)点")
var needsGoOn = false
switch firstPoint{
case 7,11:print("玩家胜")
case 2,3,12:print("庄家胜")
default:needsGoOn = true
while needsGoOn{
let currentPoint = roll() + roll()
print("玩家摇出了\(currentPoint)")
if currentPoint == 7{
print("庄家胜")
needsGoOn = false
else if currentPoint = firstPoint{
print("玩家胜")
needsGoOn = false
needsGoOn = true
数组是使用连续的内存空间保存多个同类型的元素的容器,因为数组中的元素在内存中是连续的,所以可以使用下标运算来访问数组中的元素,实现随机存取。
var array1:[Int] = []
var array2:Array&Int& = []
var array3 = [1,2,3,4,5]
var array4 = [Int](count:5,repeatedValue:0)
var array5 = Array&Int&(count:5,repeatedValue:0)
array1.append(2)
array1.append(3)
array1.insert(1,atIndex:0)
array1.insert(4,atIndex:array1.count)
array1 += [5]
array1 += [6,7,8]
array1.removeAtIndex(2)
arrar1.removeFirst()
array1.removeFirst(2)
array1.removeLast()
array1.removeRange(1...2)
array1.removeAll()
array3[0] = 100
array3.[array.count-1] = 500
for i in 0..&array3.count{
print(array3[i])
for temp in array3{
print(temp)
for temp in array3[1...3]{
print(temp)
说明for-in循环是一个只读循环,这也就意味着在循环的过程中不能对数组中的元素进行修改
for(i,temp) in array3.enumerate(){
if i == 0{
array[i] = 1
print("\(i).\(temp)")
提醒:操作数组时最重要的是不要越界访问元素。数组对象的count属性表明了数组中有多少个元素,那么在有效的索引范围是0到count-1
数组中的元素也可以是数组,因此我们可以构造多维数组,最常见的是二维数组,它相当于是一个有行有列的数组,数组中的每个元素代表一行,该数组中的每个元素代表行里面的列。二维数组可以模拟现实世界中的表格、数学上的矩阵、棋类游戏的棋盘、2D游戏中的地图,所以在实际开发中应用广泛。
下面的程序是用二维数组模拟表格的例子。
func randomInt(min:UInt32,max:UInt)-&Int{
return Int(arc4random_uniform(max - min + 1) + min)
let namesArray = ["赵","钱","孙","李","周"]
let coursesArray = ["语文","数学","英语"]
var scoresArray = [[Double]](count:namesArray.count,repeatedValue:
[Double](count:coursesArray.count,repeatedValue:0))
for i in 0..&scoresArray.count{
for j in 0..&scoresArray[i].count{
scoresArray[i][j] = Double(randomInt(50,max:100))
for (index,array) in scoresArray.enumerate(){
var sum = 0.0
for score in array{
sum += score
let avg = sum / Double(coursesArray.count)
print("\(namesArray[index])的平均成绩为:\(avg)")
for i in 0..&coursesArray.count{
var sum = 0.0
for row in 0..&coursesArray.count{
sum += scoresArray[row][i]
let avg = sum/Double(namesArray.count)
print("\(coursesArray[i])课的平均成绩为:\(avg)")
集合在内存中是离散的,集合中的元素通过计算Hash Code(哈希码或散列码)来决定存放在内存中的什么位置,集合中不允许有重复元素。
let set:Set&Int& = [1,2,1,2,3,5,10,200]
添加和删除元素
set.insert(100)
set.removeFirst()
set.remove(5)
set.removeAll()
集合运算(交集、并集、差集)
var set1:Set&Int& = [1,2,1,2,3,4,5]
var set2:Set&Int& = [1,3,5,7]
set1.intersect(set2)
set1.union(set2)
set1.subtract(set2)
字典是以键值对的方式保存数据的容量,字典中的每个元素都是键值对组合,通过键可以找到对应的值。
var dict [Int:String] = [1:"hello"
3:"wonderful"
5:"delicious"]
添加、删除、修改元素
dict[3]= "terrible"
dict[4] = "shit"
dict[5] = nil
for key in dict.keys{
print("\(key)---&\(dict[key]!)")
for value in dict.values{
print(value)
for (index,value) in dict.enumerate(){
print("\(index).\(value.0)---&\(value.1)")
排序1.sort2.sortInPlace
let array = [23,45,12,89,98,55,7]
array.sort({(one:Int,two:Int) -& Bool in return one & two })
array.sort({(one,two) in one & two })
array.sort({one,two in one & two })
array.sort({$0 & $1})
array.sort{$0 & $1}
array.sort(&)
说明:排序方法的参数是一个闭包(closure),该闭包的作用是比较数组中两个元素的大小
过滤:筛选掉不满足条件的数据
let array = [23,45,12,89,98,55,7]
let newArray = array.filter{ $0 & 50}
print(newArray)
//[89,98,55]
映射:通过映射对数据进行变换处理
let array = [23,45,12,89,98,55,7]
let newArray = array.map{ sqrt(Double($0))}
print(newArray)
let array = [23,45,12,89,98,55,7]
let newArray = array.reduce(0,combine:+)
print(newArray)
函数和闭包
函数是独立的可重复使用的功能模块,如果程序中出现了大量的重复代码,通常都可以将这部分功能封装成一个独立的函数。在Swift中,函数是"一等公民";函数可以作为类型来使用,也就是说 函数可以赋值给一个变量或常量,可以将函数作为函数的参数或者返回值,还可以使用高阶函数。
func 函数名([参数1:类型,参数2:类型,...])[throws][rethrows][-&返回类型]{
函数的执行体
[return 表达式]
外部参数名
函数名(外部参数名 内部参数名: 类型, 外部参数名 内部参数名: 类型)如果不写外部参数名那么内部参数名也是外部参数名,可以使用_来作为外部参数名表示省略外部参数名
func myMin(a x: Int, b y: Int) -& Int {
return x & y ? x : y
func myMin( x: Int, _ y: Int) -& Int {
return x & y ? x : y
inout - 输入输出参数(不仅将数据传入函数还要从函数中取出数据),inout类型的参数前要加上&符号
func createX(inout x: Int) {
createX(&x)
可变参数列表
Swift中函数的参数列表可以是可变参数列表(参数的个数是任意多个)
func sum(nums: Int...) -& Int {
var total = 0
for num in nums {
total += num
return total
闭包就是没有名字的函数或者称之为函数表达式(Lambda表达式),Objective-C与之对应的概念叫block.如果一个函数的参数类型是函数我们可以传入一个闭包;如果一个函数的返回类型是函数我们可以返回一个闭包;如果一个类的某种属性是函数我们也可以将一个闭包表达式赋值给它。
{ ([参数列表]) [-&返回类型] in 代码 }
面向对象编程(OOP)
对象:接收消息的单元。
类:对象的蓝图和模板,类是一个抽象概念。
消息:对象之间通信的方式,通过给对象发消息可以让对象执行对应的操作来解决问题
抽象:定义类的过程就是一个抽象的过程,需要做数据抽象和行为抽象,数据抽象找到对象的属性(保存对象状态的存储属性),行为抽象找到对象的方法(可以给对象发的消息)。
封装:观点一:我们在类中写的方法其实就是在封装API,方法的内部实现可能会很复杂,但是这些对调用者来说是不可见的,调用只能看到方法有一个简单清晰的接口,这就是封装。观点二:将对象的属性和操作这些属性的方法绑定在一起。观点三:隐藏一切可以隐藏的实现细节,只提供简单清晰的编程口(界面)。
继承:从已有的类创建新类的过程,提供继承信息的称为父类(超类/基类,得到继承信息的称为子类(派生类/衍生类)。通常子类除了得到父类的继承信息还会增加一些自己特有的东西,所以子类的能力一定比父类更强大。继承的意义在于子类可以复用父类的代码并且增强系统现有的功能。
多态:同样的引用调用相同的方法但是做了不同的事情。
存储属性:类自身具有的属性(找名词)
方法:写到类里面的函数或者说跟对象绑定的行为就是方法
对象方法:给对象发的消息
类方法:给类发的消息,与对象的状态无关的方法
计算属性:通过对存储属性做运算得到的属性,通常获得某个计算出的值的方法都可以设计成计算属性。
指派构造器:被其他初始化方法调用的初始化方法。
便利构造器(convenience):调用了其他的初始化方法的初始化方法。
必要构造器(required):必要构造器意味着子类也要提供一模一样的构造器.
2.创建对象3.给对象发消息
class Triangle {
var a: Double
var b: Double
var c: Double
init(a: Double, b: Double, c: Double) {
self.a = a
self.b = b
self.c = c
// 类方法(发给类的消息与对象状态无关)
// 此处的static也可以换成class作用相同
static func isValid(a: Double, _ b: Double, _ c: Double) -& Bool {
return a + b & c && b + c & a && c + a & b
// 对象方法(发给对象的消息与对象状态有关)
func perimeter() -& Double {
return a + b + c
let a = 1.0
let b = 2.0
let c = 3.0
// 在创建对象前先调用类方法判定给定的三条边能否构成三角形
// 类方法是发给类的消息所以不用创建对象直接通过类名调用
if Triangle.isValid(a, b, c) {
let t = Triangle(a: a, b: b, c: c)
// 对象方法是发给对象的消息要先创建对象才能调用
print(t.perimeter())
print("无法创建三角形")
枚举:枚举是定义符号常量的最佳方式, 符号常量总是优于字面常量。
结构(体)
总结:类和结构的区别,什么时候使用类,什么时候使用结构区别1: 结构的对象是值类型, 类的对象是引用类型,值类型在赋值的时候会在内存中进行对象的拷贝,引用类型在赋值的时候不会进行对象拷贝只是增加了一个引用.区别2: 结构会自动生成初始化方法区别3: 结构中的方法在默认情况下是不允许修改结构中的属性除非加上mutating关键字.结论: 我们自定义新类型时优先考虑使用类而不是结构除非我们要定义的是一种底层的数据结构(保存其他数据的类型)
扩展(extension)
如果在某个特定的应用场景中你发现现有的类缺少了某项功能,那么可以通过类扩展(extension)的方式现场添加这项功能
运算符重载:为自定义的类型定义运算符
class Student{
var name:String
init(name:String){
self.name = name
func &(one: Student, two: Student) -& Bool {
return one.name & two.name
下标运算(subscript)
访问修饰符
private(私有的):存储属性通常是private的,因为数据要保护起来。
internal(内部的):如果自定义的类没有打算在其他项目中使用,可以不写访问修饰符。直接使用默认的internal修饰符表示在本项目中公开对其他项目私有。
public(公共的):方法一般是public的,因为方法是对象接受的消息。
面向协议编程(POP)
protocal 协议名[父协议1,父协议二...]{
//方法的集合(计算属性相当于就是方法)
协议是方法的集合(计算属性相当于就是方法),可以把看似不相关的对象的公共行为放到一个协议中。协议在Swift开发中大致有三种作用:1.能力:遵循了协议就意味着具备了某种能力2.约定:遵循了协议就一定要实现协议中的方法3.角色:一个类可以遵循多个协议, 一个协议可以被多个类遵循, 遵循协议就意味着扮演了某种角色, 遵循多个协议就意味着可以扮演多种角色
依赖倒转原则
用协议实现委托回调
一个对象想做某件事情但是自身没有能力做这件事就可以使用委托回调,具体步骤是:1.设计协议,让被委托方遵循协议并实现协议中的方法2.委托方有一个属性是协议类型的,通过该属性可以调用协议中的方法
注意:委托方的协议类型的属性通常是可空类型,要写成弱引用(weak)
协议组合:protocal&协议1,协议2,...&
协议扩展:对协议中的方法给出默认实现,可以设计出更通用的代码
让类型不再是程序中的硬代码
泛型类/结构/枚举
定义一个虚拟类型T, 调用函数时根据传入的参数类型来决定T到底是什么
func mySwap&T&(inout a: T, inout _ b: T) {
let temp = a
注意:Swift中的类、结构和枚举都可以使用泛型.
泛型限定:&T: Comparable&限定T类型必须是遵循了Comparable协议的类型
enum MyError:ErrorType{
throws/rethrows:
正则表达式
路漫漫其修远兮,吾将上下而求索.&| | |(QQ群:)
青年人品牌推荐:
热门关键字:
[] [] []
此栏目下没有推荐文章
推荐必看:· ·
 本站真诚欢迎各类网站与我们合作交换链接! QQ: 要求PR&=4,教育、培训、计算机、电脑、IT等网站优先考虑。php要学到什么程度 给PHP开发者的编程指南 第一部分降低复杂程度-PHP教程
当前位置:&>&&>& &
给PHP开发者的编程指南 第一部分降低复杂程度
php要学到什么程度 给PHP开发者的编程指南 第一部分降低复杂程度
| 来源:网络 | 关键字:
PHP 是一门自由度很高的编程语言。它是动态语言,对程序员有很大的宽容度。作为 PHP 程序员,要想让你的代码更有效,需要了解不少的规范。很多年来,我读过很多编程方面的书籍,与很多资深程序员也讨论过代
PHP 是一门自由度很高的编程语言。它是动态语言,对程序员有很大的宽容度。作为 PHP 程序员,要想让你的代码更有效,需要了解不少的规范。很多年来,我读过很多编程方面的书籍,与很多资深程序员也讨论过代码风格的问题。具体哪条规则来自哪本书或者哪个人,我肯定不会都记得,但是本文(以及接下来的另一篇文章) 表达了我对于如何写出更好的代码的观点:能经得起考验的代码,通常是非常易读和易懂的。这样的代码,别人可以更轻松的查找问题,也可以更简单的复用代码。降低函数体的复杂度在方法或者函数体里,尽可能的降低复杂性。相对低一些的复杂性,可以便于别人阅读代码。另外,这样做也可以减少代码出问题的可能性,更易修改,有问题也更易修复。在函数里减少括号数量尽可能少的使用 if, elseif, else 和 switch 这些语句。它们会增加更多的括号。这会让代码更难懂、更难测试一些(因为每个括号都需要有测试用例覆盖到)。总是有办法来避免这个问题的。代理决策 ("命令,不用去查询(Tell, don't ask)")有的时候 if 语句可以移到另一个对象里,这样会更清晰些。例如: if($a-&somethingIsTrue()) {
$a-&doSomething(); }可以改成: $a-&doSomething();这里,具体的判断由 $a 对象的 doSomething() 方法去做了。我们不需要再为此做更多的考虑,只需要安全的调用 doSomething() 即可。这种方式优雅的遵循了命令,不要去查询原则。我建议你深入了解一下这个原则,当你向一个对象查询信息并且根据这些信息做判断的时候都可以适用这条原则。使用map有时可以用 map 语句减少 if, elseif 或 else 的使用,例如:if($type==='json') {
return $jsonDecoder-&decode($body);}elseif($type==='xml') {
return $xmlDecoder-&decode($body);}else{
throw new \LogicException(
'Type "'.$type.'" is not supported'
);}可以精简为:$decoders= ...;// a map of type (string) to corresponding Decoder objects if(!isset($decoders[$type])) {
thrownew\LogicException(
'Type "'.$type.'" is not supported'
);}这样使用 map 的方式也让你的代码遵循扩展开放,关闭修改的原则。强制类型很多 if 语句可以通过更严格的使用类型来避免,例如:if($a instanceof A) {
// happy path
return $a-&someInformation();}elseif($a=== null) {
// alternative path
return 'default information';}可以通过强制 $a 使用 A 类型来简化:return $a-&someInformation();当然,我们可以通过其他方式来支持 "null" 的情况。这个在后面的文章会提到。Return early很多时候,函数里的一个分支并非真正的分支,而是前置或者后置的一些条件,就像这样:// 前置条件if(!$a instanceof A) {
throw new \InvalidArgumentException(...);} // happy pathreturn $a-&someInformation();这里 if 语句并不是函数执行的一个分支,它只是对一个前置条件的检查。有时我们可以让 PHP 自身来完成前置条件的检查(例如使用恰当的类型提示)。不过,PHP 也没法完成所有前置条件的检查,所以还是需要在代码里保留一些。为了降低复杂度,我们需要在提前知道代码会出错时、输入错误时、已经知道结果时尽早返回。尽早返回的效果就是后面的代码没必要像之前那样缩进了:// check preconditionif(...) {
thrownew...();} // return earlyif(...) {
return...;} // happy path... return...;像上面这个模板这样,代码会变动更易读和易懂。创建小的逻辑单元如果函数体过长,就很难理解这个函数到底在干什么。跟踪变量的使用、变量类型、变量声明周期、调用的辅助函数等等,这些都会消耗很多脑细胞。如果函数比较小,对于理解函数功能很有帮助(例如,函数只是接受一些输入,做一些处理,再返回结果)。使用辅助函数在使用之前的原则减少括号之后,你还可以通过把函数拆分成更小的逻辑单元做到让函数更清晰。你可以把实现一个子任务的代码行看做一组代码,这些代码组直接用空行来分隔。然后考虑如何把它们拆分成辅助方法(即重构中的提炼方法)。辅助方法一般是 private 的方法,只会被所属的特定类的对象调用。通常它们不需要访问实例的变量,这种情况需要定义为 static 的方法。在我的经验中,private (static)的辅助方法通常会汇总到分离的类中,并且定义成 public (static 或 instance)的方法,至少在测试驱动开发的时候使用一个协作类就是这种情形。减少临时变量长的函数通常需要一些变量来保存中间结果。这些临时变量跟踪起来比较麻烦:你需要记住它们是否已经初始化了,是否还有用,现在的值又是多少等等。上节提到的辅助函数有助于减少临时变量:public function capitalizeAndReverse(array $names) {
$capitalized = array_map('ucfirst', $names);
$capitalizedAndReversed = array_map('strrev', $capitalized);
return $capitalizedAndR}使用辅助方法,我们可以不用临时变量了:public function capitalizeAndReverse(array $names) {
return self::reverse(
self::capitalize($names)
);} private static function reverse(array $names) {
return array_map('strrev', $names);} private static function capitalize(array $names) {
return array_map('ucfirst', $names);}正如你所见,我们把函数变成新函数的组合,这样变得更易懂,也更容易修改。某种方式上,代码还有点符合“扩展开放/修改关闭”,因为我们基本上不需要再修改辅助函数。由于很多算法需要遍历容器,从而得到新的容器或者计算出一个结果,此时把容器本身当做一个“一等公民”并且附加上相关的行为,这样做是很有意义的:classNames{
public function __construct(array $names)
$this-&names = $
public function reverse()
return new self(
array_map('strrev', $names)
public function capitalize()
return new self(
array_map('ucfirst', $names)
}}$result = (newNames([...]))-&capitalize()-&reverse();这样做可以简化函数的组合。虽然减少临时变量通常会带来好的设计,不过上面的例子中.cn也没必要干掉所有的临时变量。有时候临时变量的用处是很清晰的,作用也是一目了然的,就没必要精简。使用简单的类型 追踪变量的当前取值总是很麻烦的,当不清楚变量的类型时尤其如此。而如果一个变量的类型不是固定的,那简直就是噩梦。数组只包含同一种类型的值 使用数组作为可遍历的容器时,不管什么情况都要确保只使用同一种类型的值。这可以降低遍历数组读取数据的循环的复杂度:foreach($collection as $value) {
// 如果指定$value的类型,就不需要做类型检查}你的代码编辑器也会为你提供数组值的类型提示:/** * @param DateTime[] $collection */public function doSomething(array $collection) {
foreach($collection as $value) {
// $value是DateTime类型
}}而如果你不能确定 $value 是 DateTime 类型的话,你就不得不在函数里添加前置判断来检查其类型。beberlei/assert库可以让这个事情简单一些:useAssert\Assertion public function doSomething(array $collection) {
Assertion::allIsInstanceOf($collection, \DateTime::class);
...}如果容器里有内容不是 DateTime 类型,这会抛出一个 InvalidArgumentException 异常。除了强制输入相同类型的值之外,使用断言(assert)也是降低代码复杂度的一种手段,因为你可以不在函数的头部去做类型的检查。简单的返回值类型只要函数的返回值可能有不同的类型,就会极大的增加调用端代码的复杂度:$result= someFunction();if($result=== false) {
...}else if(is_int($result)) {
...}PHP 并不能阻止你返回不同类型的值(或者使用不同类型的参数)。但是这样做只会造成大量的混乱,你的程序里也会到处都充斥着 if 语句。下面是一个经常遇到的返回混合类型的例子:/** * @param int $id * @return User|null */public function findById($id){
...}这个函数会返回 User 对象或者 null,这种做法是有问题的,如果不检查返回值是否合法的 User 对象,我们是不能去调用返回值的方法的。在 PHP 7之前,这样做会造成"Fatal error",然后程序崩溃。下一篇文章我们会考虑 null,告诉你如何去处理它们。可读的表达式我们已经讨论过不少降低函数的整体复杂度的方法。在更细粒度上我们也可以做一些事情来减少代码的复杂度。隐藏复杂的逻辑通常可以把复杂的表达式变成辅助函数。看看下面的代码:if(($a||$b) &&$c) {
...}可以变得更简单一些,像这样:if(somethingIsTheCase($a,$b,$c)) {
...}阅读代码时可以清楚的知道这个判断依赖 $a, $b 和 $c 三个变量,而函数名也可以很好的表达判断条件的内容。使用布尔表达式if 表达式的内容可以转换成布尔表达式。不过 PHP 也没有强制你必须提供 boolean 值:$a=new\DateTime();... if($a) {
...}$a 会自动转换成 boolean 类型。强制类型转换是 bug 的主要来源之一,不过还有一个问题是会对代码的理解带来复杂性,因为这里的类型转换是隐式的。PHP 的隐式转换的替代方案是显式的进行类型转换,例如:if($a instanceof DateTime) {
...}如果你知道比较的是 bool 类型,就可以简化成这样:if($b=== false) {
...}使用 ! 操作符则还可以简化:if(!$b) {
...}不要 Yoda 风格的表达式Yoda 风格的表达式就像这样:if('hello'===$result) {
...}这种表达式主要是为了避免下面的错误:if($result='hello') {
...}这里 'hello' 会赋值给 $result,然后成为整个表达式的值。'hello' 会自动转换成 bool 类型,这里会转换成 true。于是 if 分支里的代码在这里会总是被执行。使用 Yoda 风格的表达式可以帮你避免这类问题:if('hello'=$result) {
...}我觉得实际情况下不太会有人出现这种错误,除非他还在学习 PHP 的基本语法。而且,Yoda 风格的代码也有不小的代价:可读性。这样的表达式不太易读,也不太容易懂,因为这不符合自然语言的习惯。以上就是本文的全部内容,希望对大家的学习有所帮助。
无相关信息
网友评论仅供其表达个人看法,并不表明网易立场。

我要回帖

更多关于 vc 数组作为入参 的文章

 

随机推荐