我有很多dto在我的应用程序中记录一些字段。该字段不应该被记录,因为数据比较敏感。模型是这样的:
typealias HiddenFieldType = String
struct DTO1 {
var field1_1: String
var fieldToHide: HiddenFieldType
var field1_2: String
var field1_3: String
}
struct DTO2 {
var field2_1: String
var field2_2: String
var fieldToHide: HiddenFieldType
var field2_3: String
}
输出数据的代码是这样的(实际上它是真正的应用程序中的os_log
):
func test() {
let dto1 = DTO1(field1_1: "1_1", fieldToHide: "super-secret-1", field1_2: "1_2", field1_3: "1_3")
let dto2 = DTO2(field2_1: "2_1", field2_2: "2_2", fieldToHide: "super-secret-2", field2_3: "2_3")
print("Test1: dto1=(dto1) dto2=(dto2)")
}
方法# 1
这个字段似乎可以在DTO1中隐藏,代码如下:
extension String.StringInterpolation {
mutating func appendInterpolation(_ value: DTO1) {
appendInterpolation("field1_1: (value.field1_1), fieldToHide: 🤷♀️, field1_2: (value.field1_2), field1_3: (value.field1_3)")
}
}
然而,该解决方案既不可伸缩也不可维护:
- 应该为每个DTO添加相同的扩展名
- 每个字段都应该包含在
appendInterpolation
中-大量的样板 - 如果一个新的字段被添加到一些DTO,我们可能会忘记更新
appendInterpolation
等
方法# 2
我试图为HiddenFieldType
添加插值(假设它是一种类型,就像DTO1
…):
extension String.StringInterpolation {
mutating func appendInterpolation(_ value: HiddenFieldType) {
appendInterpolation("🤷♀️")
}
}
但是这个解决方案根本不起作用:
- 编译器说"函数调用导致无限递归">
- 它实际上会导致无限递归
- 将
appendInterpolation
更改为appendLiteral
时,没有递归,但有"super-secret-1">
方法# 3
我尝试重写DefaultStringInterpolation
,符合ExpressibleByStringLiteral
/ExpressibleByStringInterpolation
,但它不起作用:编译器说HiddenFieldType
是String
,和Conformance of 'String' to protocol 'ExpressibleByStringLiteral' was already stated in the type's module 'Swift'
我能想到的唯一方法是将typealias HiddenFieldType = String
更改为struct HiddenFieldType { let value: String }
,因此HiddenFieldType
成为"real";类型。
方法# 4
这样的代码不再引起无限递归,但也不工作(值是未隐藏的)
struct HiddenFieldType {
let value: String
}
extension String.StringInterpolation {
mutating func appendInterpolation(_ value: HiddenFieldType) {
appendInterpolation("🤷♀️")
}
}
方法# 5
这段代码最终成功了:
struct HiddenFieldType {
let value: String
}
extension HiddenFieldType: CustomStringConvertible {
var description: String {
"🤷♀️"
}
}
因为我不能想象任何更好的,现在我会使用这种方法,但它也有一些轻微的可伸缩性问题,因为我必须更新每个DTO
的初始化点:从
let dto1 = DTO1(field1_1: "1_1", fieldToHide: "super-secret-1", field1_2: "1_2", field1_3: "1_3")
let dto1 = DTO1(field1_1: "1_1", fieldToHide: .init(value: "super-secret-1"), field1_2: "1_2", field1_3: "1_3")
和我希望只在包含typealias HiddenFieldType = String
的文件中添加一些扩展名,而不更新整个代码。
的问题
- 是否可以隐藏
HiddenFieldType
的值而不将其从typealias
更改为struct
,并且不更新每个DTO
? - 有比5更好的方法吗?
Thanks in advance
是否可以隐藏HiddenFieldType的值而不将其从typealias更改为struct
我觉得你用错工具了。typealias
只是一个名称更改,听起来你想要的东西与String
的行为根本不同(即一个被传递到os_log
调用时被打印,而一个没有)。你将无法编写将String
与typealias
区别对待的逻辑;编译器不会区分它们
是否有可能使你的DTO
s类而不是结构?(编辑:见下文,你可以保持它们作为结构体,只是使用协议扩展)如果是这样,你可以使用反射的超类来完成这一点,而不必手动指定description
为每个不同的DTO。
struct HiddenFieldType {
let value: String
}
open class DTO: CustomStringConvertible {
public var description: String {
Mirror(reflecting: self).children.compactMap { $0.value as? String }.joined(separator: "n")
}
}
final class DTO1: DTO {
let field1_1: String
let field1_2: String
let fieldToHide: HiddenFieldType
init(field1_1: String, field1_2: String, fieldToHide: HiddenFieldType) {
self. field1_1 = field1_1
self. field1_2 = field1_2
self. fieldToHide = fieldToHide
}
}
请注意,我包括description
中的所有字符串,但是,如果你有String
和HiddenFieldType
以外的类型,你想要记录,你总是可以只记录filter
的HiddenFieldType
s。
就我个人而言,我会犹豫是否要依赖任何关键代码的反射,但其他人对它更宽容,所以这是一个判断。
编辑:您不需要使用继承来实现这一点。DTO
应该是一个符合CustomStringConvertible
的协议,而不是一个超类:
protocol DTO: CustomStringConvertible {}
extension DTO {
public var description: String {
Mirror(reflecting: self).children.compactMap { $0.value as? String }.joined(separator: "n")
}
}