是否有可能改变Swift字符串插值字符串类型别名?



我有很多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,但它不起作用:编译器说HiddenFieldTypeString,和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调用时被打印,而一个没有)。你将无法编写将Stringtypealias区别对待的逻辑;编译器不会区分它们

是否有可能使你的DTOs类而不是结构?(编辑:见下文,你可以保持它们作为结构体,只是使用协议扩展)如果是这样,你可以使用反射的超类来完成这一点,而不必手动指定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中的所有字符串,但是,如果你有StringHiddenFieldType以外的类型,你想要记录,你总是可以只记录filterHiddenFieldTypes。

就我个人而言,我会犹豫是否要依赖任何关键代码的反射,但其他人对它更宽容,所以这是一个判断。

编辑:您不需要使用继承来实现这一点。DTO应该是一个符合CustomStringConvertible的协议,而不是一个超类:

protocol DTO: CustomStringConvertible {}
extension DTO {
public var description: String {
Mirror(reflecting: self).children.compactMap { $0.value as? String }.joined(separator: "n")
}
}

最新更新