Static member 'currency' cannot be used on protocol metatype 'SomeProtocol.Type'

huangapple go评论67阅读模式
英文:

Static member 'currency' cannot be used on protocol metatype 'SomeProtocol.Type'

问题

以下是您要求的翻译内容:

"我首先会给你一些背景信息。我正在尝试创建一个函数,该函数以符合某个协议(SomeProtocol)的任何类型作为参数。因此,我创建了一个具有静态方法currency的结构体,该结构体符合SomeProtocol,但是,当我尝试将该方法作为泛型函数的参数传递时,出现了以下错误:“无法在协议元类型'SomeProtocol.Type'上使用静态成员'currency'”。

我只是试图重新创建此SwiftUI代码:

Text(20.0, format: .currency(code: Locale.current.currency?.identifier ?? "USD"))

阅读文档,上面的函数是一个泛型init(),它接受符合某些协议的泛型类型作为参数。

init<F>(_ input: F.FormatInput, format: F) where F : FormatStyle, F.FormatInput : Equatable, F.FormatOutput == String

因此,.currency()是一个静态方法,来自FloatingPointFormatStyle.Currency,它是一个符合FormatStyle的结构体。

我的问题是,为什么在SwiftUI中可以工作(将符合协议的结构体上的静态方法作为参数传递给接受符合该协议的任何类型的函数),但在我的示例中不起作用:

protocol SomeProtocol {
    associatedtype SomeType: SomeProtocol
    var a: String { get }
    var b: String { get }
    static func currency(x: Int) -> SomeType
}

func someTest<T>(x: T) -> String where T: SomeProtocol{
    return "this works!"
}

struct AnotherType: SomeProtocol {
    let a = "Test"
    let b = "someTest"

    static func currency(x: Int) -> AnotherType {
        return AnotherType()
    }
}

someTest(x: .currency(x: 20))
英文:

I will give you some context first. I'm trying to make a function that takes as a parameter any type that conforms to a protocol (SomeProtocol). So, I created a struct with static method called currency and this struct conforms to SomeProtocol, but, I'm getting this error when trying to pass the method as argument for that generic function: "Static member 'currency' cannot be used on protocol metatype 'SomeProtocol.Type'".

I'm just trying to recreate this SwiftUI code:

Text(20.0, format: .currency(code: Locale.current.currency?.identifier ?? &quot;USD&quot;))

Reading the documentation, the function from above is a generic init() that takes a generic type that conforms to some protocols.

init&lt;F&gt;(_ input: F.FormatInput, format: F) where F : FormatStyle, F.FormatInput : Equatable, F.FormatOutput == String

So, .currency() is a static method that comes from FloatingPointFormatStyle.Currency, a structthat conforms to FormatStyle.

My question is, why is this working in SwiftUI (passing a static method from a struct that conforms to a protocol as an argument to a function that accepts any type that conforms to that protocol) but is not in my own example:

protocol SomeProtocol {
    associatedtype SomeType: SomeProtocol
    var a: String { get }
    var b: String { get }
    static func currency(x: Int) -&gt; SomeType
}

func someTest&lt;T&gt;(x: T) -&gt; String where T: SomeProtocol{
    return &quot;this works!&quot;
}

struct AnotherType: SomeProtocol {
    let a = &quot;Test&quot;
    let b = &quot;someTest&quot;

    static func currency(x: Int) -&gt; AnotherType {
        return AnotherType()
    }
}

someTest(x: .currency(x: 20))

答案1

得分: 1

请注意,.currency(...)隐式成员表达式

隐式成员表达式是一种缩写方式,用于在类型推断可以确定隐含类型的上下文中访问类型的成员,如枚举案例或类型方法。

Swift 只知道参数 x 期望某个 SomeProtocol 类型,但不知道是哪一个。所以它认为你的意思是:

someTest(x: SomeProtocol.currency(x: 20))

这是无效的。你要调用哪个实现的 currencySomeProtocol 中声明的 currency 方法没有实现!

你只能在协议的具体实现上调用 currency,例如 AnotherType.currency(x: 20)

请注意,内置 currency 的文档中没有提到“必需”或“提供默认实现”。SwiftUI 实际上是创建了一个包含 currency 实现的协议扩展,而不是创建协议要求:

extension SomeProtocol {
    static func currency(x: Int) -> AnotherType {
        return AnotherType()
    }
}

但这还不够。你仍然不能执行 SomeProtocol.currency(...)。如果 currency 使用协议的某些静态要求,Swift 不知道是否有任何静态要求,或者 currency 是否使用了它们。

所以你实际上需要:

extension SomeProtocol where Self == AnotherType {
    static func currency(x: Int) -> AnotherType {
        return AnotherType()
    }
}

现在 Swift 知道 .currency(x: 20) 意味着 AnotherType.currency(x: 20)

请注意,SomeType 关联类型是不必要的。如果需要,你可以添加涉及它的进一步约束,但对于这种隐式成员表达式的工作来说,它并不是必需的。

英文:

Note that .currency(...) is an implicit member expression.

> An implicit member expression is an abbreviated way to access a member of a type, such as an enumeration case or a type method, in a context where type inference can determine the implied type.

Swift only knows that the parameter x expects some SomeProtocol type, but doesn't know which one. So it thinks that you mean:

someTest(x: SomeProtocol.currency(x: 20))

This is invalid. Which implementation's currency are you calling? The currency method declared in SomeProtocol has no implementation!

You can only call currency on specific implementations of the protocol, e.g. AnotherType.currency(x: 20).

Notice that the documentation for the builtin currency doesn't say anything like "Required", or "Default implementation provided". What SwiftUI does is make an extension of the protocol that contains the implementation of currency, instead of making a protocol requirement:

extension SomeProtocol {
    static func currency(x: Int) -&gt; AnotherType {
        return AnotherType()
    }
}

But this is still not enough though. You still cannot do SomeProtocol.currency(...). What if currency uses some static requirements of the protocol? Swift doesn't know whether there is any, or whether currency uses them.

So you actually need:

extension SomeProtocol where Self == AnotherType {
    static func currency(x: Int) -&gt; AnotherType {
        return AnotherType()
    }
}

Now Swift knows that .currency(x: 20) means AnotherType.currency(x: 20).

Note that the SomeType associated type is unnecessary. You can add further constraints involving that if you want, but it is not necessary for this kind of implicit member expression to work.

huangapple
  • 本文由 发表于 2023年6月22日 08:04:06
  • 转载请务必保留本文链接:https://go.coder-hub.com/76527850.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定