我在Swift代码中遇到了与类型相关的奇怪错误:
表达式的类型是不明确的,没有更多的上下文。
即使我提供了完整的类型信息,也会发生这种情况。
这是复制它的代码。
我有2个结构:
struct Person{
let name_ : String
let address_ : Address
}
struct Address {
let street_ : String
let city_ : String
}
然后我创建一个包含2个函数的结构来获取和设置address
的{{1}}:
Person
当我尝试创建一个获取并设置地址的Lens实例时(在后面的例子中它返回一个带有新地址的新Person),我在第一个闭包中得到了错误。
struct Lens<A,B> {
let extract: (A)->B
let create: (B,A) -> A
}
不仅在镜头类型中指定了第一个闭包的参数类型,而且在闭包本身中也是如此。
发生了什么????
答案 0 :(得分:3)
虽然它表明错误在extract
,但它确实在create
。 $0
和$1
是向后的。您引用的是$0.name_
,但$0
关闭的create
为B
,Address
,但name_
属性Person
。我想你的意思是:
let lens : Lens<Person, Address> = Lens(
extract: { $0.address_ },
create: { Person(name_: $1.name_, address_: Address(street_: $0.street_, city_: $1.address_.city_)) }
)
或者您可以重新定义Lens
:
struct Lens<A, B> {
let extract: (A) -> B
let create: (A, B) -> A // note, A & B swapped
}
然后你可以这样做:
let lens : Lens<Person, Address> = Lens(
extract: { $0.address_ },
create: { Person(name_: $0.name_, address_: Address(street_: $1.street_, city_: $0.address_.city_)) }
)
或许,你的意思是:
let lens : Lens<Person, Address> = Lens(
extract: { $0.address_ },
create: { Person(name_: $0.name_, address_: $1) }
)
这样,create
同时使用所提供地址的街道和城市。 (使用地址的街道,但不是城市,对我来说没有意义。)
答案 1 :(得分:2)
lens
的初始化将使用如下表单:
let lens = Lens<Person, Address>(
extract: {p in p.address_},
create: {(a,p) in Person(name_: p.name_, address_: Address(street_: a.street_, city_: p.address_.city_))})
正如Martin R所说,唯一的错误实际上是create
关闭。当您为结构调用默认初始值设定项时,默认情况下需要为所有自变量(即使是第一个)提供外部名称(=内部名称)(这与常规函数不同,在常规函数中可省略第一个的外部名称函数参数)。还要确保为初始化程序提供正确的参数类型。
请注意,您无需提供闭包类型((p:Person)->Address in ...
),因为Swift可以从闭包中推断(并期望这一点):p in ...
就足够了(参见上面的示例)。或者,更加精简,在闭包中省略显式变量名称,并使用$0
和$1
(预期参数)引用,就像在Robs解决方案中一样。