ResutBuilder 学习笔记二:增加新的输入数据类型
我们在前面的博客中创建了一个非常简单的结果构建器ConcatBuilder
,用于连接多个字符串。 ConcatBuilder
虽然非常简单,但已经展现出一些令人兴奋的特征,代码简洁,清晰,但是还远远不够。这篇博文讨论如何为ConcatBuilder
增加新的数据类型。
增加整数输入类型
假设我们需要使用ConcatBuilder
将一些整数进行连接,并且按下述方式输入整数:
swift">@ConcatBuilder var str:String {
"春眠不觉晓"
"处处闻啼鸟"
1
2
3
}
很遗憾,编译器会报错,因为ConcatBuilder
现在不理解整数。我们需要在ConcatBuilder
中像下面这样实现buildExpression
函数。
swift"> static func buildExpression (_ component: Int) -> String {
return "\(component)"
}
实现上述函数后,所有的组件输入首先要通过该函数进行转换,因而原先的字符串组件的输入会出错。修正这个错误很容易,我们只需要像下面这样增加一个新buildExpression
函数即可:
swift">static func buildExpression (_ component: String) -> String {
return component
}
有了这两个函数,再次运行,这次结果正确。
swift"> @ConcatBuilder var str:String {
"春眠不觉晓"
"处处闻啼鸟"
1
2
3
}
print( str )
//春眠不觉晓处处闻啼鸟123
增加自定义输入类型
从上面我们可以看到,在结果构建器中,增加对整数类型的支持非常容易。类似地,增加对其他Swift数据类型的支持也不难,只需要重载buildExpression
函数即可。你也许觉得太容易了,不以为然。实际上,buildExpression
函数强大之处是可以非常容易增加自定义的输入数据类型,从而创建特定于场景的简单清晰表达。
比如在字符串拼接时经常会将一组连续的符号*
拼接,我们什么都不做,像下面这样就可以:
swift">@ConcatBuilder var str:String {
"*****"
"春眠不觉晓"
"处处闻啼鸟"
"*****"
}
但是,对于这个特定的场景,一组连续的*
,上述表达比较原始,既不简洁,也容易出错。 如果能够像下面这样,既简洁、清晰,又不容易出错,不是更好吗?
swift"> @ConcatBuilder var str:String {
Star(length:5)
"春眠不觉晓"
"处处闻啼鸟"
Star(length:5)
}
这次,我们要做的就增加新的数据类型Star
,然后在ConcatBuilder
中增加相应的buildExpression
函数,以增加对Star的支持,后者和增加对整数的支持一样的简单。
首先增加数据类型Star
,如下
swift">struct Star {
let length:Int
func getString()->String
{
return Array(repeating:"*",count:length).joined()
}
}
其次,在ConcatBuilder
中增加如下buildExpression
函数:
swift"> static func buildExpression (_ component: Star) -> String {
return component.getString()
}
看看最后的结果:
swift"> @ConcatBuilder var str:String {
Star(length:5)
"春眠不觉晓"
"处处闻啼鸟"
Star(length:5)
}
print( str )
//*****春眠不觉晓处处闻啼鸟*****
是不是很酷呢?
小结
本文介绍了如何使用buildExpression
函数在结果构建器中增加对新的输入数据类型的支持, 特别是对自定义数据类型的支持。后者非常重要,它是实现一个DSL(领域特定语言)的基础。