Swift类型创建之自定义一个类型详解

小伙伴们,Swift中的Bool类型有着非常重要的语法功能,并支撑起了整个Swift体系中的逻辑判断体系,经过老码的研究和学习, Bool类型本身其实是对基础Boolean类型封装,小伙伴们可能咬着手指头问老码,怎么一会Bool类型,一会Boolean类型,其区别在于,前者是基于枚举的组合类型,而后者则是基本类型,只有两种true和false。

####自定义原型

接下老码根据Bool的思想来创建一个OCBool类型,来让小伙伴们了解一下Swift中到底是怎么玩儿的。

来我们先看一下OCBool的定义。

#####代码示例如下:

代码如下:

enum OCBool{
case ocTrue
case ocFalse
}

#####注意:

代码中第2行和第3行,可以合并到一行写,如苹果官方Blog所写的一样
代码中命名需要注意:OCBool是类型名,所以首字母必须大写,而case中的ocTrue和ocFalse是小类型则需要首字母小写。

####实现默认值

行,我们给了一个漂亮的定义,不过按照传统语言的经验,Bool值默认情况下是假, 所以我们的OCBool也应该如此,我们使用类型扩展技术增加这个默认特性:

代码如下:

extension OCBool{
     init(){
             self =.ocFalse
     }
}

#####注意:

●代码中第1行:extension关键字,非常强大,小伙伴们可以通过此创造出许多好玩的东西,建议各位去Github上看一个名为“Swiftz”的项目,它将扩展用到了极致。

●代码中第3行:self = .ocFalse语法,刚入门的小伙伴们很迷糊,为什么会有奇怪的点语法,因为大牛Chris在Swift中增加了类型智能推断功能,在苹果Blog中,提到了“Context”概念,就是这个意思,因为这行语句是在枚举OCBool中的,其上下文就是OCBool的定义体,编译器当然知道.ocFalse就是OCBool.ocFalse了,所以这里直接点语法,非常整齐。

现在我们可以使用如下方法使用这个Bool类型。

#####代码示例如下:

代码如下:

var result:OCBool = OCBool()
var result1:OCBool = .ocTrue

####支持基本布尔型初始化

正如上述代码所述,我们只能通过类型或者枚举项目赋值,这是组合类型的用法,但是编码的日子里,我们总是希望和true,false直接打交道,也就是说,我们希望这么做,

代码示例如下:

代码如下:

var isSuccess:OCBool = true

如果小伙伴们直接这么用,则会出现如下错误:

代码如下:

/Users/tyrion-OldCoder/Documents/Learning/BoolType/BoolType/main.swift:30:24: Type 'OCBool' does not conform to protocol 'BooleanLiteralConvertible'

编译器咆哮的原因是,我们的类型没有遵从“布尔字面量转换协议”,接下来修正这个问题,

#####代码示例如下:

代码如下:

import Foundation

println("Hello, World!")

enum OCBool{
    case ocTrue
    case ocFalse
}

extension OCBool: BooleanLiteralConvertible{
static func convertFromBooleanLiteral( value: Bool) ->OCBool{
    return value ? ocTrue : ocFalse
    }
}

var isSuccess:OCBool = true

#####注意:

代码中的第11行是重点,我的类型OCBool支持了BooleanLiteralConvertible协议,这个协到底是干什么的呢,小伙伴们在Xcode代码编辑器,按住Command键,然后点击第11行中的BooleanLiteralConvertible协议名,则会进入它的定义,

#####其定义如下:

代码如下:

protocol BooleanLiteralConvertible {
    typealias BooleanLiteralType
    class func convertFromBooleanLiteral(value: BooleanLiteralType) -> Self
}

这个定义中有个类方法convertFromBooleanLiteral,它的参数为BooleanLiteralType类型,也就是我传入的Bool类型, 且返回值为实现这个协议的类型本身,在我们的OCBool类型中,其返回值就是OCBool本身。经过这个定义,我们可以直接对OCBool类型直接进行布尔字面量初始化了。

####支持Bool类型判断

小伙伴们不安分, 肯定想着我怎么用它实现逻辑判断,所以如果你这么写,
#####代码示例如下:

代码如下:

var isSuccess:OCBool = true

if isSuccess {
    println( "老码请你吃火锅!")
}

你永远吃不到老码的火锅,因为这里编译器会咆哮:

代码如下:

/Users/tyrion-OldCoder/Documents/Learning/BoolType/BoolType/main.swift:27:4: Type 'OCBool' does not conform to protocol 'LogicValue'

OCBool现在只能用bool类型初始化,而不能直接返回bool型,小火把们还记得在《老码说编程之白话Swift江湖》中,老码多次提到,妈妈再也不担心我们 if a = 1{}的写法了, 因为等号不支持值返回了, 所以在if判断是后面的条件必须有返回值,OCBool没有,所以编译器哭了。我们解决这个问题。
#####代码示例如下:

代码如下:

import Foundation

println("Hello, World!")

enum OCBool{
    case ocTrue
    case ocFalse
}

extension OCBool: BooleanLiteralConvertible{
static func convertFromBooleanLiteral( value: Bool) ->OCBool{
    return value ? ocTrue : ocFalse
    }
}

extension OCBool: LogicValue{
    func getLogicValue() ->Bool {
        var boolValue: Bool{
        switch self{
        case .ocTrue:
            return true
        case .ocFalse:
            return false
            }
        }
        return boolValue
    }
}

var isSuccess:OCBool = true

if isSuccess {
    println( "老码请你吃火锅!")
}

####运行结果如下:

代码如下:

Hello, World!
老码请你吃火锅!
Program ended with exit code: 0

#####注意:

●如果小伙伴们现在用的是Beta版的Xcode,注意苹果官方Blog中,在代码第17行如果在Xcode Beta4下是错误的,这里的协议是,LogicValue而不是BooleanVue,所以记得看错误提示才是好习惯。

●注意代码第34行,完美支持if判断,且输出结果为“老码请你吃火锅”,老码也是说说而已,请不要当真。

####支持兼容各们各派的类型

小伙伴们,江湖风险,门派众多,老码有自己的OCBool类型,可能嵩山少林有自己的SSBool类型,甚至连郭美美都可能有自己的MMBool类型,所以OCBool必须能够识别这些类型,这些各门各派的类型,只要支持LogicValue协议,就应该可以被识别,看老码怎么做,

#####代码示例如下:

代码如下:

extension OCBool{
    init( _ v: LogicValue )
    {
        if v.getLogicValue(){
            self = .ocTrue
        }
        else{
            self = .ocFalse
        }
    }

}

var mmResult: Bool = true
var ocResult:OCBool = OCBool(mmResult)

if ocResult {
    println( "老码没钱,郭美美请你吃火锅!")
}

#####代码运行结果如下:

代码如下:

Hello, World!
老码没钱,郭美美请你吃火锅!
Program ended with exit code: 0

漂亮!我们的OCBool类型现在支持了所有的逻辑变量初始化。

#####注意:

●代码中第2行:“_”下横杠的用法,这是一个功能强大的小强,在此的目的是屏蔽外部参数名,所以小伙伴们可以直接:var ocResult:OCBool = OCBool(mmResult)而不是:var ocResult:OCBool = OCBool(v: mmResult),小伙伴们惊呆了!这个init函数中本来就没有外部参数名啊,还记得老码在书里说过没,Swift的初始化函数会默认使用内部参数名,作为外部参数名。

####完善OCBool的布尔基因体系:
小伙伴们,bool类型的价值就是在于各种判断,诸如==,!=, &,|,^,!,以及各种组合逻辑运算,我们OCBool也要具备这些功能,否则就会基因缺陷,且看老码如何实现:

代码如下:

extension OCBool: Equatable{
}

//支持等值判断运算符
func ==( left: OCBool, right: OCBool )->Bool{
    switch (left, right){
    case (.ocTrue, .ocTrue):
            return true
    default:
        return false
    }
}
//支持位与运算符
func &( left:OCBool, right: OCBool)->OCBool{

if left{
        return right
    }
    else{
        return false
    }
}
//支持位或运算符
func |( left:OCBool, right: OCBool)->OCBool{

if left{
        return true
    }
    else{
        return right
    }
}

//支持位异或运算符
func ^( left:OCBool, right: OCBool)->OCBool{
    return OCBool( left != right )
}
//支持求反运算符
@prefix func !( a:OCBool )-> OCBool{
    return a ^ true
}
//支持组合求与运算符
func &= (inout left:OCBool, right:OCBool ){
    left = left & right
}

var isHasMoney:OCBool = true
var isHasWife:OCBool = true
var isHasHealty:OCBool = true
var isHasLover:OCBool = true

isHasMoney != isHasHealty
isHasHealty == isHasMoney
isHasWife ^ isHasLover
isHasWife = !isHasLover

if (isHasMoney | isHasHealty) & isHasHealty{
    println( "人生赢家,就像老码一样!")
}else
{
    println("人生最苦的事事,人死了钱没花了,人生最苦的事是,人活着,钱没了!")
}

好了,到这里就到这里了,窗外的雷声叫醒了老码,现在应该去吃饭了,以上老码给大家展示了如果制造一个自己的类型,记得老码的示例是在Xcode6 Beta4下测试的,至于Beta5的改变还没有涉及,小伙伴们要好生练习,以后各种自定类型都是基于这个思想。还有这个章节不是老码的原创,老码认真的阅读了苹果的官方博客,且自己的练习总结,如果小伙伴们费了吃奶的劲还是看不懂,请找度娘谷歌♂♂♂

(0)

相关推荐

  • 深入解析Swift中switch语句对case的数据类型匹配的支持

    Swift可以对switch中不同数据类型的值作匹配判断: var things = Any[]() things.append(0) things.append(0.0) things.append(42) things.append(3.14159) things.append("hello") things.append((3.0, 5.0)) things.append(Movie(name:"Ghostbusters", director:"Iv

  • Swift编程之枚举类型详解

    想必写过程序的童鞋对枚举类型并不陌生吧,使用枚举类型的好处是多多的,在这儿就不做过多的赘述了.Fundation框架和UIKit中的枚举更是数不胜数,枚举可以使你的代码更易阅读并且可以提高可维护性.在Swift语言中的枚举可谓是让人眼前一亮.在Swift中的枚举不仅保留了大部分编程语言中枚举的特性,同时还添加了一些好用而且实用的新特性,在本篇文章中将领略一些Swift中枚举类型的魅力. 有小伙伴会问,不就是枚举么,有什么好说的.在Swift中的枚举怎不然,Swift中的枚举的功能要强大的多,不仅

  • Swift教程之枚举类型详解

    枚举定义了一个常用的具有相关性的一组数据,并在你的代码中以一个安全的方式使用它们. 如果你熟悉C语言,你就会知道,C语言中的枚举指定相关名称为一组整数值.在Swift中枚举更为灵活,不必为枚举的每个成员提供一个值.如果一个值(被称为"原始"的值)被提供给每个枚举成员,则该值可以是一个字符串,一个字符,或者任何整数或浮点类型的值. 另外,枚举成员可以指定任何类型,每个成员都可以存储的不同的相关值,就像其他语言中使用集合或变体.你还可以定义一组通用的相关成员为一个枚举,每一种都有不同的一组

  • Swift教程之基础数据类型详解

    基础类型 虽然Swift是一个为开发iOS和OS X app设计的全新编程语言,但是Swift的很多特性还是跟C和Objective-C相似. Swift也提供了与C和Objective-C类似的基础数据类型,包括整形Int.浮点数Double和Float.布尔类型Bool以及字符串类型String.Swift还提供了两种更强大的基本集合数据类型,Array和Dictionary,更详细的内容可以参考:Collection Types. 跟C语言一样,Swift使用特定的名称来定义和使用变量.同

  • 详解Swift中enum枚举类型的用法

    一.引言 在Objective-C语言中,没有实际上是整型数据,Swift中的枚举则更加灵活,开发者可以不为其分配值类型把枚举作为独立的类型来使用,也可以为其分配值,可以是字符,字符串,整型或者浮点型数据. 二.枚举语法 Swift中enum关键字来进行枚举的创建,使用case来创建每一个枚举值,示例如下: //创建姓氏枚举,和Objective-C不同,Swift枚举不会默认分配值 enum Surname { case 张 case 王 case 李 case 赵 } //创建一个枚举类型的

  • Swift内置的数字类型及基本的转换方法

    虽然编写任何编程语言,需要使用不同的变量来存储各种信息.变量不过是保留的内存位置来存储值.这意味着,当创建一个变量,在内存中会保留一些空间. 可能喜欢像存储字符串,字符,宽字符,整数,浮点数,布尔等各种数据类型的信息.根据一个变量的数据类型,操作系统分配内存,并决定什么可以存储保留在存储器. 内置数据类型 Swift 为程序员提供内置以及用户定义的种类数据类型. 以下是声明变量使用最频繁的基本数据类型的列表: Int 或 UInt - 这是用于整数.更具体地可以使用Int32,Int64来定义3

  • 实例讲解Swift中引用类型的ARC自动引用计数

    一.引言 ARC(自动引用计数)是Objective-C和Swift中用于解决内存管理问题的方案.在学习Objective-C编程时经常会学习到一个关于ARC的例子:在一个公用的图书馆中,每次进入一人就将卡插入,走的时候将自己的卡拔出拿走.图书馆系统会判定只要有卡插入,就将图书馆的灯打开,当所有卡都被取走后,将图书馆的灯关掉.这个例子对应于Objective-C中的对象声明周期管理十分贴切.每当一个对象增加一个引用时,其引用计数会加1,当一个引用被取消时,对象的引用计数减1,当引用计数减为0时,

  • Swift使用Cocoa中的数据类型教程

    作为对 Objective-C 互用性(互操作性)的一部分,Swift提供快捷高效的方式来处理Cocoa数据类型. Swift 会自动将一些 Objective-C 类型转换为 Swift 类型,以及将 Swift 类型转换为 Objective-C 类型.在 Objective-C 和 Swift 中也有一些具有互用性的数据类型.那些可转换的数据类型或者具有互用性的数据类型被称为bridged数据类型.举个例子,在 Swift 中,您可以将一个Array值传递给一个要求为NSArray对象的方

  • 详解Swift中的数据类型类型转换

    一.类型检查与转换 在Objective-C和Java中,任何类型实例都可以通过强转使编译器认为它是另一种类型的实例,这么做其实是将所有的安全检查工作都交给了开发者自己来做.先比之下,Swift中的Optional类型转换就会比较安全与可靠. Swift中使用is关键字来进行类型的检查,其会返回一个布尔值true或者false来表明检查是否成立,示例如下: var str = "HS" if str is String { print(str) } Swift中有向上兼容与向下转换的特

  • Swift类型创建之自定义一个类型详解

    小伙伴们,Swift中的Bool类型有着非常重要的语法功能,并支撑起了整个Swift体系中的逻辑判断体系,经过老码的研究和学习, Bool类型本身其实是对基础Boolean类型封装,小伙伴们可能咬着手指头问老码,怎么一会Bool类型,一会Boolean类型,其区别在于,前者是基于枚举的组合类型,而后者则是基本类型,只有两种true和false. ####自定义原型 接下老码根据Bool的思想来创建一个OCBool类型,来让小伙伴们了解一下Swift中到底是怎么玩儿的. 来我们先看一下OCBool

  • GO语言基本类型String和Slice,Map操作详解

    目录 本文大纲 1.字符串String String常用操作:获取长度和遍历 字符串的strings包 字符串的strconv包: 2.切片Slice 3.集合Map 本文大纲 本文继续学习GO语言基础知识点. 1.字符串String String是Go语言的基本类型,在初始化后不能修改,Go字符串是一串固定长度的字符连接起来的字符序列,当然它也是一个字节的切片(Slice). import ("fmt") func main() { name := "Hello World

  • Android AS创建自定义布局案例详解

    先创建一个title.xml <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" andr

  • Go 类型转化工具库cast函数详解

    目录 1. cast是啥 2. 两种API 3. 源码分析 1. cast是啥 cast 是在Github上开源的工具库,就像他的名字一样,他为我们提供了非常便捷的类型转化的方法. 我们可以通过下面的地址拉取cast库: go get github.com/spf13/cast 2. 两种API cast库中为我们提供了两类常用的API:cast.Toxxx以及cast.ToxxxE(xxx是要转化成的数据类型). cast.ToxxxE在返回转化后数值的同时,也会返回一个error,cast.

  • TypeScript类型级别和值级别示例详解

    目录 对值级别编程类型级别编程区分 类型级编程 挑战是如何工作的 挑战 对值级别编程类型级别编程区分 首先,让我们对值级别编程和类型级别编程进行重要区分. 值级别编程让我们编写将在生产中运行的代码即运行期,并为我们的用户提供有用的东西. 类型级别编程帮助我们确保代码在发布之前即编译期不包含错误,在运行期会被完全删除 JavaScript没有类型,所以所有JavaScript都是值级别的代码: // A simple Javascript function: function sum(a, b)

  • 在django中自定义字段Field详解

    Django的Field类中方法有: to_python() # 把数据库数据转成python数据 from_db_value() # 把数据库数据转成python数据 get_pre_value() # 把python数据压缩准备存入数据库 get_db_pre_value() # 把压缩好的数据转成数据库查询集 get_prep_lookup() # 指定过滤的条件 value_to_string() # 数据序列化 如果创建的Field比字符串,日期,整数等更复杂的数据结构,可能需要重写t

  • Android代码检查规则Lint的自定义与应用详解

    目录 前言: 什么是Lint 自定义Lint流程: 1. 新创建module,Module类型选择Java or Kotlin Library, 暂时命名lint_tools 2. 在build.gradle中引入lint的依赖 3. 本地创建个资源id命名检查规则,用来规范项目中的id统一命名 4. 实现IssueRegistry并添加对应的自定义Issue: 5. 在module(lint_tools)中对应的build.gradle中配置如下信息: 6. 在需要进行lint检查的modul

  • SpringBoot应用自定义logback日志详解

    目录 概述 logback配置详解 配置内容概念介绍 配置介绍 SpringBoot中自定义logback 多环境输出日志文件 读取配置文件配置 概述 默认情况下,SpringBoot内部使用logback作为系统日志实现的框架,将日志输出到控制台,不会写到日志文件.如果在application.properties或application.yml配置,这样只能配置简单的场景,保存路径.日志格式等.复杂的场景(区分 info 和 error 的日志.每天产生一个日志文件等)满足不了,只能自定义配

  • 基于Spring-AOP实现自定义分片工具详解

    目录 1.背景 2.Spring-AOP 3.功能实现 3.1 MethodPartAndRetryer 3.2 RetryUtil 3.3 RetryAspectAop 4.功能使用 4.1 配置文件 4.2 代码示例 5.小结 1.背景 随着数据量的增长,发现系统在与其他系统交互时,批量接口会出现超时现象,发现原批量接口在实现时,没有做分片处理,当数据过大时或超过其他系统阈值时,就会出现错误.由于与其他系统交互比较多,一个一个接口去做分片优化,改动量较大,所以考虑通过AOP解决此问题. 2.

  • mysql创建删除表的实例详解

    表的创建命令需要: 表的名称 字段名称 定义每个字段(类型.长度等) 语法 下面是通用的SQL语法用来创建MySQL表: CREATE TABLE table_name (column_name column_type); 现在,我们将在 test 数据库中创建以下表. create table tutorials_tbl( tutorial_id INT NOT NULL AUTO_INCREMENT, tutorial_title VARCHAR(100) NOT NULL, tuto

随机推荐