当前位置 : 主页 > 手机开发 > 其它 >

Swift:转换集合,并创建自定义可转换协议

来源:互联网 收集:自由互联 发布时间:2021-06-11
考虑这个Person类,它只是实现StringLiteralConvertible并将字符串文字分配给name: class Person : StringLiteralConvertible { var name : String? typealias StringLiteralType = String required init(stringLiteral value: StringLi
考虑这个Person类,它只是实现StringLiteralConvertible并将字符串文字分配给name:

class Person : StringLiteralConvertible {
    var name : String?

    typealias StringLiteralType = String

    required init(stringLiteral value: StringLiteralType) {
        println("stringLiteral \(value)")
        name = value
    }

    typealias ExtendedGraphemeClusterLiteralType = String

    required init(extendedGraphemeClusterLiteral value: ExtendedGraphemeClusterLiteralType) {
        println("extendedGraphemeClusterLiteral \(value)")
        name = value
    }

    typealias UnicodeScalarLiteralType = Character

    required init(unicodeScalarLiteral value: UnicodeScalarLiteralType) {
        println("unicodeScalarLiteral \(value)")
        name = "\(value)"
    }
}

这允许我使用字符串创建Person实例:

let aaron : Person = "Aaron"

我甚至可以从一个字符串数组中转换一个Persons数组:

let names = ["John", "Jane"] as [Person]

但是这仅适用于字符串文字.如果我使用字符串变量,它会失败:

let aaronString = "Aaron"
let aaron : Person = aaronString
// Error: 'NSString' is not a subtype of 'Person'

同样,尝试强制转换非文字字符串数组也会失败:

let nameStrings = ["John", "Jane"]
let people : [Person] = nameStrings
// Error: 'String' is not identical to 'Person'

我有三个问题:

>我可以实现另一个协议来将非文字字符串转换为Person吗?我想这样做,所以我可以转换整个集合来转换对象.
>如果不是#1,那么映射初始化程序是自己执行转换的最佳方法吗?

let nameStrings = ["John", "Jane"]
let people = nameStrings.map{Person(name: $0)}

>如果是#1,是否有类似的方法我可以用来指定一种方法来转换两个在层次结构中无关的对象?也就是说,如果没有初始化程序,我可以解决此错误吗?

let rikerPerson : Person = "Riker"
let rikerEmployee = rikerPerson as Employee
// Error: 'Person' is not convertible to 'Employee'
>你所描述的“铸造”并不是真正的铸造(例如,s =“fred”; ns = s,如NSString,或者用C铸造).

let names = ["John", "Jane"] as [Person]

只是另一种写作方式:

let names: [Person] = ["John", "Jane"]

也就是说,一种告诉Swift使用StringLiteralConvertible的许多可能版本中的哪一个的方法(而不是String的默认版本).

换句话说 – 你正在履行与此片段中的as类似的函数,消除两个仅由返回类型不同的重载函数的歧义:

func f() -> String { return "foo" }
func f() -> Int { return 42 }

let i = f() as Int    // i will be 42
let s = f() as String // s will be “foo"

这里没有“转换” – 就像用来消除哪些f Swift调用一样.与选择init(stringLiteral :)的方法相同.
>绝对(但只有在地图和{}之间放置一个空格;-).

如果你担心将它全部转换为数组的浪费只是为了做一些其他事情,请查看lazy(a).map>不.在测试版中,曾经有过__conversion() – >您可以实现的T方法在您自己的类上执行“强制转换” – 或者更重要的是,允许您将Person类传递给一个带有Employee参数并隐式转换的函数.但那消失了.一般来说,这种隐式转换与Swift的风格是对立的,除了在极少数情况下(Obj-C和C interop,以及选择性中的隐式包装,是主要的).您必须为Employee编写一个init,它接受Person(或Person符合的某个类或协议),然后调用它.

网友评论