Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Swift 如何正确使用具有关联类型的协议来描述另一个对象中的属性_Swift_Generics_Swift Protocols - Fatal编程技术网

Swift 如何正确使用具有关联类型的协议来描述另一个对象中的属性

Swift 如何正确使用具有关联类型的协议来描述另一个对象中的属性,swift,generics,swift-protocols,Swift,Generics,Swift Protocols,我一直在创建一个SwiftUI组件,我希望这个组件有一个实现协议的属性。特定的用例是基于比例绘制图表的轴 scale有几个具体的实现,可以将数据从输入域转换到输出范围。我首先介绍的两个是一个线性刻度,它将Double输入域转换为Double表示的输出范围。另一个是基于日期/时间的刻度,它从基于日期的输入域转换为由双精度表示的输出范围 Scale是协议,我尝试将其大致定义为: 公共协议规模{ associatedtype InputDomain:可比较//输入域 var isClamped:Boo

我一直在创建一个SwiftUI组件,我希望这个组件有一个实现协议的属性。特定的用例是基于比例绘制图表的轴

scale有几个具体的实现,可以将数据从输入域转换到输出范围。我首先介绍的两个是一个线性刻度,它将
Double
输入域转换为
Double
表示的输出范围。另一个是基于日期/时间的刻度,它从基于
日期的输入域转换为由
双精度
表示的输出范围

Scale是协议,我尝试将其大致定义为:

公共协议规模{
associatedtype InputDomain:可比较//输入域
var isClamped:Bool{get}
//输入值
变量域:ClosedRange{get}
//输出值
变量范围:ClosedRange{get}
///在输入“域”和输出“范围”之间转换值
///
///-参数inputValue:域的ClosedRange范围内的值
///-返回:范围的ClosedRange范围内的值,如果映射超出范围,则返回NaN
func比例(uInputValue:InputDomain)->双精度
///将输出“范围”转换回输入“域”内的值。比例()的倒数
///
///-参数outputValue:范围的ClosedRange范围内的值
///-返回:域的ClosedRange范围内的值,如果映射到范围外,则返回NaN
func invert(uOutputValue:Double)->InputDomain
///返回范围闭合范围内的位置数组,以定位刻度的刻度
///
///-参数计数:要显示的刻度数,默认为10
///-返回:输入范围闭合范围内的值数组
func ticks(计数:Int)->[InputDomain]
}
LinearScale和TimeScale结构符合协议,分别定义了
typealias InputDomain=Double
typealias InputDomain=Date

当我尝试使用此协议来描述更通用于SwiftUI组件的结构(规模)类型时,问题就出现了:

公共结构AxisView:View{code> 让缩放:缩放 公共变量主体:某些视图{…} }
编译器提供了以下错误:
协议“规模”只能用作一般约束,因为它具有自身或关联的类型要求

我不确定解决这个问题的最佳方法是解决编译器错误/约束。我应该做些什么使SwiftUI组件成为通用组件,还是不使用与协议关联的类型

或者,是否有另一种方法可以考虑使用协议和结构来构造此代码以支持各种规模类型

更新:我得到了原始问题的答案,但对我来说还不完全确定。我将泛型定义添加到封闭类型(我的
Scale
实现)

我不清楚的是为什么需要这样做?在封闭结构上添加泛型标记后,编译器错误消失了。我假设这是一个swift编译器可以选择的地方,告诉它“是的,我希望这是一个泛型”是一条路径-其他可能的路径是什么

我还注意到,尽管它被定义为泛型类,但我使用的特定类通常由swift编译器推断。所以我不需要用泛型语法完全指定类型。例如,我可以使用


LinearScale()
而不是
LinearScale
(),它将推断出正确的泛型。这是预期的吗?

您还应该使您的视图具有通用性:

public struct AxisView<ScaleType: Scale>: View {    
    let scale:  ScaleType    
    public var body: some View { ... }
}
公共结构AxisView:View{code> let scale:ScaleType 公共变量主体:某些视图{…} }
您还应将视图设置为通用视图:

public struct AxisView<ScaleType: Scale>: View {    
    let scale:  ScaleType    
    public var body: some View { ... }
}
公共结构AxisView:View{code> let scale:ScaleType 公共变量主体:某些视图{…} }
这是一种不好的样式,但是你可以将scale声明为
Any
并在必要时将其展开。这是一种不好的样式,但是你可以将scale声明为
Any
并在必要时将其展开。谢谢你给我的指针指向正确的方向-我已经稍微更新了这个问题,因为我也不完全确定当我将视图设置为通用视图时会发生什么。编译器似乎对此进行了很多推断,所以为什么不能推断我也需要一个泛型结构呢?这里还有我没有的其他选择或模式吗?@heckj swift编译器可以设计为建议这样的更改,但设计者没有这样做,可能是因为这是一项非常艰苦的工作,没有带来太多好处。另一方面,如果您的意思是swift应该将此代码放在一边,而只是“假设”您实际上打算使AxisView成为通用的,那么我认为这太过分了。你不需要
,因为你已经说过
LinearScale
声明中的
InputDomain
是什么。谢谢你给我指出了正确的方向-我已经更新了一点问题,因为我也不完全确定当我将视图设置为通用视图时会发生什么。编译器似乎对此进行了很多推断,所以为什么不能推断我也需要一个泛型结构呢?这里还有我没有的其他选择或模式吗?@heckj swift编译器可以设计为建议这样的更改,但设计者没有这样做,可能是因为这是一项非常艰苦的工作,没有带来太多好处。另一方面,如果你的意思是斯威夫特应该把这个代码放在一边,只是“屁股”