我从Swift 3.0.1收到编译器错误让我感到难过。该错误表明计算属性的类型存在歧义,但我不知道如何。
我有一个带有属性Generic
的协议root
。此协议具有通用约束,root
必须是Root
类型的子类。
class Root { }
protocol Generic {
associatedtype RootType: Root
var root: RootType { get }
}
然后我定义了一个协议扩展,声明:
如果
Generic
是Root
的子类,请从self
属性返回root
。
所以基本上:如果它已经是Root
,你可以转发self
。
extension Generic where Self: Root {
var root: Self {
return self
}
}
我还有GenericWrapper
类,它是Root
的子类,并包含Generic
的实例(用Root
代理执行Generic
个操作)。
class GenericWrapper<T: Generic>: Root {
var generic: T
init(generic: T) {
self.generic = generic
}
}
最后,我定义了一个Specialised
协议及其扩展名,其中包含:
如果
Specialised
实施Generic
,请从GenericWrapper
媒体资源中返回root
。
protocol Specialised { }
extension Specialised where Self: Generic {
var root: GenericWrapper<Self> {
get {
return GenericWrapper(generic: self)
}
}
}
然后当我尝试实现一个实现Generic
和Specialised
的类时,我收到了这个错误。
class SpecialisedImplementation: Generic, Specialised {
// errors:
// Ambiguous inference of associated type 'RootType': 'GenericWrapper<SpecialisedImplementation>' vs. 'SpecialisedImplementation'
// Matching requirement 'root' to this declaration inferred associated type to 'GenericWrapper<SpecialisedImplementation>'
// Matching requirement 'root' to this declaration inferred associated type to 'SpecialisedImplementation'
}
我之所以感到困惑的原因是因为歧义表明SpecialisedImplementation
类符合Generic
时Generic: Root
的扩展名要求,但SpecialisedImplementation
没有&Root
#39; t继承自/********** std::remove_cv replacement **********/
template< typename T >
struct remove_const
{
typedef T type;
};
template< typename T >
struct remove_const< const T >
{
typedef T type;
};
template< typename T >
struct remove_volatile
{
typedef T type;
};
template< typename T >
struct remove_volatile< volatile T >
{
typedef T type;
};
template< typename T >
struct remove_cv
{
typedef typename remove_volatile< typename remove_const< T >::type >::type type;
};
/********** std::is_pointer replacement *********/
template< typename T >
struct is_pointer_helper
{
static const bool value = false;
};
template< typename T >
struct is_pointer_helper< T* >
{
static const bool value = true;
};
template< typename T >
struct is_pointer
{
static const bool value = is_pointer_helper< typename remove_cv< T >::type >::value;
};
/********** std::enable_if replacement **********/
template< bool CONDITION, typename TYPE = void >
struct enable_if
{
};
template< typename TYPE >
struct enable_if< true, TYPE >
{
typedef TYPE type;
};
/****** std::remove_reference replacement *******/
template< typename T >
struct remove_reference
{
typedef T type;
};
template< typename T >
struct remove_reference< T& >
{
typedef T type;
};
/******* std::is_constructible replacement ******/
template< typename T, typename AT_1 = void, typename AT_2 = void, typename AT_3 = void, typename AT_4 = void >
class is_constructible_impl
{
private:
template< typename C_T, typename C_AT_1, typename C_AT_2, typename C_AT_3, typename C_AT_4 >
static bool test(
typename c_std::enable_if<
sizeof( C_T ) ==
sizeof( C_T(
static_cast< C_AT_1 >( *static_cast< typename c_std::remove_reference< C_AT_1 >::type* >( NULL ) ),
static_cast< C_AT_2 >( *static_cast< typename c_std::remove_reference< C_AT_2 >::type* >( NULL ) ),
static_cast< C_AT_3 >( *static_cast< typename c_std::remove_reference< C_AT_3 >::type* >( NULL ) ),
static_cast< C_AT_4 >( *static_cast< typename c_std::remove_reference< C_AT_4 >::type* >( NULL ) )
) )
>::type*
);
template< typename, typename, typename, typename, typename >
static int test( ... );
public:
static const bool value = ( sizeof( test< T, AT_1, AT_2, AT_3, AT_4 >( NULL ) ) == sizeof( bool ) );
};
template< typename T, typename AT_1, typename AT_2, typename AT_3 >
class is_constructible_impl< T, AT_1, AT_2, AT_3, void >
{
private:
template< typename C_T, typename C_AT_1, typename C_AT_2, typename C_AT_3 >
static bool test(
typename c_std::enable_if<
sizeof( C_T ) ==
sizeof( C_T(
static_cast< C_AT_1 >( *static_cast< typename c_std::remove_reference< C_AT_1 >::type* >( NULL ) ),
static_cast< C_AT_2 >( *static_cast< typename c_std::remove_reference< C_AT_2 >::type* >( NULL ) ),
static_cast< C_AT_3 >( *static_cast< typename c_std::remove_reference< C_AT_3 >::type* >( NULL ) )
) )
>::type*
);
template< typename, typename, typename, typename >
static int test( ... );
public:
static const bool value = ( sizeof( test< T, AT_1, AT_2, AT_3 >( NULL ) ) == sizeof( bool ) );
};
template< typename T, typename AT_1, typename AT_2 >
class is_constructible_impl< T, AT_1, AT_2, void, void >
{
private:
template< typename C_T, typename C_AT_1, typename C_AT_2 >
static bool test(
typename c_std::enable_if<
sizeof( C_T ) ==
sizeof( C_T(
static_cast< C_AT_1 >( *static_cast< typename c_std::remove_reference< C_AT_1 >::type* >( NULL ) ),
static_cast< C_AT_2 >( *static_cast< typename c_std::remove_reference< C_AT_2 >::type* >( NULL ) )
) )
>::type*
);
template< typename, typename, typename >
static int test( ... );
public:
static const bool value = ( sizeof( test< T, AT_1, AT_2 >( NULL ) ) == sizeof( bool ) );
};
template< typename T, typename AT_1 >
class is_constructible_impl< T, AT_1, void, void, void >
{
private:
template< typename C_T, typename C_AT_1 >
static bool test(
typename c_std::enable_if<
sizeof( C_T ) ==
sizeof( C_T(
static_cast< C_AT_1 >( *static_cast< typename c_std::remove_reference< C_AT_1 >::type* >( NULL ) )
) )
>::type*
);
template< typename, typename >
static int test( ... );
public:
static const bool value = ( sizeof( test< T, AT_1 >( NULL ) ) == sizeof( bool ) );
};
template< typename T >
class is_constructible_impl< T, void, void, void, void >
{
private:
template< typename C_T >
static C_T testFun( C_T );
template< typename C_T >
static bool test( typename c_std::enable_if< sizeof( C_T ) == sizeof( testFun( C_T() ) ) >::type* );
template< typename >
static int test( ... );
public:
static const bool value = ( sizeof( test< T >( NULL ) ) == sizeof( bool ) );
};
template< typename T, typename AT_1 = void, typename AT_2 = void, typename AT_3 = void, typename AT_4 = void >
class is_constructible_impl_ptr
{
public:
static const bool value = false;
};
template< typename T, typename AT_1 >
class is_constructible_impl_ptr< T, AT_1, typename enable_if< is_pointer< typename remove_reference< T >::type >::value, void >::type, void, void >
{
private:
template< typename C_T >
static bool test( C_T );
template< typename >
static int test( ... );
public:
static const bool value = ( sizeof( test< T >( static_cast< AT_1 >( NULL ) ) ) == sizeof( bool ) );
};
template< typename T >
class is_constructible_impl_ptr< T, void, void, void, void >
{
public:
static const bool value = true;
};
template< typename T, typename AT_1 = void, typename AT_2 = void, typename AT_3 = void, typename AT_4 = void >
class is_constructible
{
public:
static const bool value = (
is_pointer< typename remove_reference< T >::type >::value ?
is_constructible_impl_ptr< T, AT_1, AT_2, AT_3, AT_4 >::value :
is_constructible_impl< T, AT_1, AT_2, AT_3, AT_4 >::value
);
};
所以它不应该确定吗?
答案 0 :(得分:2)
诊断结果令人困惑;这里真正的问题是它太圆了,它超出了编译器可以处理的范围。
它尝试解析Generic
,并且发现它不能不假设SpecialisedImplementation
是Root
的子类(这不是真的,但是它迫切希望找到一种方法使它工作)。并且它会尝试Specialised
工作,但只有在Generic
已经有效的情况下才能这样做,但让Generic
工作的唯一方法就是使其Root
。
你希望它能同时承认你说的一切都是真的,但它并不那么聪明。它试图将它逐个零碎地构建,一次一个协议,并让人感到困惑。在bugs.swift.org上打开一个bug报告。
(但这也几乎肯定狂野过于复杂。特别是,如果可能的话,我会努力摆脱Root
类;混合协议和类以及泛型一起编写很多令人困惑的编译器问题。)
答案 1 :(得分:1)
我认为这是一个编译器错误并打开了bug report。对于遇到类似问题的其他人,我已设法通过从Self
扩展程序中移除Generic
要求来解决此问题:
class Root { }
protocol Generic {
associatedtype RootType: Root
var root: RootType { get }
}
extension Generic where Self: Root {
// ===================
// don't use Self here
// ===================
var root: Root {
return self
}
}
class GenericWrapper<T: Generic>: Root {
var generic: T
init(generic: T) {
self.generic = generic
}
}
protocol Specialised { }
extension Specialised where Self: Generic {
var root: GenericWrapper<Self> {
get {
return GenericWrapper(generic: self)
}
}
}
class SpecialisedImplementation: Generic, Specialised {
// no errors!
}
答案 2 :(得分:0)
我正在解决该错误。
与该声明匹配的要求'afuncName(:)' 将类型关联到“ SomeType”
这意味着:
想象一下我写了这个协议。
protocol Athlete{
associatedtype ShoeSize
func run(with: ShoeSize)
func jump(with: ShoeSize)
}
现在我尝试像这样遵循它:
class Person: Athlete{
func run(with: Int){ // Line A
print("running")
}
func jump(with: String){ // Line B
print("jumping")
}
}
在行 A 处,将ShoeSize关联类型推断为Int
。因此,对于其他jump
函数,它期望其输入类型也为Int
。但是它得到了String
,因此引发了错误。
与 B 行相同。只是这一次才将ShoeSize关联类型推断为String
。因此,对于其他run
函数,它期望其输入类型也为String
。但是它得到了Int
,因此引发了错误。
基本上,这样做我得到以下两个错误:
note: matching requirement 'jump(with:)' to this declaration inferred associated type to 'String'
func jum(with: String){
note: matching requirement 'run(with:)' to this declaration inferred associated type to 'Int'
func run(with: Int){
有什么解决方案?
奔跑和跳跃都应具有相同的输入,因为这两个输入均受关联类型的限制