我最近 - 非常最近 - 开始学习如何为 iOS 编程,并且被 SQLite3 中似乎(对我来说)明显的疏忽所困扰。让我来证明一下,在上周之前我对 Mac、Objective C、Xcode、iOS 或 SQLite 的(实践)经验为零,所以我没有妄想进入久经考验的工具领域并发现明显的错误在我的第一次尝试中。我认为有一个很好的解释。
然而,在过去几个月使用 SQL Server、MySQL 和 PostgreSQL 之后,我惊讶地发现 SQLite 没有更好的按名称添加参数的功能。我可以在网上找到的所有内容(文档、论坛 [包括 SO])都说使用整数索引分配参数,如果您修改查询,这似乎很难维护。即使您可以在语句中命名参数并执行类似
的操作sqlite3_bind_int(stmt, sqlite3_bind_parameter_index(stmt, "@my_param"), myInt);
似乎也没有人这样做。事实上,似乎根本没有人尝试将其自动化;唯一alternate approach我可以找到使用的参数数组和循环计数器,并检查每个参数以确定要插入的对象类型。我最初考虑过类似的方法,但是 a) 我老板的立场是数据库参数应该始终进行类型检查(我同意,尽管我意识到 SQLite 字段不是强类型的,而且我在技术上无论如何都可以做到),b) 它感觉像是一个不雅的 hack,并且 c) 我认为这种方法没有被广泛使用是有原因的。所以:
1) 为什么 SQLite 中没有接受参数名称(例如,'const char')的绑定(bind)方法?或者有没有我遗漏了什么?
2) 为什么似乎没有人使用像上面示例那样的方法?
我深入研究了源代码,认为我可以轻松地修改库或编写自己的(类型化的)类方法来为我执行上述操作,但我假设没有人构建它是有原因的进入 SQLite 呢。我唯一的猜测是,查找参数索引所需的额外内存和周期对于 [在此处插入 iDevice] 来说太宝贵了,不值得使用参数名称带来的便利。 . . ?
如有任何见解,我们将不胜感激。
最佳答案
有;这是 sqlite3_bind_parameter_index()您提到的用于将参数名称转换为索引的函数,然后您可以将其与 sqlite3_bind_*() 一起使用功能。但是,没有 sqlite3_bind_*_by_name() 函数或类似的东西。这是为了帮助防止 API 膨胀。人气Flying Meat Database sqlite wrapper如果您有兴趣了解它的使用方式,它的一个分支中支持命名参数。
如果您考虑实现全命名参数绑定(bind)方法需要什么,请考虑当前的 bind 函数列表:
int sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int n, void(*)(void*));
int sqlite3_bind_double(sqlite3_stmt*, int, double);
int sqlite3_bind_int(sqlite3_stmt*, int, int);
int sqlite3_bind_int64(sqlite3_stmt*, int, sqlite3_int64);
int sqlite3_bind_null(sqlite3_stmt*, int);
int sqlite3_bind_text(sqlite3_stmt*, int, const char*, int n, void(*)(void*));
int sqlite3_bind_text16(sqlite3_stmt*, int, const void*, int, void(*)(void*));
int sqlite3_bind_value(sqlite3_stmt*, int, const sqlite3_value*);
int sqlite3_bind_zeroblob(sqlite3_stmt*, int, int n);
如果我们想添加对命名参数的显式支持,该列表的长度将加倍以包括:
int sqlite3_bind_name_blob(sqlite3_stmt*, const char*, const void*, int n, void(*)(void*));
int sqlite3_bind_name_double(sqlite3_stmt*, const char*, double);
int sqlite3_bind_name_int(sqlite3_stmt*, const char*, int);
int sqlite3_bind_name_int64(sqlite3_stmt*, const char*, sqlite3_int64);
int sqlite3_bind_name_null(sqlite3_stmt*, const char*);
int sqlite3_bind_name_text(sqlite3_stmt*, const char*, const char*, int n, void(*)(void*));
int sqlite3_bind_name_text16(sqlite3_stmt*, const char*, const void*, int, void(*)(void*));
int sqlite3_bind_name_value(sqlite3_stmt*, const char*, const sqlite3_value*);
int sqlite3_bind_name_zeroblob(sqlite3_stmt*, const char*, int n);
两倍的功能意味着更多的时间花在维护 API、确保向后兼容性等方面。然而,通过简单地引入 sqlite3_bind_parameter_index(),他们能够添加对命名的完整支持只有一个单一函数的参数。这意味着如果他们决定支持新的绑定(bind)类型(可能是 sqlite3_bind_int128?),他们只需添加一个函数,而不是两个。
至于为什么似乎没有人使用它...我无法通过调查给出任何明确的答案。我的猜测 是按顺序引用参数更自然一些,在这种情况下命名参数就没那么有用了。命名参数似乎只有在您需要乱序引用参数时才有用。
关于objective-c - 直接通过名称绑定(bind) SQLite 参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7508107/
类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc
exe应该在我打开页面时运行。异步进程需要运行。有什么方法可以在ruby中使用两个参数异步运行exe吗?我已经尝试过ruby命令-system()、exec()但它正在等待过程完成。我需要用参数启动exe,无需等待进程完成是否有任何rubygems会支持我的问题? 最佳答案 您可以使用Process.spawn和Process.wait2:pid=Process.spawn'your.exe','--option'#Later...pid,status=Process.wait2pid您的程序将作为解释器的子进程执行。除
我有一些Ruby代码,如下所示:Something.createdo|x|x.foo=barend我想编写一个测试,它使用double代替block参数x,这样我就可以调用:x_double.should_receive(:foo).with("whatever").这可能吗? 最佳答案 specify'something'dox=doublex.should_receive(:foo=).with("whatever")Something.should_receive(:create).and_yield(x)#callthere
我已经从我的命令行中获得了一切,所以我可以运行rubymyfile并且它可以正常工作。但是当我尝试从sublime中运行它时,我得到了undefinedmethod`require_relative'formain:Object有人知道我的sublime设置中缺少什么吗?我正在使用OSX并安装了rvm。 最佳答案 或者,您可以只使用“require”,它应该可以正常工作。我认为“require_relative”仅适用于ruby1.9+ 关于ruby-主要:Objectwhenrun
它不等于主线程的binding,这个toplevel作用域是什么?此作用域与主线程中的binding有何不同?>ruby-e'putsTOPLEVEL_BINDING===binding'false 最佳答案 事实是,TOPLEVEL_BINDING始终引用Binding的预定义全局实例,而Kernel#binding创建的新实例>Binding每次封装当前执行上下文。在顶层,它们都包含相同的绑定(bind),但它们不是同一个对象,您无法使用==或===测试它们的绑定(bind)相等性。putsTOPLEVEL_BINDINGput
我正在为一个项目制作一个简单的shell,我希望像在Bash中一样解析参数字符串。foobar"helloworld"fooz应该变成:["foo","bar","helloworld","fooz"]等等。到目前为止,我一直在使用CSV::parse_line,将列分隔符设置为""和.compact输出。问题是我现在必须选择是要支持单引号还是双引号。CSV不支持超过一个分隔符。Python有一个名为shlex的模块:>>>shlex.split("Test'helloworld'foo")['Test','helloworld','foo']>>>shlex.split('Test"
我不确定传递给方法的对象的类型是否正确。我可能会将一个字符串传递给一个只能处理整数的函数。某种运行时保证怎么样?我看不到比以下更好的选择:defsomeFixNumMangler(input)raise"wrongtype:integerrequired"unlessinput.class==FixNumother_stuffend有更好的选择吗? 最佳答案 使用Kernel#Integer在使用之前转换输入的方法。当无法以任何合理的方式将输入转换为整数时,它将引发ArgumentError。defmy_method(number)
如果您尝试在Ruby中的nil对象上调用方法,则会出现NoMethodError异常并显示消息:"undefinedmethod‘...’fornil:NilClass"然而,有一个tryRails中的方法,如果它被发送到一个nil对象,它只返回nil:require'rubygems'require'active_support/all'nil.try(:nonexisting_method)#noNoMethodErrorexceptionanymore那么try如何在内部工作以防止该异常? 最佳答案 像Ruby中的所有其他对象
两者都可以defsetup(options={})options.reverse_merge:size=>25,:velocity=>10end和defsetup(options={}){:size=>25,:velocity=>10}.merge(options)end在方法的参数中分配默认值。问题是:哪个更好?您更愿意使用哪一个?在性能、代码可读性或其他方面有什么不同吗?编辑:我无意中添加了bang(!)...并不是要询问nobang方法与bang方法之间的区别 最佳答案 我倾向于使用reverse_merge方法:option
我有一个只接受一个参数的方法:defmy_method(number)end如果使用number调用方法,我该如何引发错误??通常,我如何定义方法参数的条件?比如我想在调用的时候报错:my_method(1) 最佳答案 您可以添加guard在函数的开头,如果参数无效则引发异常。例如:defmy_method(number)failArgumentError,"Inputshouldbegreaterthanorequalto2"ifnumbereputse.messageend#=>Inputshouldbegreaterthano