那些通常被其它语言认为是基本或初级的数据型类型(Data types)——比如表示数字、字符和字符串——实际上就是命名型类型,Swift 标准库是使用结构体定义和实现它们的。因为它们是命名型类型,因此你可以按照“扩展和扩展声明”章节里讨论的那样,声明一个扩展来增加它们的行为以适应你程序的需求。
复合型类型是没有名字的类型,它由 Swift 本身定义。Swift 存在两种复合型类型:函数类型和元组类型。一个复合型类型可以包含命名型类型和其它复合型类型。例如,元组类型(Int, (Int, Int))包含两个元素:第一个是命名型类型Int,第二个是另一个复合型类型(Int, Int).
本节讨论 Swift 语言本身定义的类型,并描述 Swift 中的类型推断行为。
类型的语法: type → array-type | function-type | type-identifier | tuple-type | optional-type | implicitly-unwrapped-optional-type | protocol-composition-type | metatype-type
作为一个开发者,有一个学习的氛围跟一个交流圈子特别重要,这是一个我的iOS开发交流群:130 595 548,不管你是小白还是大牛都欢迎入驻 ,让我们一起进步,共同发展!(群内会免费提供一些群主收藏的免费学习书籍资料以及整理好的几百道面试题和答案文档!)
1. let someTuple:(Double, Double) = (3.14159, 2.71828)
2. func someFunction(a: Int){ /* ... */ }
在第一个例子中,表达式someTuple的类型被指定为(Double, Double)。在第二个例子中,函数someFunction的参数a的类型被指定为Int。
类型注解可以在类型之前包含一个类型特性(type attributes)的可选列表。
类型注解的语法: type-annotation → :attributes[opt] type
1. typealias Point = (Int, Int)
2. let origin: Point = (0, 0)
情况二,类型标识符使用dot(.)语法来表示在其它模块(modules)或其它类型嵌套内声明的命名型类型。例如,下面例子中的类型标识符引用在ExampleModule模块中声明的命名型类型MyType:
1. var someValue: ExampleModule.MyType
类型标识符的语法: type-identifier → type-name generic-argument-clause[opt] | type-name generic-argument-clause[opt].type-identifier type-name → identifier
元组类型语法: tuple → (tuple-type-body[opt]) tuple-type-body → tuple-type-element-list ...[opt] tuple-type-element-list → tuple-type-element | tuple-type-element, tuple-type-element-list tuple-type-element → attributes[opt] inout [opt] type | inout [opt] element-name type-annotation element-name → identifier
1. func simpleAssert(condition: @auto_closure () -> Bool, message: String){
2. if !condition(){
3. println(message)
4. }
5. }
6. let testNumber = 5
7. simpleAssert(testNumber % 2 == 0, "testNumber isn't an even number.")
8. // prints "testNumber isn't an even number."
函数类型可以拥有一个可变长参数作为参数类型中的最后一个参数。从语法角度上讲,可变长参数由一个基础类型名字和...组成,如Int...。可变长参数被认为是一个包含了基础类型元素的数组。即Int...就是Int[]。关于使用可变长参数的例子,见章节“可变长参数”。
为了指定一个in-out参数,可以在参数类型前加inout前缀。但是你不可以对可变长参数或返回值类型使用inout。关于In-Out参数的讨论见章节In-Out参数部分。
柯里化函数(curried function)的类型相当于一个嵌套函数类型。例如,下面的柯里化函数addTwoNumber()()的类型是Int -> Int -> Int:
1. func addTwoNumbers(a: Int)(b: Int) -> Int{
2. return a + b
3. }
4. addTwoNumbers(4)(5) // returns 9
柯里化函数的函数类型从右向左组成一组。例如,函数类型Int -> Int -> Int可以被理解为Int -> (Int -> Int)——也就是说,一个函数传入一个Int然后输出作为另一个函数的输入,然后又返回一个Int。例如,你可以使用如下嵌套函数来重写柯里化函数addTwoNumbers()():
1. func addTwoNumbers(a: Int) -> (Int -> Int){
2. func addTheSecondNumber(b: Int) -> Int{
3. return a + b
4. }
5. return addTheSecondNumber
6. }
7. addTwoNumbers(4)(5) // Returns 9
函数类型的语法: function-type → type -> type
1. let someArray: String[] = ["Alex", "Brian", "Dave"]
2. let someArray: Array<String> = ["Alex", "Brian", "Dave"]
上面两种情况下,常量someArray都被声明为字符串数组。数组的元素也可以通过[]获取访问:someArray[0]是指第0个元素“Alex”。
上面的例子同时显示,你可以使用[]作为初始值构造数组,空的[]则用来来构造指定类型的空数组。
1. var emptyArray: Double[] = []
你也可以使用链接起来的多个[]集合来构造多维数组。例如,下例使用三个[]集合来构造三维整型数组:
1. var array3D: Int[][][] = [[[1, 2], [3, 4]], [[5, 6], [7, 8]]]
访问一个多维数组的元素时,最左边的下标指向最外层数组的相应位置元素。接下来往右的下标指向第一层嵌入的相应位置元素,依次类推。这就意味着,在上面的例子中,array3D[0]是指[[1, 2], [3, 4]],array3D[0][1]是指[3, 4],array3D[0][1][1]则是指值4。
关于Swift标准库中Array类型的细节讨论,见章节Arrays。
数组类型的语法: array-type → type[ ] | array-type[ ]
1. var optionalInteger: Int?
2. var optionalInteger: Optional<Int>
在上述两种情况下,变量optionalInteger都被声明为可选整型类型。注意在类型和?之间没有空格。
类型Optional<T>是一个枚举,有两种形式,None和Some(T),又来代表可能出现或可能不出现的值。任意类型都可以被显式的声明(或隐式的转换)为可选类型。当声明一个可选类型时,确保使用括号给?提供合适的作用范围。比如说,声明一个整型的可选数组,应写作(Int[])?,写成Int[]?的话则会出错。
如果你在声明或定义可选变量或特性的时候没有提供初始值,它的值则会自动赋成缺省值nil。
可选符合LogicValue协议,因此可以出现在布尔值环境下。此时,如果一个可选类型T?实例包含有类型为T的值(也就是说值为Optional.Some(T)),那么此可选类型就为true,否则为false。
如果一个可选类型的实例包含一个值,那么你就可以使用后缀操作符!来获取该值,正如下面描述的:
1. optionalInteger = 42
2. optionalInteger! // 42
使用!操作符获取值为nil的可选项会导致运行错误(runtime error)。
你也可以使用可选链和可选绑定来选择性的执行可选表达式上的操作。如果值为nil,不会执行任何操作因此也就没有运行错误产生。
更多细节以及更多如何使用可选类型的例子,见章节“可选”。
可选类型语法: optional-type → type?
1. var implicitlyUnwrappedString: String!
2. var implicitlyUnwrappedString: ImplicitlyUnwrappedOptional<String>
上述两种情况下,变量implicitlyUnwrappedString被声明为一个隐式解析可选类型的字符串。注意类型与!之间没有空格。
你可以在使用可选的地方同样使用隐式解析可选。比如,你可以将隐式解析可选的值赋给变量、常量和可选特性,反之亦然。
有了可选,你在声明隐式解析可选变量或特性的时候就不用指定初始值,因为它有缺省值nil。
由于隐式解析可选的值会在使用时自动解析,所以没必要使用操作符!来解析它。也就是说,如果你使用值为nil的隐式解析可选,就会导致运行错误。
使用可选链会选择性的执行隐式解析可选表达式上的某一个操作。如果值为nil,就不会执行任何操作,因此也不会产生运行错误。
关于隐式解析可选的更多细节,见章节“隐式解析可选”。
隐式解析可选的语法: implicitly-unwrapped-optional-type → type!
协议合成类型的语法: protocol-composition-type → protocol <protocol-identifier-list[opt]> protocol-identifier-list → protocol-identifier | protocol-identifier, protocol-identifier-list protocol-identifier → type-identifier
1. class SomeBaseClass {
2. class func printClassName() {
3. println("SomeBaseClass")
4. }
5. }
6. class SomeSubClass: SomeBaseClass {
7. override class func printClassName() {
8. println("SomeSubClass")
9. }
10. }
11. let someInstance: SomeBaseClass = SomeSubClass()
12. // someInstance is of type SomeBaseClass at compile time, but
13. // someInstance is of type SomeSubClass at runtime
14. someInstance.dynamicType.printClassName()
15. // prints "SomeSubClass
元类型的语法: metatype-type → type.Type | type.Protocol
类型继承子句的语法: type-inheritance-clause → :type-inheritance-list type-inheritance-list → type-identifier | type-identifier, type-inheritance-list
1. let e = 2.71828 // The type of e is inferred to be Double.
2. let eFloat: Float = 2.71828 // The type of eFloat is Float.
Swift中的类型推断在单独的表达式或语句水平上进行。这意味着所有用于推断类型的信息必须可以从表达式或其某个子表达式的类型检查中获取。
我可以得到Infinity和NaNn=9.0/0#=>Infinityn.class#=>Floatm=0/0.0#=>NaNm.class#=>Float但是当我想直接访问Infinity或NaN时:Infinity#=>uninitializedconstantInfinity(NameError)NaN#=>uninitializedconstantNaN(NameError)什么是Infinity和NaN?它们是对象、关键字还是其他东西? 最佳答案 您看到打印为Infinity和NaN的只是Float类的两个特殊实例的字符串
我不确定传递给方法的对象的类型是否正确。我可能会将一个字符串传递给一个只能处理整数的函数。某种运行时保证怎么样?我看不到比以下更好的选择:defsomeFixNumMangler(input)raise"wrongtype:integerrequired"unlessinput.class==FixNumother_stuffend有更好的选择吗? 最佳答案 使用Kernel#Integer在使用之前转换输入的方法。当无法以任何合理的方式将输入转换为整数时,它将引发ArgumentError。defmy_method(number)
有时我需要处理键/值数据。我不喜欢使用数组,因为它们在大小上没有限制(很容易不小心添加超过2个项目,而且您最终需要稍后验证大小)。此外,0和1的索引变成了魔数(MagicNumber),并且在传达含义方面做得很差(“当我说0时,我的意思是head...”)。散列也不合适,因为可能会不小心添加额外的条目。我写了下面的类来解决这个问题:classPairattr_accessor:head,:taildefinitialize(h,t)@head,@tail=h,tendend它工作得很好并且解决了问题,但我很想知道:Ruby标准库是否已经带有这样一个类? 最佳
我正在尝试解析一个CSV文件并使用SQL命令自动为其创建一个表。CSV中的第一行给出了列标题。但我需要推断每个列的类型。Ruby中是否有任何函数可以找到每个字段中内容的类型。例如,CSV行:"12012","Test","1233.22","12:21:22","10/10/2009"应该产生像这样的类型['integer','string','float','time','date']谢谢! 最佳答案 require'time'defto_something(str)if(num=Integer(str)rescueFloat(s
我正在玩HTML5视频并且在ERB中有以下片段:mp4视频从在我的开发环境中运行的服务器很好地流式传输到chrome。然而firefox显示带有海报图像的视频播放器,但带有一个大X。问题似乎是mongrel不确定ogv扩展的mime类型,并且只返回text/plain,如curl所示:$curl-Ihttp://0.0.0.0:3000/pr6.ogvHTTP/1.1200OKConnection:closeDate:Mon,19Apr201012:33:50GMTLast-Modified:Sun,18Apr201012:46:07GMTContent-Type:text/plain
我想使用PostgreSQL中的point类型。我已经完成了:railsgmodelTestpoint:point最终的迁移是:classCreateTests当我运行时:rakedb:migrate结果是:==CreateTests:migrating====================================================--create_table(:tests)rakeaborted!Anerrorhasoccurred,thisandalllatermigrationscanceled:undefinedmethod`point'for#/hom
希望我没有误解“ducktyping”的含义,但从我读到的内容来看,这意味着我应该根据对象如何响应方法而不是它是什么类型/类来编写代码。代码如下:defconvert_hash(hash)ifhash.keys.all?{|k|k.is_a?(Integer)}returnhashelsifhash.keys.all?{|k|k.is_a?(Property)}new_hash={}hash.each_pair{|k,v|new_hash[k.id]=v}returnnew_hashelseraise"CustomattributekeysshouldbeID'sorPropertyo
我试图像这样在我的测试用例中执行获取:request.env['CONTENT_TYPE']='application/json'get:index,:application_name=>"Heka"虽然,它失败了:ActionView::MissingTemplate:Missingtemplatealarm_events/indexwith{:handlers=>[:builder,:haml,:erb,:rjs,:rhtml,:rxml],:locale=>[:en,:en],:formats=>[:html]尽管在我的Controller中我有:respond_to:html,
我有代码:classScenedefinitialize(number)@number=numberendattr_reader:numberendscenes=[Scene.new("one"),Scene.new("one"),Scene.new("two"),Scene.new("one")]groups=scenes.inject({})do|new_hash,scene|new_hash[scene.number]=[]ifnew_hash[scene.number].nil?new_hash[scene.number]当我启动它时出现错误:freq.rb:11:in`[]'
我正在使用File.open即时创建一个.csv文件。但我需要做的是将文件的Content-Type设置为binary/octet-stream,这样浏览器会自动下载它,而不是仅仅显示它的内容在浏览器中。文件本身在本地创建,然后上传到AmazonS3。 最佳答案 简答无法指定Content-Type创建文件时文件系统中的值。事实上,这可能不是实现目标的最佳方式。为了建议浏览器下载文件而不是显示文件,您可以留下Content-Type:text/csv并添加标题Content-Disposition:attachment或Conten