jjzjj

ios - 协议(protocol) 'Line' 只能用作通用约束,因为它具有 Self 或关联类型要求

coder 2023-09-13 原文

我正在快速处理协议(protocol)。我假设它类似于其他语言的“界面”。我正在测试它如何处理变量。协议(protocol)对我来说很新,因为我从未见过与非静态变量的接口(interface)。我创建了一个 Station 协议(protocol)。

protocol Station{
    var id:String {get set}
    var name:String {get set} // station name
    var lines: Array<String> {get set} // all lines persent in this station 
}

然后是包含该站引用的线路。它还包括 Hashable 协议(protocol)。

protocol Line: Hashable  {
    var lineId: String{get set}
    var station1:Station {get set}    // start station
    var station2:Station {get set}   // end station
    var stations:Array<Station> {get set}   // all the stations that is in this line   
}

这是该协议(protocol)的实现

struct LinesImpl: Line{
    var station1: Station
    var station2: Station
    var stations: Array<Station>
    var lineId: String
    static func == (lhs: LinesImpl, rhs: LinesImpl) -> Bool {
        return (lhs.station1.name == rhs.station1.name && lhs.station2.name == rhs.station2.name && lhs.lineId == rhs.lineId)
    }
    func hash(into hasher: inout Hasher) {
        hasher.combine(station1.name)
        hasher.combine(station2.name)
        hasher.combine(lineId)
    }
    init(station1: Station, station2: Station, stations: [Station], lineId: String){
        self.station1 = station1
        self.station2 = station2
        self.stations = stations
        self.lineId = lineId   
    }
}

一旦我添加了 Hashable。我无法再为 Line 协议(protocol)创建引用。

当我尝试这样做时,它说“协议(protocol)‘Line’只能用作通用约束,因为它具有 self 或相关类型要求”:

我在这里看到很多这样的问题,但我仍然看不出错误是什么。任何帮助都是极好的。多谢你们。

最佳答案

当您添加 Hashable 时,即添加了 Equatable,这使它成为具有关联类型 (PAT) 的协议(protocol),因为 Equatable 是一个 PAT . PAT 不是一种类型;它是一种用于向其他类型添加方法的工具。

您不能将 PAT 用作变量的类型,不能将其放入数组中,不能将其作为参数直接传递,不能将其作为值返回。 PAT 的唯一要点是作为通用约束(where L: Line)。 PAT 说明另一种具体类型必须提供什么才能在某些上下文中可用。

您应该如何解决这个问题尚不清楚。这看起来根本不应该是一个协议(protocol)。这取决于您要在此处解决的代码重用问题。

协议(protocol)通常是关于某些东西可以做什么的。 Line 似乎只是试图隐藏实现,没有表达任何东西;那不是协议(protocol)。如所写,这里根本没有理由使用泛型或协议(protocol)。 Line 的其他实现是什么样的? (我无法想象您还可能如何实现这种类型。)

我怀疑正确的答案是用 Station 结构和 Line 结构替换所有这些。我没有看到协议(protocol)在哪里发挥作用。

我可以通过以下方式实现您正在构建的内容,以及一些新协议(protocol)以了解它们的用途。其中一些可能超出您解决此问题的需要,但我想展示实际中的协议(protocol)。

// A protocol for "ID" types that automatically gives them handy inits
// Nested ID types mean that Line.ID can't get confused with Station.ID.
// The point of a protocol is to add additional features to a type like this.
protocol IDType: Hashable, ExpressibleByStringLiteral, CustomStringConvertible {
    var value: String { get }
    init(value: String)
}

extension IDType {
    // For convenience
    init(_ value: String) { self.init(value: value) }
    // Default impl for ExpressibleByStringLiteral
    init(stringLiteral value: String) { self.init(value: value) }
    // Default impl for CustomStringConvertible
    var description: String { return value }
}

struct Line: Equatable  {
    struct ID: IDType { let value: String }
    let id: ID
    let stations: [Station]
    var origin: Station { return stations.first! } // We ensure during init that stations is non-empty
    var terminus: Station { return stations.last! }

    init(id: ID, origin: Station, stops: [Station], terminus: Station) {
        self.id = id
        self.stations = [origin] + stops + [terminus]
    }
}

// Conforming Line to this protocol lets it print more beautifully.
extension Line: CustomStringConvertible {
    var description: String { return "\(id): \(origin) -> \(terminus)" }
}

// Stations can't contain Line directly. These are value types, and that would be
// recursive. But this is nice because it lets us construct immutable Stations
// and then glue them together with Lines which may even be in independent
// systems (for example, the bus system might be separate from the rail system,
// but share stations)
struct Station: Hashable {
    struct ID: IDType { let value: String }
    let id: ID
    let name: String

    func lines(in system: System) -> [Line] {
        return system.linesVisiting(station: self)
    }
}

extension Station: CustomStringConvertible {
    var description: String { return name }
}

struct System: Equatable {
    let lines: [Line]

    // Using Set here makes it clear there are no duplicates, and saves
    // some hassle turning it back into an Array, but we could also just
    // return Array here as Array(Set(...))
    var stations: Set<Station> {
        // Uniquify the stations
        return Set(lines.flatMap { $0.stations })
    }

    func linesVisiting(station: Station) -> [Line] {
        return lines.filter { $0.stations.contains(station) }
    }
}

// Some examples of using it.
let stationNames = ["Shady Grove", "Bethesda", "Metro Center", "Glenmont",
                    "Wiehle-Reston East", "Largo Town Center"]

// Build up a few stations; obviously there are many more
let stations = Dictionary(uniqueKeysWithValues:
    stationNames.map { ($0, Station(id: .init($0), name: $0)) })

// Define some lines
let redLine = Line(id: "OR",
                   origin: stations["Shady Grove"]!,
                   stops: [stations["Bethesda"]!, stations["Metro Center"]!],
                   terminus: stations["Glenmont"]!)

let silverLine = Line(id: "SV",
                      origin: stations["Wiehle-Reston East"]!,
                      stops: [stations["Metro Center"]!],
                      terminus: stations["Largo Town Center"]!)

// And glue them together into a system
let system = System(lines: [redLine, silverLine])

关于ios - 协议(protocol) 'Line' 只能用作通用约束,因为它具有 Self 或关联类型要求,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55066079/

有关ios - 协议(protocol) 'Line' 只能用作通用约束,因为它具有 Self 或关联类型要求的更多相关文章

  1. ruby-on-rails - rails : "missing partial" when calling 'render' in RSpec test - 2

    我正在尝试测试是否存在表单。我是Rails新手。我的new.html.erb_spec.rb文件的内容是:require'spec_helper'describe"messages/new.html.erb"doit"shouldrendertheform"dorender'/messages/new.html.erb'reponse.shouldhave_form_putting_to(@message)with_submit_buttonendendView本身,new.html.erb,有代码:当我运行rspec时,它失败了:1)messages/new.html.erbshou

  2. ruby-on-rails - 'compass watch' 是如何工作的/它是如何与 rails 一起使用的 - 2

    我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t

  3. ruby - 具有身份验证的私有(private) Ruby Gem 服务器 - 2

    我想安装一个带有一些身份验证的私有(private)Rubygem服务器。我希望能够使用公共(public)Ubuntu服务器托管内部gem。我读到了http://docs.rubygems.org/read/chapter/18.但是那个没有身份验证-如我所见。然后我读到了https://github.com/cwninja/geminabox.但是当我使用基本身份验证(他们在他们的Wiki中有)时,它会提示从我的服务器获取源。所以。如何制作带有身份验证的私有(private)Rubygem服务器?这是不可能的吗?谢谢。编辑:Geminabox问题。我尝试“捆绑”以安装新的gem..

  4. ruby-on-rails - Rails 3.2.1 中 ActionMailer 中的未定义方法 'default_content_type=' - 2

    我在我的项目中添加了一个系统来重置用户密码并通过电子邮件将密码发送给他,以防他忘记密码。昨天它运行良好(当我实现它时)。当我今天尝试启动服务器时,出现以下错误。=>BootingWEBrick=>Rails3.2.1applicationstartingindevelopmentonhttp://0.0.0.0:3000=>Callwith-dtodetach=>Ctrl-CtoshutdownserverExiting/Users/vinayshenoy/.rvm/gems/ruby-1.9.3-p0/gems/actionmailer-3.2.1/lib/action_mailer

  5. ruby - 在 jRuby 中使用 'fork' 生成进程的替代方案? - 2

    在MRIRuby中我可以这样做:deftransferinternal_server=self.init_serverpid=forkdointernal_server.runend#Maketheserverprocessrunindependently.Process.detach(pid)internal_client=self.init_client#Dootherstuffwithconnectingtointernal_server...internal_client.post('somedata')ensure#KillserverProcess.kill('KILL',

  6. ruby - 主要 :Object when running build from sublime 的未定义方法 `require_relative' - 2

    我已经从我的命令行中获得了一切,所以我可以运行rubymyfile并且它可以正常工作。但是当我尝试从sublime中运行它时,我得到了undefinedmethod`require_relative'formain:Object有人知道我的sublime设置中缺少什么吗?我正在使用OSX并安装了rvm。 最佳答案 或者,您可以只使用“require”,它应该可以正常工作。我认为“require_relative”仅适用于ruby​​1.9+ 关于ruby-主要:Objectwhenrun

  7. ruby - 续集在添加关联时访问many_to_many连接表 - 2

    我正在使用Sequel构建一个愿望list系统。我有一个wishlists和itemstable和一个items_wishlists连接表(该名称是续集选择的名称)。items_wishlists表还有一个用于facebookid的额外列(因此我可以存储opengraph操作),这是一个NOTNULL列。我还有Wishlist和Item具有续集many_to_many关联的模型已建立。Wishlist类也有:selectmany_to_many关联的选项设置为select:[:items.*,:items_wishlists__facebook_action_id].有没有一种方法可以

  8. ruby - 无法让 RSpec 工作—— 'require' : cannot load such file - 2

    我花了三天的时间用头撞墙,试图弄清楚为什么简单的“rake”不能通过我的规范文件。如果您遇到这种情况:任何文件夹路径中都不要有空格!。严重地。事实上,从现在开始,您命名的任何内容都没有空格。这是我的控制台输出:(在/Users/*****/Desktop/LearningRuby/learn_ruby)$rake/Users/*******/Desktop/LearningRuby/learn_ruby/00_hello/hello_spec.rb:116:in`require':cannotloadsuchfile--hello(LoadError) 最佳

  9. ruby-on-rails - 新 Rails 项目 : 'bundle install' can't install rails in gemfile - 2

    我已经像这样安装了一个新的Rails项目:$railsnewsite它执行并到达:bundleinstall但是当它似乎尝试安装依赖项时我得到了这个错误Gem::Ext::BuildError:ERROR:Failedtobuildgemnativeextension./System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/bin/rubyextconf.rbcheckingforlibkern/OSAtomic.h...yescreatingMakefilemake"DESTDIR="cleanmake"DESTDIR="

  10. ruby-on-rails - rspec should have_select ('cars' , :options => ['volvo' , 'saab' ] 不工作 - 2

    关闭。这个问题需要detailsorclarity.它目前不接受答案。想改进这个问题吗?通过editingthispost添加细节并澄清问题.关闭8年前。Improvethisquestion在首页我有:汽车:VolvoSaabMercedesAudistatic_pages_spec.rb中的测试代码:it"shouldhavetherightselect"dovisithome_pathit{shouldhave_select('cars',:options=>['volvo','saab','mercedes','audi'])}end响应是rspec./spec/request

随机推荐