我可以在Swift中模拟traits / mixins吗?

时间:2014-06-08 15:28:27

标签: swift mixins traits

斯威夫特是否有一种混合特征的方式,斯卡拉?关于使用扩展来向现有类添加协议的Swift小册子的部分非常接近。但是,由于协议不能包含实现,因此无法将代码混合到类中。还有另一种方式吗?

5 个答案:

答案 0 :(得分:8)

从Swift 2.0开始,是的!

Providing Default Implementations

  

您可以使用协议扩展来提供默认实现   该协议的任何方法或财产要求。如果一个   符合类型提供了自己实现的所需方法   或属性,将使用该实现而不是该实现   由扩展提供。

答案 1 :(得分:7)

模拟混合的一种方法是使用通用函数来提供实现

例如使用这些协议

protocol Named {
    func GetName() -> String
}

protocol NamedExtension {
    func GetLowercaseName() -> String
    func GetUppercaseName() -> String
}

我想要一些课程来实施GetName()并使用混音,这样他们也可以获得GetLowercaseName()GetUppercaseName()而不实施它们

这是免费功能

NamedExtension的实现
func GetLowercaseNameImpl<T:Named>(obj:T) -> String {
    return obj.GetName().lowercaseString
}

func GetUppercaseNameImpl<T:Named>(obj:T) -> String {
    return obj.GetName().uppercaseString
}

Int

上的扩展程序
extension Int : Named {
    func GetName() -> String {
        return "Int"
    }
}

extension Int : NamedExtension {
    // use provided implementation
    func GetLowercaseName() -> String {
        return GetLowercaseNameImpl(self)
    }
    func GetUppercaseName() -> String {
        return GetUppercaseNameImpl(self)
    }
}

我可以使用

1.GetName() // result Int
1.GetUppercaseName() // result "INT"
1.GetLowercaseName() // result "int"

答案 2 :(得分:6)

我不了解Scala,但是根据您告诉我的内容,可以同时创建protocolextension扩展类型以添加​​&#34伪 - 性状&#34;行为。

例如:

protocol IsGreaterThan
{
    func isGreaterThan(other:Int) -> Bool
    func isNotGreaterThan(other:Int) -> Bool
}

extension Int : IsGreaterThan
{
    func isGreaterThan(other:Int) -> Bool
    {
        return self > other
    }

    func isNotGreaterThan(other:Int) -> Bool
    {
        return !isGreaterThan(other)
    }
}

真正的腿筋是现在如何限制泛型。我认为在即将到来的Swift版本中它们会有很大的改进。

答案 3 :(得分:2)

与Bryan Chen的回答类似:

import Foundation

protocol Named {
    var name : String { get }
}

protocol NamedExtension : Named { // NB extends Named
    var lowercaseName : String { get }
    var uppercaseName : String { get }
}

struct NamedExtensionDefault { // Put defaults inside a struct to keep name spaces seperate
    static func lowercaseName(named : NamedExtension) -> String {
        return (named.name as NSString).lowercaseString
    }
    static func uppercaseName(named : NamedExtension) -> String {
        return (named.name as NSString).uppercaseString
    }
}

extension Int : NamedExtension {
    var name : String {
    return "Int"
    }
    // Use default implementation
    var lowercaseName : String {
    return NamedExtensionDefault.lowercaseName(self)
    }
    var uppercaseName : String {
    return NamedExtensionDefault.uppercaseName(self)
    }
}

1.name // result Int
1.uppercaseName // result "INT"
1.lowercaseName // result "int"

与Bryan的答案的主要区别在于我没有使用泛型,因为我使NamedExtension扩展Named,因此默认实现可以访问name

答案 4 :(得分:1)

这是我(尚未经过广泛测试)的方式,我认为Swala 2.1.1中的Scala特性,Playgrounds-ready,两个版本:

不太灵活:

protocol BigBadProtocol {
    func madFunc() -> String;
    // func otherFunc();
    // Maybe a couple more functions here.
}

protocol BlueMadFuncUser: BigBadProtocol {}

extension BlueMadFuncUser {
    func madFunc() -> String {
        return "Blue"
    }
}

protocol RedMadFuncUser: BigBadProtocol {}

extension RedMadFuncUser {
    func madFunc() -> String {
        return "Red"
    }
}

class ClearClass: BigBadProtocol {
    func madFunc() -> String {
        return "Clear"
    }
}

class BlueClass: BlueMadFuncUser {}

class RedClass: RedMadFuncUser {}

更灵活:

protocol BigBadProtocol {
    func madFunc() -> String;
    // func otherFunc();
    // Maybe a couple more functions here.
}

protocol BlueMadFuncUser {}

extension BigBadProtocol where Self: BlueMadFuncUser {
    func madFunc() -> String {
        return "Blue"
    }
}

protocol RedMadFuncUser {}

extension BigBadProtocol where Self: RedMadFuncUser {
    func madFunc() -> String {
        return "Red"
    }
}

class ClearClass: BigBadProtocol {
    func madFunc() -> String {
        return "Clear"
    }
}

class BlueClass: BigBadProtocol, BlueMadFuncUser {}

class RedClass: BigBadProtocol, RedMadFuncUser {}

完整性检查:

var classes: [BigBadProtocol] = [ClearClass(), BlueClass(), RedClass()]

// Prints "Clear, Blue, Red\n"
print((classes.map { $0.madFunc() }).joinWithSeparator(", "))

// Print another way for Playgrounds, which appears to bug out on the lines above
var s = ""
for klass in classes {
    s += klass.madFunc() + " "
}
print(s)

BlueMadFuncUser和RedMadFuncUser是两个特征的版本。我的术语可能已关闭,但您可以随意创建这样的第二个特征,并在您的课程中混合搭配。

使用基于继承的方法重用这样的逻辑会更具挑战性或更好的做法。

在Hack for PHP中发现它非常有用之后我最终想要这个模式,从我可以告诉的特性与Scala非常相似:https://docs.hhvm.com/hack/other-features/trait-and-interface-requirements