String 和 Vec<T>
都拥有一片内存区域,且允许用户对其操作
还拥有元数据(例如容量等)
提供额外的功能或保障(String 保障其数据是合法的 UTF-8 编码)
Box<T>:在 heap 内存上分配值Rc<T>:启用多重所有权的引用计数类型Ref<T>和RefMut<T>,通过 RefCell<T>访问:在运行时而不是编译时强制借用规则的类型Box<T> 来指向 Heap 上的数据Box<T>Box<T> 是最简单的智能指针:
Box<T> 的常用场景Box<T>在heap上存储数据fn main() {
let b = Box::new(5);
println!("b = {}", b);
} // b 释放存在 stack 上的指针 heap上的数据
use crate::List::{Cons, Nil};
fn main() {
let list = Cons(1, Cons(2, Cons(3, Nil)));
}
enum List { // 报错
Cons(i32, List),
Nil,
}
enum Message {
Quit,
Move {x: i32, y: i32},
Write(String),
ChangeColor(i32, i32, i32),
}
use crate::List::{Cons, Nil};
fn main() {
let list = Cons(1,
Box::new(Cons(2,
Box::new(Cons(3,
Box::new(Nil))))));
}
enum List {
Cons(i32, Box<List>),
Nil,
}
fn main() {
let x = 5;
let y = &x;
assert_eq!(5, x);
assert_eq!(5, *y);
}
Box<T> 当作引用Box<T> 可以替代上例中的引用fn main() {
let x = 5;
let y = Box::new(x);
assert_eq!(5, x);
assert_eq!(5, *y);
}
Box<T> 被定义成拥有一个元素的 tuple structMyBox<T>struct MyBox<T>(T);
impl<T> MyBox<T> {
fn new(x: T) -> MyBox<T> {
MyBox(x)
}
}
fn main() {
let x = 5;
let y = MyBox::new(x); // 报错
assert_eq!(5, x);
assert_eq!(5, *y);
}
use std::ops::Deref;
struct MyBox<T>(T);
impl<T> MyBox<T> {
fn new(x: T) -> MyBox<T> {
MyBox(x)
}
}
impl<T> Deref for MyBox<T> {
type Target = T;
fn deref(&self) -> &T {
&self.0
}
}
fn main() {
let x = 5;
let y = MyBox::new(x);
assert_eq!(5, x);
assert_eq!(5, *y); // *(y.deref())
}
use std::ops::Deref;
fn hello(name: &str) {
println!("Hello, {}", name);
}
fn main() {
let m = MyBox::new(String::from("Rust"));
// &m &MyBox<String> 实现了 deref trait
// deref &String
// deref &str
hello(&m);
hello(&(*m)[..]);
hello("Rust");
}
struct MyBox<T>(T);
impl<T> MyBox<T> {
fn new(x: T) -> MyBox<T> {
MyBox(x)
}
}
impl<T> Deref for MyBox<T> {
type Target = T;
fn deref(&self) -> &T {
&self.0
}
}
fn main() {
let x = 5;
let y = MyBox::new(x);
assert_eq!(5, x);
assert_eq!(5, *y); // *(y.deref())
}
/*
* @Author: QiaoPengjun5162 qiaopengjun0@gmail.com
* @Date: 2023-04-13 21:39:51
* @LastEditors: QiaoPengjun5162 qiaopengjun0@gmail.com
* @LastEditTime: 2023-04-13 21:46:50
* @FilePath: /smart/src/main.rs
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
struct CustomSmartPointer {
data: String,
}
impl Drop for CustomSmartPointer {
fn drop(&mut self) {
println!("Dropping CustomSmartPointer with data: `{}`!", self.data);
}
}
fn main() {
let c = CustomSmartPointer {data: String::from("my stuff")};
let d = CustomSmartPointer {data: String::from("other stuff")};
println!("CustomSmartPointers created.")
}
运行
smart on master [?] is ? 0.1.0 via ? 1.67.1
➜ cargo run
Compiling smart v0.1.0 (/Users/qiaopengjun/rust/smart)
warning: unused variable: `c`
--> src/main.rs:20:9
|
20 | let c = CustomSmartPointer {data: String::from("my stuff")};
| ^ help: if this is intentional, prefix it with an underscore: `_c`
|
= note: `#[warn(unused_variables)]` on by default
warning: unused variable: `d`
--> src/main.rs:21:9
|
21 | let d = CustomSmartPointer {data: String::from("other stuff")};
| ^ help: if this is intentional, prefix it with an underscore: `_d`
warning: `smart` (bin "smart") generated 2 warnings (run `cargo fix --bin "smart"` to apply 2 suggestions)
Finished dev [unoptimized + debuginfo] target(s) in 0.53s
Running `target/debug/smart`
CustomSmartPointers created.
Dropping CustomSmartPointer with data: `other stuff`!
Dropping CustomSmartPointer with data: `my stuff`!
smart on master [?] is ? 0.1.0 via ? 1.67.1 took 3.6s
std::mem::drop 来提前 drop 值std::mem::drop 函数,来提前 drop 值struct CustomSmartPointer {
data: String,
}
impl Drop for CustomSmartPointer {
fn drop(&mut self) {
println!("Dropping CustomSmartPointer with data: `{}`!", self.data);
}
}
fn main() {
let c = CustomSmartPointer {data: String::from("my stuff")};
drop(c);
let d = CustomSmartPointer {data: String::from("other stuff")};
println!("CustomSmartPointers created.")
}
Rc<T>:引用计数智能指针Rc<T> 引用计数智能指针Rc<T>
Rc<T>使用场景Rc<T> 只能用于单线程场景Rc<T> 不在预导入模块(prelude)Rc::clone(&a) 函数:增加引用计数Rc::strong_count(&a):获得引用计数
Rc::weak_count 函数/*
* @Author: QiaoPengjun5162 qiaopengjun0@gmail.com
* @Date: 2023-04-13 22:32:41
* @LastEditors: QiaoPengjun5162 qiaopengjun0@gmail.com
* @LastEditTime: 2023-04-13 22:37:17
* @FilePath: /smart/src/lib.rs
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
enum List {
Cons(i32, Box<List>),
Nil,
}
use crate::List::{Cons, Nil};
fn main() {
let a = Cons(5, Box::new(Cons(10, Box::new(Nil))));
let b = Cons(3, Box::new(a));
let c = Cons(4, Box::new(a)); // 报错
}
优化修改一
/*
* @Author: QiaoPengjun5162 qiaopengjun0@gmail.com
* @Date: 2023-04-13 22:32:41
* @LastEditors: QiaoPengjun5162 qiaopengjun0@gmail.com
* @LastEditTime: 2023-04-13 22:45:15
* @FilePath: /smart/src/lib.rs
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
enum List {
Cons(i32, Rc<List>),
Nil,
}
use crate::List::{Cons, Nil};
use std::rc::Rc;
fn main() {
let a = Rc::new(Cons(5, Rc::new(Cons(10, Rc::new(Nil)))));
// a.clone() // 深度拷贝操作
let b = Cons(3, Rc::clone(&a));
let c = Cons(4, Rc::clone(&a)); //
}
优化修改二
/*
* @Author: QiaoPengjun5162 qiaopengjun0@gmail.com
* @Date: 2023-04-13 22:32:41
* @LastEditors: QiaoPengjun5162 qiaopengjun0@gmail.com
* @LastEditTime: 2023-04-13 22:51:04
* @FilePath: /smart/src/lib.rs
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
enum List {
Cons(i32, Rc<List>),
Nil,
}
use crate::List::{Cons, Nil};
use std::rc::Rc;
fn main() {
let a = Rc::new(Cons(5, Rc::new(Cons(10, Rc::new(Nil)))));
println!("count after creating a = {}", Rc::strong_count(&a));
let b = Cons(3, Rc::clone(&a));
println!("count after creating b = {}", Rc::strong_count(&a));
{
let c = Cons(4, Rc::clone(&a));
println!("count after creating c = {}", Rc::strong_count(&a));
}
println!("count after c goes of scope = {}", Rc::strong_count(&a));
}
Rc::clone() vs 类型的 clone() 方法Rc::clone():增加引用,不会执行数据的深度拷贝操作Rc<T>Rc<T> 通过不可变引用,使你可以在程序不同部分之间共享只读数据
但是,如何允许数据变化呢?
RefCell<T> 和内部可变性RefCell<T>Rc<T> 不同, RefCell<T> 类型代表了其持有数据的唯一所有权。RefCell<T> 与 Box<T> 的区别Box<T>
RefCell<T>
编译阶段
运行时
RefCell<T>Rc<T>相似,只能用于单线程场景Box<T>、Rc<T>、RefCell<T>的依据| 说明 | Box<T> |
Rc<T> |
RefCell<T> |
|---|---|---|---|
| 同一数据的所有者 | 一个 | 多个 | 一个 |
| 可变性、借用检查 | 可变、不可变借用(编译时检查) | 不可变借用(编译时检查) | 可变、不可变借用(运行时检查) |
RefCell<T>本身不可变,但仍能修改其中存储的值fn main() {
let x = 5;
let y = &mut x; // 报错 cannot borrow as mutable
}
例子:
pub trait Message {
fn send(&self, msg: &str);
}
pub struct LimitTracker<'a, T: 'a + Message> {
messenger: &'a T,
value: usize,
max: usize,
}
impl<'a, T> LimitTracker<'a, T>
where
T: Messenger,
{
pub fn new(messenger: &T, value: usize) -> LimitTracker<T> {
LimitTracker {
messenger,
value: 0,
max,
}
}
pub fn set_value(&mut self, value: usize) {
self.value = value;
let percentage_of_max = self.value as f64 / self.max as f64;
if percentage_of_max >= 1.0 {
self.messenger.send("Error: You are over your quota!");
} else if percentage_of_max >= 0.9 {
self.messenger
.send("Urgent warning: You're used up over 90% of your quota!");
} else if percentage_of_max >= 0.75 {
self.messenger
.send("Warning: You're used up over 75% of your quota!");
}
}
}
#[cfg(test)]
mod tests {
use super::*;
struct MockMessenger {
sent_messages: Vec<String>,
}
impl MockMessenger {
fn new() -> MockMessenger {
MockMessenger {
sent_messages: vec![],
}
}
}
impl Messenger for MockMessenger {
fn send(&mut self, message: &str) { // 报错
self.sent_messages.push(String::from(message));
}
}
#[test]
fn it_sends_an_over_75_percent_warning_message() {
let mock_messenger = MockMessenger::new();
let mut limit_tracker = LimitTracker::new(&mock_messenger, 100);
limit_tracker.set_value(80);
assert_eq!(mock_messenger.sent_messages.len(), 1);
}
}
修改之后:
pub trait Message {
fn send(&self, msg: &str);
}
pub struct LimitTracker<'a, T: 'a + Message> {
messenger: &'a T,
value: usize,
max: usize,
}
impl<'a, T> LimitTracker<'a, T>
where
T: Messenger,
{
pub fn new(messenger: &T, value: usize) -> LimitTracker<T> {
LimitTracker {
messenger,
value: 0,
max,
}
}
pub fn set_value(&mut self, value: usize) {
self.value = value;
let percentage_of_max = self.value as f64 / self.max as f64;
if percentage_of_max >= 1.0 {
self.messenger.send("Error: You are over your quota!");
} else if percentage_of_max >= 0.9 {
self.messenger
.send("Urgent warning: You're used up over 90% of your quota!");
} else if percentage_of_max >= 0.75 {
self.messenger
.send("Warning: You're used up over 75% of your quota!");
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::cell::RefCell;
struct MockMessenger {
sent_messages: RefCell<Vec<String>>,
}
impl MockMessenger {
fn new() -> MockMessenger {
MockMessenger {
sent_messages: RefCell::new(vec![]),
}
}
}
impl Messenger for MockMessenger {
fn send(&self, message: &str) { // 报错
self.sent_messages.borrow_mut().push(String::from(message));
}
}
#[test]
fn it_sends_an_over_75_percent_warning_message() {
let mock_messenger = MockMessenger::new();
let mut limit_tracker = LimitTracker::new(&mock_messenger, 100);
limit_tracker.set_value(80);
assert_eq!(mock_messenger.sent_messages.borrow().len(), 1);
}
}
RefCell<T>在运行时记录借用信息Ref<T>,它实现了 DerefRefMut<T>,它实现了 DerefRefCell<T> 会记录当前存在多少个活跃的 Ref<T> 和 RefMut<T> 智能指针:
Ref<T>的值离开作用域被释放时:不可变借用计数减1RefMut<T> 的值离开作用域被释放时:可变借用计数减1Rc<T> 和 RefCell<T> 结合使用来实现一个拥有多重所有权的可变数据#[derive(Debug)]
enum List {
Cons(Rc<RefCell<i32>>, Rc<List>),
Nil,
}
use crate::List::{Cons, Nil};
use std::rc::Rc;
use std::cell::RefCell;
fn main() {
let value = Rc::new(RefCell::new(5));
let a = Rc::new(Cons(Rc::clone(&value), Rc::new(Nil)));
let b = Cons(Rc::new(RefCell::new(6)), Rc::clone(&a));
let c = Cons(Rc::new(RefCell::new(10)), Rc::clone(&a));
*value.borrow_mut() += 10;
println!("a after = {:?}", a);
println!("b after = {:?}", b);
println!("c after = {:?}", c);
}
运行
refdemo on master [?] is ? 0.1.0 via ? 1.67.1
➜ cargo run
Compiling refdemo v0.1.0 (/Users/qiaopengjun/rust/refdemo)
Finished dev [unoptimized + debuginfo] target(s) in 0.58s
Running `target/debug/refdemo`
a after = Cons(RefCell { value: 15 }, Nil)
b after = Cons(RefCell { value: 6 }, Cons(RefCell { value: 15 }, Nil))
c after = Cons(RefCell { value: 10 }, Cons(RefCell { value: 15 }, Nil))
refdemo on master [?] is ? 0.1.0 via ? 1.67.1
➜
Cell<T>:通过复制来访问数据Mutex<T>:用于实现跨线程情形下的内部可变性模式Rc<T> 和 RefCell<T>就可能创造出循环引用,从而发生内存泄漏:
use crate::List::{Cons, Nil};
use std::cell::RefCell;
use std::rc::Rc;
#[derive(Debug)]
enum List {
Cons(i32, RefCell<Rc<List>>),
Nil,
}
impl List {
fn tail(&self) -> Option<&RefCell<Rc<List>>> {
match self {
Cons(_, item) => Some(item),
Nil => None,
}
}
}
fn main() {
let a = Rc::new(Cons(5, RefCell::new(Rc::new(Nil))));
println!("a initial rc count = {}", Rc::strong_count(&a));
println!("a next item = {:?}", a.tail());
let b = Rc::new(Cons(10, RefCell::new(Rc::clone(&a))));
println!("a rc count after b creation = {}", Rc::strong_count(&a));
println!("b initial rc count = {}", Rc::strong_count(&b));
println!("b next item = {:?}", b.tail());
if let Some(link) = a.tail() {
*link.borrow_mut() = Rc::clone(&b);
}
println!("b rc count after changing a = {}", Rc::strong_count(&b));
println!("a rc count after changing a = {}", Rc::strong_count(&a));
// Uncomment the next line to see that we have a cycle;
// it will overflow the stack.
// println!("a next item = {:?}", a.tail());
}
Rc<T>换成Weak<T>Rc::clone为Rc<T>实例的 strong_count 加1,Rc<T>的实例只有在 strong_count 为0的时候才会被清理Rc<T>实例通过调用Rc::downgrade方法可以创建值的 Weak Reference (弱引用)
Weak<T>(智能指针)Rc::downgrade会为 weak_count 加 1Rc<T>使用 weak_count 来追踪存在多少Weak<T>Rc<T>实例的清理Rc<T>实例的所有权Weak<T>前,需保证它指向的值仍然存在:
Weak<T>实例上调用 upgrade 方法,返回Option<Rc<T>>use std::rc::Rc;
use std::cell::RefCell;
#[derive(Debug)]
struct Node {
value: i32,
children: RefCell<Vec<Rc<Node>>>,
}
fn main() {
let leaf = Rc::new(Node {
value: 3,
children: RefCell::new(vec![]),
});
let branch = Rc::new(Node {
value: 5,
children: RefCell::new(vec![Rc::clone(&leaf)]),
});
}
修改后:
use std::rc::{ Rc, Weak };
use std::cell::RefCell;
#[derive(Debug)]
struct Node {
value: i32,
parent: RefCell<Weak<Node>>,
children: RefCell<Vec<Rc<Node>>>,
}
fn main() {
let leaf = Rc::new(Node {
value: 3,
parent: RefCell::new(Weak::new()),
children: RefCell::new(vec![]),
});
println!("leaf parent - {:?}", leaf.parent.borrow().upgrade());
let branch = Rc::new(Node {
value: 5,
parent: RefCell::new(Weak::new()),
children: RefCell::new(vec![Rc::clone(&leaf)]),
});
*leaf.parent.borrow_mut() = Rc::downgrade(&branch);
println!("leaf parent = {:?}", leaf.parent.borrow().upgrade());
}
修改后:
use std::rc::{ Rc, Weak };
use std::cell::RefCell;
#[derive(Debug)]
struct Node {
value: i32,
parent: RefCell<Weak<Node>>,
children: RefCell<Vec<Rc<Node>>>,
}
fn main() {
let leaf = Rc::new(Node {
value: 3,
parent: RefCell::new(Weak::new()),
children: RefCell::new(vec![]),
});
println!(
"leaf strong = {}, weak = {}",
Rc::strong_count(&leaf),
Rc::weak_count(&leaf),
);
{
let branch = Rc::new(Node {
value: 5,
parent: RefCell::new(Weak::new()),
children: RefCell::new(vec![Rc::clone(&leaf)]),
});
*leaf.parent.borrow_mut() = Rc::downgrade(&branch);
println!(
"leaf strong = {}, weak = {}",
Rc::strong_count(&branch),
Rc::weak_count(&branch),
);
println!(
"leaf strong = {}, weak = {}",
Rc::strong_count(&leaf),
Rc::weak_count(&leaf),
);
}
println!("leaf parent = {:?}", leaf.parent.borrow().upgrade());
println!(
"leaf strong = {}, weak = {}",
Rc::strong_count(&leaf),
Rc::weak_count(&leaf),
);
}
我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚
几个月前,我读了一篇关于rubygem的博客文章,它可以通过阅读代码本身来确定编程语言。对于我的生活,我不记得博客或gem的名称。谷歌搜索“ruby编程语言猜测”及其变体也无济于事。有人碰巧知道相关gem的名称吗? 最佳答案 是这个吗:http://github.com/chrislo/sourceclassifier/tree/master 关于ruby-寻找通过阅读代码确定编程语言的rubygem?,我们在StackOverflow上找到一个类似的问题:
?博客主页:https://xiaoy.blog.csdn.net?本文由呆呆敲代码的小Y原创,首发于CSDN??学习专栏推荐:Unity系统学习专栏?游戏制作专栏推荐:游戏制作?Unity实战100例专栏推荐:Unity实战100例教程?欢迎点赞?收藏⭐留言?如有错误敬请指正!?未来很长,值得我们全力奔赴更美好的生活✨------------------❤️分割线❤️-------------------------
嗨~大家好,这里是可莉!今天给大家带来的是7个C语言的经典基础代码~那一起往下看下去把【程序一】打印100到200之间的素数#includeintmain(){ inti; for(i=100;i 【程序二】输出乘法口诀表#includeintmain(){inti;for(i=1;i 【程序三】判断1000年---2000年之间的闰年#includeintmain(){intyear;for(year=1000;year 【程序四】给定两个整形变量的值,将两个值的内容进行交换。这里提供两种方法来进行交换,第一种为创建临时变量来进行交换,第二种是不创建临时变量而直接进行交换。1.创建临时变量来
网络编程套接字网络编程基础知识理解源`IP`地址和目的`IP`地址理解源MAC地址和目的MAC地址认识端口号理解端口号和进程ID理解源端口号和目的端口号认识`TCP`协议认识`UDP`协议网络字节序socket编程接口`sockaddr``UDP`网络程序服务器端代码逻辑:需要用到的接口服务器端代码`udp`客户端代码逻辑`udp`客户端代码`TCP`网络程序服务器代码逻辑多个版本服务器单进程版本多进程版本多线程版本线程池版本服务器端代码客户端代码逻辑客户端代码TCP协议通讯流程TCP协议的客户端/服务器程序流程三次握手(建立连接)数据传输四次挥手(断开连接)TCP和UDP对比网络编程基础知识
目录前言滤波电路科普主要分类实际情况单位的概念常用评价参数函数型滤波器简单分析滤波电路构成低通滤波器RC低通滤波器RL低通滤波器高通滤波器RC高通滤波器RL高通滤波器部分摘自《LC滤波器设计与制作》,侵权删。前言最近需要学习放大电路和滤波电路,但是由于只在之前做音乐频谱分析仪的时候简单了解过一点点运放,所以也是相当从零开始学习了。滤波电路科普主要分类滤波器:主要是从不同频率的成分中提取出特定频率的信号。有源滤波器:由RC元件与运算放大器组成的滤波器。可滤除某一次或多次谐波,最普通易于采用的无源滤波器结构是将电感与电容串联,可对主要次谐波(3、5、7)构成低阻抗旁路。无源滤波器:无源滤波器,又称
@作者:SYFStrive @博客首页:HomePage📜:微信小程序📌:个人社区(欢迎大佬们加入)👉:社区链接🔗📌:觉得文章不错可以点点关注👉:专栏连接🔗💃:感谢支持,学累了可以先看小段由小胖给大家带来的街舞👉微信小程序(🔥)目录自定义组件-behaviors 1、什么是behaviors 2、behaviors的工作方式 3、创建behavior 4、导入并使用behavior 5、behavior中所有可用的节点 6、同名字段的覆盖和组合规则总结最后自定义组件-behaviors 1、什么是behaviorsbehaviors是小程序中,用于实现
遍历文件夹我们通常是使用递归进行操作,这种方式比较简单,也比较容易理解。本文为大家介绍另一种不使用递归的方式,由于没有使用递归,只用到了循环和集合,所以效率更高一些!一、使用递归遍历文件夹整体思路1、使用File封装初始目录,2、打印这个目录3、获取这个目录下所有的子文件和子目录的数组。4、遍历这个数组,取出每个File对象4-1、如果File是否是一个文件,打印4-2、否则就是一个目录,递归调用代码实现publicclassSearchFile{publicstaticvoidmain(String[]args){//初始目录Filedir=newFile("d:/Dev");Datebeg
ES一、简介1、ElasticStackES技术栈:ElasticSearch:存数据+搜索;QL;Kibana:Web可视化平台,分析。LogStash:日志收集,Log4j:产生日志;log.info(xxx)。。。。使用场景:metrics:指标监控…2、基本概念Index(索引)动词:保存(插入)名词:类似MySQL数据库,给数据Type(类型)已废弃,以前类似MySQL的表现在用索引对数据分类Document(文档)真正要保存的一个JSON数据{name:"tcx"}二、入门实战{"name":"DESKTOP-1TSVGKG","cluster_name":"elasticsear
我完全不是程序员,正在学习使用Ruby和Rails框架进行编程。我目前正在使用Ruby1.8.7和Rails3.0.3,但我想知道我是否应该升级到Ruby1.9,因为我真的没有任何升级的“遗留”成本。缺点是什么?我是否会遇到与普通gem的兼容性问题,或者甚至其他我不太了解甚至无法预料的问题? 最佳答案 你应该升级。不要坚持从1.8.7开始。如果您发现不支持1.9.2的gem,请避免使用它们(因为它们很可能不被维护)。如果您对gem是否兼容1.9.2有任何疑问,您可以在以下位置查看:http://www.railsplugins.or