草庐IT

Swift SQLite3 语法和绑定(bind)

coder 2023-07-21 原文

首先,这些是我的功能:

  • 插入功能
    func insert(book : Book) throws -> Bool {
        var insertPointer: OpaquePointer? = nil
        let query = "INSERT INTO BOOK (bookName, bookAuthor, bookDesc, bookDate, bookImg, createdBy) VALUES (?, ?, ?, ?, ?, ?)"
    
        defer{
            sqlite3_finalize(insertPointer)
        }
    
        if sqlite3_prepare_v2(db, query, -1, &insertPointer, nil) == SQLITE_OK {
            sqlite3_bind_text(insertPointer, 1, book.bookTitle, -1, nil)
            sqlite3_bind_text(insertPointer, 2, book.bookAuthor, -1, nil)
            sqlite3_bind_text(insertPointer, 3, book.bookDesc, -1, nil)
          //sqlite3_bind_date(insertPointer, 4, book.bookDate,nil)
          //sqlite3_bind_image(insertPointer, 5, book.bookImg, -1, nil)
            sqlite3_bind_text(insertPointer, 6, book.createdBy, -1, nil)
    
            guard sqlite3_step(insertPointer) == SQLITE_DONE else {
                throw SQLiteError.Step(message: errorMessage)
            }
        } else {
            throw SQLiteError.Prepare(message: errorMessage)
        }
    
        return true
    }
    
  • 更新功能
    func update(book : Book) throws -> Bool {
        var updatePointer: OpaquePointer? = nil
        var query = "UPDATE Book SET bookName = ?, bookAuthor = ?, bookDesc = ?, bookDate = ?, bookImg = ?, createdBy = ?, WHERE bookId = ?"
    
        defer{
            sqlite3_finalize(updatePointer)
        }
    
        if sqlite3_prepare_v2(db, query, -1, &updatePointer, nil) == SQLITE_OK {
    
            sqlite3_bind_text(updatePointer, 2, book.bookAuthor, -1, nil)
            sqlite3_bind_text(updatePointer, 3, book.bookDesc, -1, nil)
            //sqlite3_bind_date(updatePointer, 4, book.bookDate,nil)
            //sqlite3_bind_image(updatePointer, 5, book.bookImg, -1, nil)
            sqlite3_bind_text(updatePointer, 6, book.createdBy, -1, nil)
            sqlite3_bind_text(updatePointer, 7, book.bookId, -1, nil)
            guard sqlite3_step(updatePointer) == SQLITE_DONE else {
                throw SQLiteError.Step(message: errorMessage)
            }
        } else {
            throw SQLiteError.Prepare(message: errorMessage)
        }
    
        return true
    }
    
  • 删除功能
    func delete(book : Book) throws -> Bool {
        var deletePointer: OpaquePointer? = nil
        var query = "DELETE FROM Book WHERE bookId = ?"
    
        defer{
            sqlite3_finalize(deletePointer)
        }
    
        if sqlite3_prepare_v2(db, query, -1, &deletePointer, nil) == SQLITE_OK {
            sqlite3_bind_text(updatePointer, 1, book.bookId, -1, nil)
            guard sqlite3_step(deletePointer) == SQLITE_DONE else {
                throw SQLiteError.Step(message: errorMessage)
            }
        } else {
            throw SQLiteError.Prepare(message: errorMessage)
        }
    
        return true
    }
    

  • 我有一个 Book像这样的类:
    class Book{
        var bookId : Int
        var bookImg : Data
        var bookTitle : String
        var bookAuthor : String
        var bookDesc : String
        var bookDate : Date
        var createdBy : String
    
        init(bookId : Int, bookImg : Data, bookTitle : String, bookAuthor : String, bookDesc : String, bookDate : Date, createdBy : String){
            self.bookId = bookId
            self.bookImg = bookImg
            self.bookTitle = bookTitle
            self.bookAuthor = bookAuthor
            self.bookDesc = bookDesc
            self.bookDate = bookDate
            self.createdBy = createdBy
        }
    }
    

    我是 Swift 和 SQLite 的新手。我的问题是:
  • 我在参数绑定(bind)方面做得对吗?
  • 如何绑定(bind) DataDate键入 SQLite 查询? (上面代码中的注释行)

  • 任何帮助将不胜感激!

    最佳答案

    你问:

    1. Am I doing it right with the parameter binding?


    大部分。
  • 绑定(bind)字符串时,谨慎使用 SQLITE_TRANSIENT作为 sqlite3_bind_text 的最后一个参数和 sqlite3_bind_blob ,定义如下:
    internal let SQLITE_STATIC = unsafeBitCast(0, to: sqlite3_destructor_type.self)
    internal let SQLITE_TRANSIENT = unsafeBitCast(-1, to: sqlite3_destructor_type.self)
    
  • 绑定(bind)时bookId ,您要使用 sqlite3_bind_int64 .
  • delete你指的是updatePointer .将其更改为 deletePointer .
  • 您可能应该检查这些 sqlite3_bind_xxx返回代码并抛出错误,如果它们不是 SQLITE_OK , 也。

  • 然后你问:

    1. How do I bind Data and Date type into SQLite query? (the commented line in code above)


    对于日期类型,SQLite 没有 native 日期类型(请参阅 http://sqlite.org/datatype3.html )。所以你可以:
  • 使用 ISODateFormatter构建一个字符串,并绑定(bind)字符串;如果你需要小数秒,你可以使用 withFractionalSeconds 选项(在 iOS 11、macOS 10.13 等中引入),例如:
    let formatter = ISO8601DateFormatter()
    formatter.formatOptions.insert(.withFractionalSeconds)
    
  • 如果您需要毫秒并需要支持那些较旧的操作系统版本,请使用 DateFormatterdateFormatyyyy-MM-dd'T'HH:mm:ss.SSSX , localeLocale(identifier: "en_US_POSIX") , 和 timeZoneTimeZone(secondsFromGMT: 0) ,并再次将日期存储和检索为字符串并进行转换;或
  • 使用 timeIntervalSince1970Date ,并将其插入为 sqlite3_bind_double .

  • 前一种字符串替代方案最容易使用,并且在第三方工具中目视检查数据库时更容易。 timeIntervalSince1970可以说效率更高,但这只是意味着您需要使用 unixepoch如果查看第三方 SQLite 工具中的列,则将 double 转换为可理解的日期,这可能有点麻烦。这是效率与可用性的权衡。

    回复 Data , 插入使用 sqlite3_bind_blob .

    几个最后的小观察:
  • 您正在推迟 sqlite3_finalize在你之前sqlite3_prepare_v2 .您应该defer它之后 sqlite3_prepare_v2 .您应该只在准备成功时完成,而不是在失败时完成。
  • 关于更新 WHERE条款,您可能需要检查 sqlite3_changes查看是否有任何记录更改。对于按标识符进行更新,如果没有更新/删除任何内容,我将函数更改为抛出错误。
  • 其中几个函数被定义为抛出错误以及返回一个 bool 值。对于没有意义的更新/删除函数(因为我们使用错误来知道它是否成功,使得 bool 返回值变得多余)。所以我删除了 Bool返回类型。对于其他函数(例如 SELECT 例程),返回值显然是有意义的,但对于这些通过/失败更新例程而言则不然。
  • 对于 Book属性,我删除了 book字首。在 SQL 中使用该前缀是有意义的(它使连接查询更容易编写),但它在 Swift 类型中是多余的。您通常只在需要消除歧义的地方使用那种前缀(例如 bookDescription ,以避免与 CustomStringConvertible 属性混淆, description )。


  • 无论如何,把它放在一起,你会得到类似的东西:
    var dateFormatter: DateFormatter = {
        let _formatter = DateFormatter()
        _formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSX"
        _formatter.locale = Locale(identifier: "en_US_POSIX")
        _formatter.timeZone = TimeZone(secondsFromGMT: 0)
        return _formatter
    }()
    
    var errorMessage: String { return String(cString: sqlite3_errmsg(db)) }
    
    func insert(_ book: inout Book) throws {
        var statement: OpaquePointer? = nil
        let query = "INSERT INTO book (bookName, bookAuthor, bookDesc, bookDate, bookImg, createdBy) VALUES (?, ?, ?, ?, ?, ?)"
    
        guard sqlite3_prepare_v2(db, query, -1, &statement, nil) == SQLITE_OK else {
            throw SQLiteError.prepare(message: errorMessage)
        }
    
        defer { sqlite3_finalize(statement) }
    
        guard sqlite3_bind_text(statement, 1, book.title, -1, SQLITE_TRANSIENT) == SQLITE_OK else {
            throw SQLiteError.bind(message: errorMessage)
        }
    
        guard sqlite3_bind_text(statement, 2, book.author, -1, SQLITE_TRANSIENT) == SQLITE_OK else {
            throw SQLiteError.bind(message: errorMessage)
        }
    
        guard sqlite3_bind_text(statement, 3, book.bookDescription, -1, SQLITE_TRANSIENT) == SQLITE_OK else {
            throw SQLiteError.bind(message: errorMessage)
        }
    
        guard sqlite3_bind_text(statement, 4, dateFormatter.string(from: book.createDate), -1, SQLITE_TRANSIENT) == SQLITE_OK else {
            throw SQLiteError.bind(message: errorMessage)
        }
    
        guard book.image.withUnsafeBytes({ bufferPointer -> Int32 in
            sqlite3_bind_blob(statement, 5, bufferPointer.baseAddress, Int32(book.image.count), SQLITE_TRANSIENT)
        }) == SQLITE_OK else {
            throw SQLiteError.bind(message: errorMessage)
        }
    
        guard sqlite3_bind_text(statement, 6, book.createdBy, -1, SQLITE_TRANSIENT) == SQLITE_OK else {
            throw SQLiteError.bind(message: errorMessage)
        }
    
        guard sqlite3_step(statement) == SQLITE_DONE else {
            throw SQLiteError.step(message: errorMessage)
        }
    
        book.id = Int(sqlite3_last_insert_rowid(db))
    }
    
    func update(_ book: Book) throws {
        guard let id = book.id.flatMap({ Int64($0) }) else {
            throw SQLiteError.noDataChanged
        }
    
        var statement: OpaquePointer? = nil
        let query = "UPDATE Book SET bookName = ?, bookAuthor = ?, bookDesc = ?, bookDate = ?, bookImg = ?, createdBy = ? WHERE bookId = ?"
    
        guard sqlite3_prepare_v2(db, query, -1, &statement, nil) == SQLITE_OK else {
            throw SQLiteError.prepare(message: errorMessage)
        }
    
        defer { sqlite3_finalize(statement) }
    
        guard sqlite3_bind_text(statement, 1, book.title, -1, SQLITE_TRANSIENT) == SQLITE_OK else {
            throw SQLiteError.bind(message: errorMessage)
        }
    
        guard sqlite3_bind_text(statement, 2, book.author, -1, SQLITE_TRANSIENT) == SQLITE_OK else {
            throw SQLiteError.bind(message: errorMessage)
        }
    
        guard sqlite3_bind_text(statement, 3, book.bookDescription, -1, SQLITE_TRANSIENT) == SQLITE_OK else {
            throw SQLiteError.bind(message: errorMessage)
        }
    
        guard sqlite3_bind_text(statement, 4, dateFormatter.string(from: book.createDate), -1, SQLITE_TRANSIENT) == SQLITE_OK else {
            throw SQLiteError.bind(message: errorMessage)
        }
    
        guard book.image.withUnsafeBytes({ bufferPointer -> Int32 in
            sqlite3_bind_blob(statement, 5, bufferPointer.baseAddress, Int32(book.image.count), SQLITE_TRANSIENT)
        }) == SQLITE_OK else {
            throw SQLiteError.bind(message: errorMessage)
        }
    
        guard sqlite3_bind_text(statement, 6, book.createdBy, -1, SQLITE_TRANSIENT) == SQLITE_OK else {
            throw SQLiteError.bind(message: errorMessage)
        }
    
        guard sqlite3_bind_int64(statement, 7, id) == SQLITE_OK else {
            throw SQLiteError.bind(message: errorMessage)
        }
    
        guard sqlite3_step(statement) == SQLITE_DONE else {
            throw SQLiteError.step(message: errorMessage)
        }
    
        guard sqlite3_changes(db) > 0 else {
            throw SQLiteError.noDataChanged
        }
    }
    
    func delete(_ book: Book) throws {
        guard let id = book.id.flatMap({ Int64($0) }) else {
            throw SQLiteError.noDataChanged
        }
    
        var statement: OpaquePointer? = nil
        let query = "DELETE FROM Book WHERE bookId = ?"
    
        guard sqlite3_prepare_v2(db, query, -1, &statement, nil) == SQLITE_OK else {
            throw SQLiteError.prepare(message: errorMessage)
        }
    
        defer { sqlite3_finalize(statement) }
    
        guard sqlite3_bind_int64(statement, 1, id) == SQLITE_OK else {
            throw SQLiteError.bind(message: errorMessage)
        }
    
        guard sqlite3_step(statement) == SQLITE_DONE else {
            throw SQLiteError.step(message: errorMessage)
        }
    
        guard sqlite3_changes(db) > 0 else {
            throw SQLiteError.noDataChanged
        }
    }
    
    func select(bookId: Int) throws -> Book {
        var statement: OpaquePointer? = nil
        let query = "SELECT bookId, bookName, bookAuthor, bookDesc, bookDate, bookImg, createdBy FROM Book WHERE bookId = ?"
    
        guard sqlite3_prepare_v2(db, query, -1, &statement, nil) == SQLITE_OK else {
            throw SQLiteError.prepare(message: errorMessage)
        }
    
        defer { sqlite3_finalize(statement) }
    
        guard sqlite3_bind_int64(statement, 1, Int64(bookId)) == SQLITE_OK else {
            throw SQLiteError.bind(message: errorMessage)
        }
    
        guard sqlite3_step(statement) == SQLITE_ROW else {
            throw SQLiteError.step(message: errorMessage)
        }
    
        return try book(for: statement)
    }
    
    func selectAll() throws -> [Book] {
        var statement: OpaquePointer? = nil
        let query = "SELECT bookId, bookName, bookAuthor, bookDesc, bookDate, bookImg, createdBy FROM Book"
    
        guard sqlite3_prepare_v2(db, query, -1, &statement, nil) == SQLITE_OK else {
            throw SQLiteError.prepare(message: errorMessage)
        }
    
        defer { sqlite3_finalize(statement) }
    
        var books = [Book]()
    
        var rc: Int32
        repeat {
            rc = sqlite3_step(statement)
            guard rc == SQLITE_ROW else { break }
            books.append(try book(for: statement))
        } while rc == SQLITE_ROW
    
        guard rc == SQLITE_DONE else {
            throw SQLiteError.step(message: errorMessage)
        }
    
        return books
    }
    
    func book(for statement: OpaquePointer?) throws -> Book {
        let bookId = Int(sqlite3_column_int64(statement, 0))
    
        guard let bookNameCString = sqlite3_column_text(statement, 1) else {
            throw SQLiteError.column(message: errorMessage)
        }
        let bookName = String(cString: bookNameCString)
    
        guard let bookAuthorCString = sqlite3_column_text(statement, 2) else {
            throw SQLiteError.column(message: errorMessage)
        }
        let bookAuthor = String(cString: bookAuthorCString)
    
        guard let bookDescCString = sqlite3_column_text(statement, 3) else {
            throw SQLiteError.column(message: errorMessage)
        }
        let bookDesc = String(cString: bookDescCString)
    
        guard let bookDateCString = sqlite3_column_text(statement, 4) else {
            throw SQLiteError.column(message: errorMessage)
        }
        guard let bookDate = dateFormatter.date(from: String(cString: bookDateCString)) else {
            throw SQLiteError.invalidDate
        }
    
        let bookImgCount = Int(sqlite3_column_bytes(statement, 5))
        guard bookImgCount > 0 else {
            throw SQLiteError.missingData
        }
        guard let bookImgBlog = sqlite3_column_blob(statement, 5) else {
            throw SQLiteError.column(message: errorMessage)
        }
        let bookImg = Data(bytes: bookImgBlog, count: bookImgCount)
    
        guard let createdByCString = sqlite3_column_text(statement, 6) else {
            throw SQLiteError.column(message: errorMessage)
        }
        let createdBy = String(cString: createdByCString)
    
        return Book(id: bookId, image: bookImg, title: bookName, author: bookAuthor, bookDescription: bookDesc, createDate: bookDate, createdBy: createdBy)
    }
    

    有了这些定义:
    struct Book {
        var id: Int?
        var image: Data
        var title: String
        var author: String
        var bookDescription: String  // this is the only one where I kept the `book` prefix, simply because `description` is a reserved name
        var createDate: Date
        var createdBy: String
    }
    
    enum SQLiteError: Error {
        case open(result: Int32)
        case exec(message: String)
        case prepare(message: String)
        case bind(message: String)
        case step(message: String)
        case column(message: String)
        case invalidDate
        case missingData
        case noDataChanged
    }
    

    虽然我相信你应该检查所有 sqlite3_xxx要求错误,我个人觉得以上所有内容都有些难看。我建议包装所有 SQLite3 调用,让您摆脱困境。那里有很多。 This a thin wrapper将上面的代码简化为:
    func insert(_ book: inout Book) throws {
        let query = "INSERT INTO book (bookName, bookAuthor, bookDesc, bookDate, bookImg, createdBy) VALUES (?, ?, ?, ?, ?, ?)"
    
        let statement = try database.prepare(query, parameters: [
            book.title, book.author, book.bookDescription, book.createDate, book.image, book.createdBy
        ])
        try statement.step()
        book.id = Int(database.lastRowId())
    }
    
    func update(_ book: Book) throws {
        let query = "UPDATE Book SET bookName = ?, bookAuthor = ?, bookDesc = ?, bookDate = ?, bookImg = ?, createdBy = ? WHERE bookId = ?"
    
        let statement = try database.prepare(query, parameters: [
            book.title, book.author, book.bookDescription, book.createDate, book.image, book.createdBy, book.id
        ])
        try statement.step()
    }
    
    func delete(_ book: Book) throws {
        let query = "DELETE FROM Book WHERE bookId = ?"
        let statement = try database.prepare(query, parameters: [book.id])
        try statement.step()
    }
    
    func select(bookId: Int) throws -> Book? {
        let query = "SELECT bookId, bookName, bookAuthor, bookDesc, bookDate, bookImg, createdBy FROM Book WHERE bookId = ?"
        let statement = try database.prepare(query, parameters: [bookId])
        if try statement.step() == .row {
            return book(for: statement)
        } else {
            return nil
        }
    }
    
    func selectAll() throws -> [Book] {
        let query = "SELECT bookId, bookName, bookAuthor, bookDesc, bookDate, bookImg, createdBy FROM Book"
        let statement = try database.prepare(query)
    
        var books = [Book]()
        while try statement.step() == .row {
            if let book = book(for: statement) {
                books.append(book)
            }
        }
        return books
    }
    
    func book(for statement: Statement) -> Book? {
        guard
            let id = Int(from: statement, index: 0),
            let title = String(from: statement, index: 1),
            let author = String(from: statement, index: 2),
            let description = String(from: statement, index: 3),
            let date = Date(from: statement, index: 4),
            let data = Data(from: statement, index: 5),
            let createdBy = String(from: statement, index: 6) else {
                return nil
        }
    
        return Book(id: id, image: data, title: title, author: author, bookDescription: description, createDate: date, createdBy: createdBy)
    }
    

    关于Swift SQLite3 语法和绑定(bind),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46846769/

    有关Swift SQLite3 语法和绑定(bind)的更多相关文章

    1. ruby - 树顶语法无限循环 - 2

      我脑子里浮现出一些关于一种新编程语言的想法,所以我想我会尝试实现它。一位friend建议我尝试使用Treetop(Rubygem)来创建一个解析器。Treetop的文档很少,我以前从未做过这种事情。我的解析器表现得好像有一个无限循环,但没有堆栈跟踪;事实证明很难追踪到。有人可以指出入门级解析/AST指南的方向吗?我真的需要一些列出规则、常见用法等的东西来使用像Treetop这样的工具。我的语法分析器在GitHub上,以防有人希望帮助我改进它。class{initialize=lambda(name){receiver.name=name}greet=lambda{IO.puts("He

    2. ruby - ruby 中的 TOPLEVEL_BINDING 是什么? - 2

      它不等于主线程的binding,这个toplevel作用域是什么?此作用域与主线程中的binding有何不同?>ruby-e'putsTOPLEVEL_BINDING===binding'false 最佳答案 事实是,TOPLEVEL_BINDING始终引用Binding的预定义全局实例,而Kernel#binding创建的新实例>Binding每次封装当前执行上下文。在顶层,它们都包含相同的绑定(bind),但它们不是同一个对象,您无法使用==或===测试它们的绑定(bind)相等性。putsTOPLEVEL_BINDINGput

    3. ruby-on-rails - 使用 Sublime Text 3 突出显示 HTML 背景语法中的 ERB? - 2

      所以我在关注Railscast,我注意到在html.erb文件中,ruby代码有一个微弱的背景高亮效果,以区别于其他代码HTML文档。我知道Ryan使用TextMate。我正在使用SublimeText3。我怎样才能达到同样的效果?谢谢! 最佳答案 为SublimeText安装ERB包。假设您安装了SublimeText包管理器*,只需点击cmd+shift+P即可获得命令菜单,然后键入installpackage并选择PackageControl:InstallPackage获取包管理器菜单。在该菜单中,键入ERB并在看到包时选择

    4. ruby - 覆盖相似的方法,更短的语法 - 2

      在Ruby类中,我重写了三个方法,并且在每个方法中,我基本上做同样的事情:classExampleClassdefconfirmation_required?is_allowed&&superenddefpostpone_email_change?is_allowed&&superenddefreconfirmation_required?is_allowed&&superendend有更简洁的语法吗?如何缩短代码? 最佳答案 如何使用别名?classExampleClassdefconfirmation_required?is_a

    5. ruby 语法糖 : dealing with nils - 2

      可能已经问过了,但我找不到它。这里有2个常见的情况(对我来说,在编程Rails时......)用ruby​​编写是令人沮丧的:"astring".match(/abc(.+)abc/)[1]在这种情况下,我得到一个错误,因为字符串不匹配,因此在nil上调用[]运算符。我想找到的是比以下内容更好的替代方法:temp="astring".match(/abc(.+)abc/);temp.nil??nil:temp[1]简而言之,如果不匹配,则简单地返回nil而不会出错第二种情况是这样的:var=something.very.long.and.tedious.to.writevar=some

    6. ruby - Ruby 语法糖有 "rules"吗? - 2

      我正在学习Ruby的基础知识(刚刚开始),我遇到了Hash.[]method.它被引入a=["foo",1,"bar",2]=>["foo",1,"bar",2]Hash[*a]=>{"foo"=>1,"bar"=>2}稍加思索,我发现Hash[*a]等同于Hash.[](*a)或Hash.[]*一个。我的问题是为什么会这样。是什么让您将*a放在方括号内,是否有某种规则可以在何时何地使用“it”?编辑:我的措辞似乎造成了一些困惑。我不是在问数组扩展。我明白了。我的问题基本上是:如果[]是方法名称,为什么可以将参数放在括号内?这看起来几乎——但不完全是——就像说如果你有一个方法Foo.d

    7. ruby-on-rails - 创建 ruby​​ 数据库时惰性符号绑定(bind)失败 - 2

      我正在尝试在Rails上安装ruby​​,到目前为止一切都已安装,但是当我尝试使用rakedb:create创建数据库时,我收到一个奇怪的错误:dyld:lazysymbolbindingfailed:Symbolnotfound:_mysql_get_client_infoReferencedfrom:/Library/Ruby/Gems/1.8/gems/mysql2-0.3.11/lib/mysql2/mysql2.bundleExpectedin:flatnamespacedyld:Symbolnotfound:_mysql_get_client_infoReferencedf

    8. ruby - 如何让Ruby捕获线程中的语法错误 - 2

      我正在尝试使用ruby​​编写一个双线程客户端,一个线程从套接字读取数据并将其打印出来,另一个线程读取本地数据并将其发送到远程服务器。我发现的问题是Ruby似乎无法捕获线程内的错误,这是一个示例:#!/usr/bin/rubyThread.new{loop{$stdout.puts"hi"abc.putsefsleep1}}loop{sleep1}显然,如果我在线程外键入abc.putsef,代码将永远不会运行,因为Ruby将报告“undefinedvariableabc”。但是,如果它在一个线程内,则没有错误报告。我的问题是,如何让Ruby捕获这样的错误?或者至少,报告线程中的错误?

    9. ruby -::在 Ruby 语法中是什么意思? - 2

      这个问题在这里已经有了答案:WhatisRuby'sdouble-colon`::`?(12个答案)关闭8年前。什么是::?@song||=::TwelveDaysSong.new

    10. ruby - ruby 乘法语句中星号中断语法前的空格 - 2

      在添加一些空格以使代码更具可读性时(与上面的代码对齐),我遇到了这个:classCdefx42endendm=C.new现在这将给出“错误数量的参数”:m.x*m.x这将给出“语法错误,意外的tSTAR,期待$end”:2/m.x*m.x这里的解析器到底发生了什么?我使用Ruby1.9.2和2.1.5进行了测试。 最佳答案 *用于运算符(42*42)和参数解包(myfun*[42,42])。当你这样做时:m.x*m.x2/m.x*m.xRuby将此解释为参数解包,而不是*运算符(即乘法)。如果您不熟悉它,参数解包(有时也称为“spl

    随机推荐