构建自定义记录器:所有类型的自定义Swift字符串插值

构建自定义记录器:所有类型的自定义Swift字符串插值,swift,string,string-interpolation,Swift,String,String Interpolation,我想重现新的Swift日志功能的行为,其中字符串中的插值显示为,而不是我在应用程序中使用的自定义日志的实际值 例如: let accountNumber = 12345 log("User account number: \(accountNumber)") // User account number: 12345 ← leaking personal information 相反,我希望得到以下结果: // User account number: <pri

我想重现新的Swift日志功能的行为,其中字符串中的插值显示为
,而不是我在应用程序中使用的自定义日志的实际值

例如:

let accountNumber = 12345
log("User account number: \(accountNumber)")

// User account number: 12345  ← leaking personal information 
相反,我希望得到以下结果:

// User account number: <private>

您可以创建一个自定义类型(我们称之为
SecureMessage
),即
ExpressibleByStringInterpolation
(以及
CustomStringConvertible
),并让
log
函数将其作为其消息参数:

func log(_ message: SecureMessage) {
   print("\(message)")
}

let accountNumber = 12345
log("User account number: \(accountNumber)")
现在,我们可以定义
SecureMessage

struct SecureMessage: ExpressibleByStringInterpolation, 
                      CustomStringConvertible {

   struct StringInterpolation: StringInterpolationProtocol {
      var output = ""

      init(literalCapacity: Int, interpolationCount: Int) { }
        
      mutating func appendLiteral(_ literal: String) {
         output.append(literal)
      }

      mutating func appendInterpolation<T>(_ str: T) {
         output.append("<private>")
      }
   }

   let description: String

   init(stringLiteral value: String) {
      description = value
   }

   init(stringInterpolation: StringInterpolation) {
      description = stringInterpolation.output
   }
}
并更改
appendInterpolation
方法,以获取具有某些默认隐私值的隐私参数:

mutating func appendInterpolation<T: LosslessStringConvertible>(_ str: T, privacy: PrivacyLevel = .private) {
   switch privacy {
      case .private:
         output.append("<private>")
      case .public:
         output.append(String(str))
   }
}

非常感谢您快速而彻底的回答!!
enum PrivacyLevel {
   case `public`, `private`
}
mutating func appendInterpolation<T: LosslessStringConvertible>(_ str: T, privacy: PrivacyLevel = .private) {
   switch privacy {
      case .private:
         output.append("<private>")
      case .public:
         output.append(String(str))
   }
}
log("Hidden account number:  \(accountNumber)") // private by default
log("Visible account number: \(accountNumber, privacy: .public)")