星期三, 十二月 02, 2015

pyqt 5定制数据模型/Custom data model

目的:qml中combobox的Model用python实现 Model,并通过QML显示出来
要点:qt 5已经改变了roleNames方法,字符串需要用原始ascll 码,字符串前面加b来实现改点;
数据项目必须扩展来自pyqt 5的object.

ListModel.py
from PyQt5 import QtCore, QtGui
from PyQt5.QtCore import QAbstractListModel, QModelIndex, Qt, QUrl, QVariant
                   
class LottoListModel(QtCore.QAbstractListModel):
    titleRole = Qt.UserRole + 1
    def __init__(self, parent=None):
        super(LottoListModel, self).__init__(parent)

        self.items = []
    def roleNames(self):
        names = {}
        names[self.titleRole] = b"title"
       # names[self.colorRole] = "color"
        return names
         
    def appendRow(self, item):
        self.items.append(item)

    def rowCount(self, parent=QtCore.QModelIndex()):
        print('rowcount.....')
        return len(self.items)

    def data(self, index, role=Qt.DisplayRole):
        print('get data....',index,'   ',role)
        try:
            item = self.items[index.row()]
        except IndexError:
            return QVariant()

        if role == self.titleRole:
            return item.title()


        return QVariant()         

class LottoListItem(object):#核心关键,必须是python object的子类作为项目
    def __init__(self, title):
        self._title = title


    def title(self):
        return self._title

main.py:
import sys
import os
from PyQt5.QtCore import QObject, QUrl, pyqtSlot, QVariant
from PyQt5.QtWidgets import QApplication
from PyQt5.QtGui import QGuiApplication
from PyQt5.QtQml import QQmlApplicationEngine
from PyQt5.QtCore import QObject, QUrl, Qt,QAbstractTableModel
from PyQt5.QtCore import  pyqtProperty,pyqtSignal
import PyQt5
import ListModel as LM
class MainApp(QObject):
     @pyqtSlot(result=QVariant)
     def getAlgorithm(self):
          self.myModel=LM.LottoListModel()
          self.myModel.appendRow(LM.LottoListItem("0001"))    
          self.myModel.appendRow(LM.LottoListItem("0002"))         
          return self.myModel;

app = QGuiApplication (sys.argv)
engine=QQmlApplicationEngine()
ctx = engine.rootContext()

engine.load(QUrl("view.qml "))
window = engine.rootObjects()[0]
_MainApp = MainApp(window)
_MainApp.logwin[str].connect(window.logger)
_MainApp.getAlgorithm();
ctx.setContextProperty("py_MainApp", _MainApp)

window.show()
sys.exit(app.exec_())

         
view.qml

import QtQuick 2.5
import QtQuick.Controls 1.4
Rectangle {
   id: myItem

     color:'red'
   width: 500; height: 500


ComboBox {
    model:py_MainApp.getAlgorithm()
    width: 200
     }
ListView {
    width: 200; height: 250

    model: myModel
    delegate: Text {title }
     }
}

星期六, 十一月 07, 2015

pyqt5 可以把Python和QT5都可以关联起来。

今天把QT5下的一个QML程序简单移植到python下,通过pyqt5,果然非常的强大。
pyqt5非常强大

星期三, 五月 27, 2015

ofbiz 用于netbeans/Eclipse 定制。

1.NetBean 8.0.2/jdk .1.8/ofbiz 13.07.02
关键一点:新建项目使用Netbeans的 Java /Java Free-Form Project,Java自由格式项目
到Ofbiz展开的目录即可。非常简单。
编译是只需要找到build.xml选择里面的各种人物,运行执行即可。

2.Eclipse4.4/jdk 1.8/ofbiz 13.07.02

https://cwiki.apache.org/confluence/display/OFBIZ/Eclipse+Tips
 
 现在的ofbiz .zip包里就应该包含了Eclipse .project文件,所以打开Ofbiz是更加容易的。
不过需要注意的是Eclipse的work space不能直接在ofbiz的展开目录上比如:
D:\apache-ofbiz-13.07.02 上打开;
打开ofbiz在Eclipse只要选择Import然后选择"Existing Project into Workspace",然后
在目录里输入:D:\apache-ofbiz-13.07.02,选择结束即可。
调试什么的参考:
https://cwiki.apache.org/confluence/display/OFBIZ/Running+and+Debugging+OFBiz+in+Eclipse

星期二, 五月 26, 2015

成功在jdk.1.8.0_45 x64/MariaDB 10.0.19_x64/安装成功ofbiz-13.07.02

ofbiz-13.07.01,有个问题,在jdk 1.8的时候,安装完demo.ant load-demo后
浏览http://127.0.0.0:8080/ecommerce的时候,页面语言菜单无法显示,出现异常。
只能降级到 jdk 1.7使用。
这个新的版本  13.07.02 这个bug修复了。并且成功在MariaDB上也就是Mysql 5.6上
安装成功!!!!!!!

漂亮。

星期五, 五月 08, 2015

QT 5.4 天龙八部 中高级提高

1The Meta-Object System
 QT核心基础概念
http://doc.qt.io/qt-5/metaobjects.html#meta-object-system
2Models and Views in Qt Quick
综合应用预览篇。
http://doc.qt.io/qt-5/qtquick-modelviewsdata-modelview.html
3Model/View Programming
QT 核心综合概念
http://doc.qt.io/qt-5/model-view-programming.html
4Using C++ Models with Qt Quick Views
综合快速引用QML/C++ 
http://doc.qt.io/qt-5/qtquick-modelviewsdata-cppmodels.html
5Writing QML Extensions with C++
 理解深入隐藏在后面的概念
http://doc.qt.io/qt-5/qtqml-tutorials-extending-qml-example.html
6Integrating QML and C++http://doc.qt.io/qt-5/qtqml-cppintegration-topic.html
7Exposing Attributes of C++ Types to QML http://doc.qt.io/qt-5/qtqml-cppintegration-exposecppattributes.html
8Defining QML Types from C++http://doc.qt.io/qt-5/qtqml-cppintegration-definetypes.html
9


 

星期四, 四月 02, 2015

QT 5 i18n sample(or example ) step by step

1.新建一个目录 
  cd c:\temp;mkdir testi18n
cd testi18n

2.新建最简单cpp
 i18n.cpp
#include <QApplication>
#include <QLabel>
#include <QTranslator>
#include <QDebug>
int main(int argc,char *argv[])
{
QApplication app(argc,argv);

    // translation file for application strings
    QTranslator translator;
   bool result= translator.load("superapp_zh_CN",":/i18n"); //这里的:/i18n 可以参考后面的 i18n.qrc 中的prefix中的对应关系
   qDebug()<<"load resource flag:"<<result;
               app.installTranslator(&translator);
                 qDebug()<<QLocale::system().name();
QLabel * label = new QLabel(QObject::tr("Hello"));//应该根据语言切换
           qDebug()<<QObject::tr("Hello"); //应该根据语言切换
label->show();
app.exec();
}
3.创建项目文件
 qmake -project //建立testi18n.pro文件
4.编辑项目文件,加入i18n 字典说明
    在testi18n.pro中加入英文和中文两个数据字典文件:
TRANSLATIONS    = superapp_en_US.ts \
                     superapp_zh_CN.ts 
5.创建资源文件
 lupdate testi18n.pro //第3步建立
  C:\temp\qt\testi18n>lupdate testi18n.pro
Updating 'superapp_en_US.ts'...
    Found 1 source text(s) (0 new and 1 already existing)
Updating 'superapp_zh_CN.ts'...
    Found 1 source text(s) (0 new and 1 already existing)

6.使用linguist来编辑翻译字典
    注意打开打开翻译翻译必须确认,也就是蓝色的对号,然后保存,如果不保存,最后生成字典二进制资源文件的时候,将不会被编译,
    直接打开.ts文件可以看到,没有点对号确认的字典项目对应 一个type="unfinished",只有确认了之后,才变成标准的
<translation type="unfinished">你好世界</translation>
 linguist里 确认后变成:
        <translation>你好世界</translation>
7.编译生成二进制字典文件
 lrelease testi18n.pro
C:\temp\qt\testi18n>lrelease testi18n.pro
Updating 'C:/temp/qt/testi18n/superapp_en_US.qm'...
    Generated 1 translation(s) (1 finished and 0 unfinished)
Updating 'C:/temp/qt/testi18n/superapp_zh_CN.qm'...
    Generated 1 translation(s) (1 finished and 0 unfinished)

8.建立资源文件i18n.qrc
  <RCC>
<qresource prefix="/i18n" > //注意prefix 是用来标明在最终二进制文件中资源文件的引用目录,可以是唯一的任意字符串
<file>superapp_en_US.qm</file>
<file>superapp_zh_CN.qm</file>
</qresource>
</RCC>
9.将资源文件加入项目文件testi18n.pro中
RESOURCES +=i18n.qrc

10.生成Makefile文件
   qmake testi18n.pro

11.编译生成.exe文件
   make

12.运行
 release\testi18n.exe


星期四, 三月 05, 2015

javafx Scene Builder 2.0 如何给anchorpane加入一个本地背景图像

通过Css来加入:
-fx-background-image:url("file:///C:/nyayanew/config/game3/bgl1f2.jpg")
类似代码:
File f = new File("C:\\nyayanew\\config\\game3\\bgl1f2.jpg");
center.setStyle("-fx-background-image:file:///" + f.getAbsolutePath().replace("\\", "/"));

星期五, 一月 23, 2015

如何在JavaFx 8里实现 Hover效果。

css 3 transform:
 .myimage:hover {
  background-color: #dae7f3;
  transform: translate(-5px,-5px);
  effect: dropshadow( three-pass-box , rgba(0,0,0,1) , 5, 0.0 , 0 , 1 );
  box-shadow: 5px 5px 15px rgba(67, 72, 84, 0.5);
}

但是javafx 8只支持css 2.1 和部分css 3的语法,恰恰transform不在此列:
不过可以通过-fx-translate-x,和draopshadow实现悬浮图片或者其他物体的效果.
在css文件中定义一下class selector,然后在JavaFX Scene Builder 2.0 设置 style class 为myButton即可.
.myButton:hover {
  -fx-effect: dropshadow( three-pass-box , rgba(0,0,0,1) , 5, 0.0 , 0 , 1 );
   -fx-translate-x: -5px;
   -fx-translate-y: -5px;
}

星期三, 一月 21, 2015

how ant task read manifest.mf from another jar file.

经常需要在打包可执行jar包的时候,将众多jar打包成一个jar包,
但是只有一个主项目的MANIFEST.MF是需要的。其他的jar包的
MANIFEST.MF都可以忽略掉。
其实很简单的方法:
        <zip destfile="final.jar">
            <zipfileset src="store/temp_final.jar"
            excludes="META-INF/*.SF, META-INF/*.DSA, META-INF/*.RSA,META-INF/MANIFEST.MF"/>
这里将其他jar包的MANIFEST.MF给去掉了。
            <zipfileset src="dist/project.jar" includes="META-INF/**"/>           
这里将project.jar里的MENIFEST.MF放到最终的jar包里
        </zip>
zipfieset 的prefix属性是用来指明最终jar包里的目录结构,这提供了更加灵活的方式。
不过这里不需要通过prefix来指明最终的jar包目录结构,如果是通过引入一个文件作为MANIFEST.MF,prefix属性就是经常需要的了。
不过一个文件就是使用<fileset >任务来引入了。


星期四, 一月 01, 2015

curl link static under windows x64 error:undefined reference to WSAIoctl@36

依然是少了link 库的原因。
加入一下库即可连接成静态库,避免错误

libwldap32.a libws2_32.a libwsock32.a \libmswsock.a

星期二, 十二月 30, 2014

Nginx+jboss session问题。

用Nginx做反向代理,Jboss做动态内容处理,或者也是集群,
就必然涉及到session的问题。
这个方法简单的,可以在Nginx设置, upstream的算法,为ip_hash,
同一个客户使用固定的jboss服务器。
另外一个就是使用jboss 实现session replication(session复制).
可以查阅手册解决之。

星期日, 十月 12, 2014

星期一, 九月 22, 2014

如何动态载入外部储存卡上的dex/jar包?

java的概念定制ClassLoader非常强大,Android提供了两个classloader来完成相关的任务.
PathClassLoader: 只能读取已经保存在系统里的jar/dex包
DexClassLoader:可以灵活读取任何权限允许的jar包。
我们设想可以读取保存在外部存储卡上的jar,更加符合实际的逻辑需要:
设计:
将动态jar包保存在/sdcard/temp/testjar.jar 文件里,在app里调用载入该包,并执行特定的方法:

1.Android Activtiy 准备动态载入相关代码:
将该方法加入到app某个菜单项目
onOptionsItemSelected方法里来调用,该app package为home.sunose假设:

public String classLoadFromExtern(Activity acivity)
{
 String result="";
 String sdcard=Environment.getExternalStorageDirectory().getAbsolutePath();
 String jarPath = sdcard
             + "/temp/testjar.jar";
String tmppath=acivity.getDir( "temp", 0).getAbsolutePath();
//注意tmppath是用来将testjar.jar展开的目录,这个目录必须属于当前app的用户id,所以必须使用
//context上下文相关的getDir得到该目录,避免没有权限的错误:
//DexClassLoader is not owned by the current user 这个异常.
//这是private DexFile(String sourceName, String outputName, int flags) throws IOException 
//的判断Libcore.os.getuid() != Libcore.os.stat(parent).st_uid

Log.d (TAG ,tmppath );
 DexClassLoader myClassLoader = new DexClassLoader (jarPath ,tmppath ,null, ClassLoader.getSystemClassLoader());
    try
     {
         Class<?>  clazz = myClassLoader .loadClass("com.test.First");
//         AIObject aio=(AIObject)clazz.newInstance();
         Method method = clazz.getDeclaredMethod("execute" ,String.class);
         method.setAccessible(true);
          result=(String)method .invoke(clazz.newInstance(), "test");
     }
     catch(Exception ex)
     {
         ex.printStackTrace();
     }
 return result;
}

2.准备桌面com.test.First.java类:
package com.test;
public class First
{
public String execute(String term)
{
String result=new java.util.Date()+" term is "+term;  
System.out.println(result);
return result;
}
}
5.mkdir com;mkdir com\test //建立标准java package目录结构,准备
6.cd c:\temp\com\test ,建立First.java,内容为步骤2内容

7.javac  com\test\First.java -d classes //编译java文件,并将编译后的class输出到c:\temp\classes目录

//准备dex打包编译的class
8.D:\Android\android-sdk-windows\build-tools\20.0.0\dx.bat  --dex --output c:\temp\testjar.jar  c:\temp\classes
9.adb push testjar.jar /sdcard/temp/  //推送到android上
10.在app中调用步骤1的方法后,adb logcat 可以看到
后台Logcat的输出:
D/dalvikvm(31581): DexOpt: --- BEGIN 'testjar.jar' (bootstrap=0) ---
D/dalvikvm(31608): DexOpt: load 5ms, verify+opt 1ms, 93356 bytes
D/dalvikvm(31581): DexOpt: --- END 'testjar.jar' (success) ---
D/dalvikvm(31581): DEX prep '/storage/emulated/0/temp/testjar.jar': unzip in 0ms, rewrite 98ms

11.也可以看到testjar.jar 实际展开后的目录:
 adb shell
ls /data/data/home.sunose/app_temp

星期一, 九月 08, 2014

嵌入在ScrollView里的GridView如何动态修改Layout 宽度? GridView In ScrollView programmatically change layout size ?

其实宽度修改都很简答。
以下伪代码:
GridView gv = this.findViewById(R.id.gridview_id);
               gv.getLayoutParams(). width = 1965;//px width
              gv.getLayoutParams(). height = LayoutParams. WRAP_CONTENT;
然后根据需要调用这个UI 刷新即可,一下两行代码可有可无. 
                   View vg =   getWindow().getDecorView().getRootView();
                   vg.invalidate();   
但是如果想给GridView加上水平滚动条则问题就有些麻烦了.需要将GridView嵌入在ScrollView或者HorizontalScrollView

<HorizontalScrollView>
 <GridView></GridView>
</HorizontalScrollView>

此时在代码中修改LayoutParams.width的方法,发现对GridView突然不起作用了.这个时候一个奇怪的技巧就起作用了.
将GridView再包围一个Layout即可。
修改为:
<HorizontalScrollView>
      <LinearLayout  
        android:layout_width="wrap_content"  
        android:layout_height="wrap_content"  
        android:orientation="vertical" >
 <GridView></GridView>
</LinearLayout>
</HorizontalScrollView>
这个技巧花费了数天才无意中发现。

星期二, 九月 02, 2014

Android 各种目录的获取。

Android 在内部rom里的存储路径和外部存储卡上的存储目录,可以通过
调用Activity的函数来获取。
Activity.getFilesDir().getAbsolutePath()得到:
   /data/data/<App Package name>/files
Activity.getExternalFilesDir(null).getAbsolutePath()得到:
/storage/emulated/0/Android/data/
<App Package name>/files
Environment.getExternalStorageDirectory().getAbsolutePath()
得到:
/storage/emulated/0

/storage/emulated/0是外部储存卡mount到系统的路劲入口,可以通过检测状态来确认是否有外部存储卡。
读取外部存储卡要在Androidmanifest.xml里加入权限:
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

星期日, 八月 31, 2014

GIMP 2.8不能编辑GIF和png图片问题

GIF和png颜色空间都是indexed,所以无法编辑。

如果想编辑必须首先转换颜色空间,这个非常容易,只要在image/颜色菜单里
选择mode(模式)即可转换




星期三, 八月 27, 2014

如何在Android里使用最新的Apache Httpclient

注意:Android最早使用的Apache HttpClient 4.0-beta的一个包,后来基本
不再维护,所以如果有更多的新的HTTP 特性,基本不再支持,
而且,Android推荐大家使用系统标准的java标准包:HttpURLConnection 
但是HttpURLConnection比较底层,使用起来非常的不便,尤其是在
    类似提交Form和服务器传送数据的时候;所以最近有okHttp就封装了HttpURLConnction
给开发人员提供了较好的API.但是使用起来依然不如HttpRequest爽快.
尤其是在目前稍微严肃的应用都会基于HTTPS/SSL的基础之上,大量的验证
模式支持就是以前的4.0版本不支持的。没有现成的方案。所以使用
  最新的httpclient包是必须的了。
但是由于httpclient是基于标准JDK的,有许多牵涉到版权的API比如
misc.sun之类的包不能在Android上使用,所以这个处理工作还是比较繁琐的。
幸运的是apache提供了Android移植包:
参考,写本文时的最新版本4.3.5:
http://hc.apache.org/httpcomponents-client-4.3.x/android-port.html
  
可以在www.mvnrepository.com上 输入httpclient-android来寻找最新的
jar包Android移植版本并下载即可。
当然有些类不可避免的原始的类的功能不同并有扩展,这个时候,就要使用
类名带HC4结尾的类来使用最新的功能特性了
 
但是如果我们在Android Activity调用Async或者Thread调用最基本的:
CloseableHttpClient httpclient = HttpClients.createDefault();
立即出现异常:
 java.lang.IllegalArgumentException: Item may not be null
  
查看代码则是:
  org.apache.http.config.RegistryBuilder.java
的  Args.notNull(item, "Item");造成了错误。
阅读代码发现,这是因为SocketFactory为空造成的,所以
必须首先初始化,SocketFactory

 SSLContext sslContext = SSLContexts.createSystemDefault();
   SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
         sslContext,
         SSLConnectionSocketFactory.STRICT_HOSTNAME_VERIFIER);
 CloseableHttpClient  httpclient= HttpClientBuilder.create()
      .setSSLSocketFactory(sslsf)
      .build();

或者使用定制的方法:

 ConnectionSocketFactory plainsf = <...>  LayeredConnectionSocketFactory sslsf = <...>  Registry<ConnectionSocketFactory> r = RegistryBuilder.<ConnectionSocketFactory>create()          .register("http", plainsf)          .register("https", sslsf)          .build();    HttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(r);  HttpClients.custom()          .setConnectionManager(cm)          .build();

这个都可以从hc.apache.org对应版本的tutorial章节,看到详细的代码

注意在android使用需要在AndroidManifest.xml里加入权限:
<uses-permission android:name="android.permission.INTERNET"/>
  这个httpclient-android-4.3.5.jar在Android Studio和Eclipse ADT
里如何打包到最后的apk里步骤不同,使用的时候注意即可。

星期四, 八月 21, 2014

Button 实现淡入淡出动画

布局文件:
activity_main.xml:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.example.buttonana.MainActivity" >
  <Button
      android:layout_marginTop="50dp"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"     
      android:id="@+id/animationid"
      android:text="fade out"/>

  <Button
      android:id="@+id/mainbtn"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:layout_alignLeft="@+id/animationid"
      android:layout_alignParentTop="true"
      android:layout_marginTop="170dp"
      android:text="Click Me" />

</RelativeLayout>

关键语句:
      amt.setFillAfter(true);//important.

package com.example.buttonana;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.Button;

public class MainActivity extends Activity {

    Button mainbtn;
    Button animationbtn;
   
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mainbtn=(Button)this.findViewById(R.id.mainbtn);
        animationbtn=(Button)this.findViewById(R.id.animationid);
        mainbtn.setOnClickListener(new View.OnClickListener() {
           
            @Override
            public void onClick(View v) {
                Log.d("BUTTON","enter.........................................................");
                Animation t =getAnimation();
                animationbtn.clearAnimation();
                animationbtn.setAnimation(t);
                t.startNow();
            }
        });
       
    }
  public Animation getAnimation()
  {
      Animation amt=new AlphaAnimation(1.0f,0.01f);
      amt.setDuration(4*1000);
      amt.setFillAfter(true);//important.
      return amt;
     
  }

}

星期二, 八月 05, 2014

gradle 调用另外一个gradle 脚本文件

gradle 0.9 之后,支持apply from: "addiontal.gradle"语法。

星期日, 八月 03, 2014

Android Studio Beta 打包源代码和build.gradle 脚本到一个zip文件

在build.gradle脚本里加入脚本:

task srcZip2(type: Zip) {
    classifier = 'src'
    from projectDir
    include 'src/**/*'
    include 'build.gradle'
    destinationDir file('.')
    archiveName "src.zip"
}


tasks.whenTaskAdded { task ->
    if (task.name == 'generateReleaseBuildConfig' || task.name == 'generateDebugBuildConfig') {
        task.dependsOn 'srcZip2'
    }
}


最后就在当前 app目录下建立了src.zip文件。

如何在Android Studio beta 版本里加入Build versionNumber的脚本。

利用AndroidManifest.xml里的android:versionCode"整数",
android:versionName为字符串,格式为"0.0.1"的格式。

将一下代码复制到build.gradle里,最后空白的地方,sync之后即可:
这是在build project的时候,即更新AndroidManifest.xml里的
这两个字段

task('increaseVersionCode') << {
    def manifestFile = file(android.sourceSets.main.manifest.srcFile)
    def pattern = Pattern.compile("versionCode=\"(\\d+)\"")
    def manifestText = manifestFile.getText()
    def matcher = pattern.matcher(manifestText)
    matcher.find()
    def versionCode = Integer.parseInt(matcher.group(1))
    versionCode= versionCode+1
    def manifestContent = matcher.replaceAll("versionCode=\"" + versionCode + "\"")
    manifestFile.write(manifestContent)
    println  "versionCode is:"+versionCode

}

task('incrementVersionName') << {
    def manifestFile = file(android.sourceSets.main.manifest.srcFile)
    def patternVersionNumber = Pattern.compile("versionName=\"(\\d+)\\.(\\d+)\\.(\\d+)\"")
    def manifestText = manifestFile.getText()
    def matcherVersionNumber = patternVersionNumber.matcher(manifestText)
    matcherVersionNumber.find()
    def majorVersion = Integer.parseInt(matcherVersionNumber.group(1))
    def minorVersion = Integer.parseInt(matcherVersionNumber.group(2))
    def buildVersion = Integer.parseInt(matcherVersionNumber.group(3))
    def mNextVersionName = majorVersion + "." + minorVersion + "." +  + (buildVersion + 1)
    def manifestContent = matcherVersionNumber.replaceAll("versionName=\"" + mNextVersionName + "\"")
    println  "build number is:"+mNextVersionName
    manifestFile.write(manifestContent)
}

tasks.whenTaskAdded { task ->
    if (task.name == 'generateReleaseBuildConfig' || task.name == 'generateDebugBuildConfig') {
        task.dependsOn 'increaseVersionCode'
        task.dependsOn 'incrementVersionName'
    }
}

星期三, 五月 28, 2014

The Rust References and Lifetimes Guide(Rust引用和生命周期指引)

The Rust References and Lifetimes Guide(Rust引用和生命周期指引)

version 0.1

1 Introduction(介绍)

References are one of the more flexible and powerful tools available in Rust. A reference can point anywhere: into the managed or exchange heap, into the stack, and even into the interior of another data structure. A reference is as flexible as a C pointer or C++ reference. However, unlike C and C++ compilers, the Rust compiler includes special static checks that ensure that programs use references safely. Another advantage of references is that they are invisible to the garbage collector, so working with references helps reduce the overhead of automatic memory management.
引用是Rust可用的超级复杂和强大的工具之一.引用可以指向任何地方:可管理或者可交换堆, 或者堆栈,甚至可以指向另外一个数据结构的内部.引用和C语言的指针和C++的引用一样复杂. 但是,不像C和C++编译器,Rust编译器包含特殊静态检查用来确保程序安全使用引用. 另外一个有点是引用对垃圾收集器是不可见的,应此使用引用可以减少自动内存回收的开销. Despite their complete safety, a reference's representation at runtime is the same as that of an ordinary pointer in a C program. They introduce zero overhead. The compiler does all safety checks at compile time.
尽管使用引用完全安全,Rust引用在运行时本质上和C程序的一般指针还是相同的 。 它们是零开销的.编译器在编译时间做安全检查. Although references have rather elaborate theoretical underpinnings (region pointers), the core concepts will be familiar to anyone who has worked with C or C++. Therefore, the best way to explain how they are used—and their limitations—is probably just to work through several examples.
虽然引用有相当精巧的理论基础(区域指针),核型概念对曾经用C或C++工作的感觉很熟悉. 因此,最好解释它们如何使用的方法以及它们的局限,可以通过几个例子来说明.

2 By example

References, sometimes known as borrowed pointers, are only valid for a limited duration. References never claim any kind of ownership over the data that they point to: instead, they are used for cases where you would like to use data for a short time.
引用有时候也称呼为 借用指针,仅仅在有限的时段内合法。 引用永远不会要求其指向数据的任何形式的所有权:替代的, 它们被用于你只在很短时间内使用数据的地方。 As an example, consider a simple struct type Point:
考虑这个例子,一个简单的数据结构:Point
struct Point {x: f64, y: f64}
We can use this simple definition to allocate points in many different ways. For example, in this code, each of these three local variables contains a point, but allocated in a different place:
我们可以使用这个简单的定义用众多不同的方法来申请点.比如,以下例子代码中,三个局部变量 每个都包含一个点point,但是在不同的地方申请:
let on_the_stack :  Point     =     Point {x: 3.0, y: 4.0};
let managed_box  : @Point     =    @Point {x: 5.0, y: 1.0};
let owned_box    : Box<Point> = box Point {x: 7.0, y: 9.0};
Suppose we wanted to write a procedure that computed the distance between any two points, no matter where they were stored. For example, we might like to compute the distance between on_the_stack and managed_box, or between managed_box and owned_box. One option is to define a function that takes two arguments of type Point—that is, it takes the points by value. But if we define it this way, calling the function will cause the points to be copied. For points, this is probably not so bad, but often copies are expensive. Worse, if the data type contains mutable fields, copying can change the semantics of your program in unexpected ways. So we'd like to define a function that takes the points by pointer. We can use references to do this:
假定我们想写一个过程计算任意两个点之间的距离,而不管它们在哪里保存.比如,我们可以计算距离: 在on_the_stack和managed_box之间或者在managed_box和owned_box之间.一个选择是定义函数有两个Point实际参数, 当然它按值传递使用.但是如何我们这样定义函数的话,调用该函数是将造成points的复制.对point来说,数据结构简单, 不是什么太糟糕的事情,但是经常的复制开销就非常昂贵了.更糟糕的是,如果数据类型包含可修改的字段,复制可以以不希望的 方式改变你程序的语义.应此我们想定义一个函数使用指针引用.我们可以使用引用这样做:
fn compute_distance(p1: &Point, p2: &Point) -> f64 {
    let x_d = p1.x - p2.x;
    let y_d = p1.y - p2.y;
    sqrt(x_d * x_d + y_d * y_d)
}
Now we can call compute_distance() in various ways:
然后我们可以用几种方法调用compute_distance()
compute_distance(&on_the_stack, managed_box);
compute_distance(managed_box, owned_box);
Here, the & operator takes the address of the variable on_the_stack; this is because on_the_stack has the type Point (that is, a struct value) and we have to take its address to get a value. We also call this borrowing the local variable on_the_stack, because we have created an alias: that is, another name for the same data.
这里&运算符表示要获取变量on_the_stack的地址;因为变量on_the_stack的类型为Point(结构值) 所以我们必须取得它的地址来得到值.我们叫这种行为为借用(borrowing)局部变量on_the_stack. 可以这样理解我们建立一个别名:同一个数据的另外一个名字. In contrast, we can pass the boxes managed_box and owned_box to compute_distance directly. The compiler automatically converts a box like @Point or ~Point to a reference like &Point. This is another form of borrowing: in this case, the caller lends the contents of the managed or owned box to the callee.
相反的,我们可以直接传递封箱managed_box(可管理封箱)和owned_box(自有封箱)到compute_distance()函数. 编译器自动转换封箱如@Point或者~Point为&Point形式的引用.这是另外一种形式的借用: 调用者借出可管理的或者自有的封箱的内容给调用被调用者。 Whenever a caller lends data to a callee, there are some limitations on what the caller can do with the original. For example, if the contents of a variable have been lent out, you cannot send that variable to another task. In addition, the compiler will reject any code that might cause the borrowed value to be freed or overwrite its component fields with values of different types (I'll get into what kinds of actions those are shortly). This rule should make intuitive sense: you must wait for a borrower to return the value that you lent it (that is, wait for the reference to go out of scope) before you can make full use of it again.
每当调用者借出数据给被调用者,关于调用者可以对原始数据做什么有一些限制. 比如,如果变量的内容已经被借用了,你就不能将变量送给(send)给另外一个任务. 此外,编译器会拒绝任何造成被借用的值被释放或者它的组件字段被不同类型的值覆盖. (我将会简短展示这些行为).这个规则可以得出直观的推测:你必须等待借用者返回值之后(也就是说,等待引用出了范围) 才可被你完全再次使用.

3 Other uses for the & operator(引用&操作符的其他用法)

In the previous example, the value on_the_stack was defined like so:
在前面的例子里,on_the_stack的值是这样被定义的:
let on_the_stack: Point = Point {x: 3.0, y: 4.0};
This declaration means that code can only pass Point by value to other functions. As a consequence, we had to explicitly take the address of on_the_stack to get a reference. Sometimes however it is more convenient to move the & operator into the definition of on_the_stack:
这个声明意思是代码只能根据值来转递Point.因此,我们必须显示的获取on_the_stack的地址来得到引用. 有时候更常用的方法是将&运算符移到on_the_stack定义的前面.
let on_the_stack2: &Point = &Point {x: 3.0, y: 4.0};
Applying & to an rvalue (non-assignable location) is just a convenient shorthand for creating a temporary and taking its address. A more verbose way to write the same code is:
使用&给一个右值(不可复制的位置)是用来建立一个临时变量获取数据的地址更方便的快捷方法; 更累赘的代码方法可以这样写:
let tmp = Point {x: 3.0, y: 4.0};
let on_the_stack2 : &Point = &tmp;

4 Taking the address of fields(获取字段的地址)

As in C, the & operator is not limited to taking the address of local variables. It can also take the address of fields or individual array elements. For example, consider this type definition for rectangle:
如同在C语言里一样,&运算符不只限于获取局部变量的地址.它也可以取得字段的地址或者个别数组元素的地址. 比如,考虑这个类型rectangle的定义:
struct Point {x: f64, y: f64} // as before
struct Size {w: f64, h: f64} // as before
struct Rectangle {origin: Point, size: Size}
Now, as before, we can define rectangles in a few different ways:
现在,向前一个例子一样,我们也用几种不同的方法来定义rectangles:
let rect_stack   =    &Rectangle {origin: Point {x: 1.0, y: 2.0},
                                  size: Size {w: 3.0, h: 4.0}};
let rect_managed =    @Rectangle {origin: Point {x: 3.0, y: 4.0},
                                  size: Size {w: 3.0, h: 4.0}};
let rect_owned   = box Rectangle {origin: Point {x: 5.0, y: 6.0},
                                  size: Size {w: 3.0, h: 4.0}};
In each case, we can extract out individual subcomponents with the & operator. For example, I could write:
每一个例子中,我们都可以使用&预算符来提取独立的子组件.比如,如此写代码:
compute_distance(&rect_stack.origin, &rect_managed.origin);
which would borrow the field origin from the rectangle on the stack as well as from the managed box, and then compute the distance between them.
我们从堆栈里的rectangle借用origin字段,同样从可管理的封箱借用origin,然后计算它们的距离.

5 Borrowing managed boxes and rooting(借用可管理的封箱及生根)

We’ve seen a few examples so far of borrowing heap boxes, both managed and owned. Up till this point, we’ve glossed over issues of safety. As stated in the introduction, at runtime a reference is simply a pointer, nothing more. Therefore, avoiding C's problems with dangling pointers requires a compile-time safety check.
至此我们看到一部分例子关于借用堆封箱 包括可管理的封箱以及自有的封箱. 直到现在,我们忽略了有关安全的问题.诚如介绍,在运行时参考就是一个简单指针,没有其他东西. 因此,避免C语言的问题悬空指针问题就要求编译时间的安全检查. The basis for the check is the notion of lifetimes. A lifetime is a static approximation of the span of execution during which the pointer is valid: it always corresponds to some expression or block within the program. Code inside that expression can use the pointer without restrictions. But if the pointer escapes from that expression (for example, if the expression contains an assignment expression that assigns the pointer to a mutable field of a data structure with a broader scope than the pointer itself), the compiler reports an error. We'll be discussing lifetimes more in the examples to come, and a more thorough introduction is also available.
检查的基本概念就是生命周期.声明周期是静态近似于执行的跨度,在这个时间内指针是合法的: 这个总是对应着程序里的一些表达式或者块.在表达式里代码可以没有约束的使用指针. 如果指针在表达式里被放弃(比如,如果表达式包含一个复制表达式将指针赋予一个数据结构里可变的字段, 该字段的范围比指针本身更广),那么编译器就报告一个错误.我们将会讨论更多的生命周期的列子, 可得到更加深入的解释. When the & operator creates a reference, the compiler must ensure that the pointer remains valid for its entire lifetime. Sometimes this is relatively easy, such as when taking the address of a local variable or a field that is stored on the stack:
当&运算符建立一个应用,编译器必须确认该指针在其生命周期内保持合法。 有时候这个相对容易,比如当获取一个局部变量或者储存在堆栈字段地址:
struct X { f: int }
fn example1() {
    let mut x = X { f: 3 };
    let y = &mut x.f;  // -+ L
    // ...             //  |
}                      // -+
Here, the lifetime of the reference y is simply L, the remainder of the function body. The compiler need not do any other work to prove that code will not free x.f. This is true even if the code mutates x.
这里来看,引用y的生命周期简单的保持在从L开始保存在函数主体里.编译器无需做任何事情证明代码将不会释放x.f. 这一点甚至在代码修改x的时候也值正确的。 The situation gets more complex when borrowing data inside heap boxes:
状态开始变得更加复杂的情况是当在堆封箱里借用数据时:
fn example2() {
    let mut x = @X { f: 3 };
    let y = &x.f;      // -+ L
    // ...             //  |
}                      // -+
In this example, the value x is a heap box, and y is therefore a pointer into that heap box. Again the lifetime of y is L, the remainder of the function body. But there is a crucial difference: suppose x were to be reassigned during the lifetime L? If the compiler isn't careful, the managed box could become unrooted, and would therefore be subject to garbage collection. A heap box that is unrooted is one such that no pointer values in the heap point to it. It would violate memory safety for the box that was originally assigned to x to be garbage-collected, since a non-heap pointer y still points into it.
这个例子里,x的值是个堆封箱(managed box),y是个指针指向堆封箱.当然y的生命周期是L,在函数剩余主体里保持. 但是这里有一个关键的区别:假定x在声明周期L?被重新赋值,如果编译器不仔细,可管理的封箱将变成无根unrooted, 应此导致被垃圾回收.堆封箱无根是说没有一个在堆上指针指向它.这将违反有关原始的封箱x被内存回收的内存安全, 因为虽然没有堆指针,但依然有一个非堆指针y依然指向它.
Note: Our current implementation implements the garbage collector using reference counting and cycle detection.
For this reason, whenever an & expression borrows the interior of a managed box stored in a mutable location, the compiler inserts a temporary that ensures that the managed box remains live for the entire lifetime. So, the above example would be compiled as if it were written
由于这个理由,无论如何一个&表达式借用可管理的封箱内部并储存在可变的地点,编译器插入 一个临时变量用来确保可管理的封箱在整个生命周期保持存活.因此上面的例子可以编译为如下所写:
fn example2() {
    let mut x = @X {f: 3};
    let x1 = x;
    let y = &x1.f;     // -+ L
    // ...             //  |
}                      // -+
Now if x is reassigned, the pointer y will still remain valid. This process is called rooting.
现在即使x被重新赋值,指针y依然保持合法.这个处理过程被叫做生根。

6 Borrowing owned boxes(借用自有的封箱)

The previous example demonstrated rooting, the process by which the compiler ensures that managed boxes remain live for the duration of a borrow. Unfortunately, rooting does not work for borrows of owned boxes, because it is not possible to have two references to an owned box.
前一个例子演示了rooting生根,这个处理是编译器为了保证可管理的封箱在借用时段内保持存活. 不幸的是,生根(rooting)在借用自有的封箱上不能使用.因为不可能有两个引用到一个自有的封箱. For owned boxes, therefore, the compiler will only allow a borrow if the compiler can guarantee that the owned box will not be reassigned or moved for the lifetime of the pointer. This does not necessarily mean that the owned box is stored in immutable memory. For example, the following function is legal:
对自有的封箱来说,编译器只允许一次借用.如果编译可以担保自有的封箱在声明周期内不会被重新赋值或者移动. 这就意味着没必要储存自有的封箱在不可变内存上.比如,下面的函数是合法的:
fn example3() -> int {
    let mut x = box Foo {f: 3};
    if some_condition() {
        let y = &x.f;      // -+ L
        return *y;         //  |
    }                      // -+
    x = box Foo {f: 4};
    // ...
}
Here, as before, the interior of the variable x is being borrowed and x is declared as mutable. However, the compiler can prove that x is not assigned anywhere in the lifetime L of the variable y. Therefore, it accepts the function, even though x is mutable and in fact is mutated later in the function.
这里同之前一样,内部变量x被借用并且x被声明为可变的.但是编译器可以证明x在变量y的生命周期L内没有被赋值. 因此,它认为这个函数合法,甚至x在函数的后面实际上被修改了。 It may not be clear why we are so concerned about mutating a borrowed variable. The reason is that the runtime system frees any owned box as soon as its owning reference changes or goes out of scope. Therefore, a program like this is illegal (and would be rejected by the compiler):
当然这个例子也不能表明为什么我们那么关心修改一个被借用的变量.理由是运行时系统是尽快的释放自有的封箱, 如果它自己的引用被修改或者出了范围.因此程序看起来是非法的(被编译器拒绝).
fn example3() -> int {
    let mut x = box X {f: 3};
    let y = &x.f;
    x = box X {f: 4};  // Error reported here.
    *y
}
To make this clearer, consider this diagram showing the state of memory immediately before the re-assignment of x:
为了更加清晰,我们用图表来表明内存的状态,在重新赋值x之前:
    Stack               Exchange Heap

  x +-------------+
    | box {f:int} | ----+
  y +-------------+     |
    | &int        | ----+
    +-------------+     |    +---------+
                        +--> |  f: 3   |
                             +---------+
Once the reassignment occurs, the memory will look like this:
当重新赋值一发生,内存看起来如下:
    Stack               Exchange Heap

  x +-------------+          +---------+
    | box {f:int} | -------> |  f: 4   |
  y +-------------+          +---------+
    | &int        | ----+
    +-------------+     |    +---------+
                        +--> | (freed) |
                             +---------+
Here you can see that the variable y still points at the old box, which has been freed.
这里你可以看到变量y依然指向老的封箱,但它已经被释放回收了. In fact, the compiler can apply the same kind of reasoning to any memory that is (uniquely) owned by the stack frame. So we could modify the previous example to introduce additional owned pointers and structs, and the compiler will still be able to detect possible mutations:
事实上,编译器可以应用同样的理由到(唯一的)堆栈框架(frame)所拥有的任何内存. 因此我们可以修改以前的例子来说明额外的自有的指针和结构,编译器依然可以检查到 可能的改变:
fn example3() -> int {
    struct R { g: int }
    struct S { f: Box<R> }

    let mut x = box S {f: box R {g: 3}};
    let y = &x.f.g;
    x = box S {f: box R {g: 4}};  // Error reported here.
    x.f = box R {g: 5};           // Error reported here.
    *y
}
In this case, two errors are reported, one when the variable x is modified and another when x.f is modified. Either modification would invalidate the pointer y.
在这个例子里,两个错误被报告,一个变量x被修改时,另外一个x.f被修改时.任何其中一个修改都能造成指针y的报废.

7 Borrowing and enums(借用和枚举)

The previous example showed that the type system forbids any borrowing of owned boxes found in aliasable, mutable memory. This restriction prevents pointers from pointing into freed memory. There is one other case where the compiler must be very careful to ensure that pointers remain valid: pointers into the interior of an enum.
前面的例子显示了类型系统禁止任何自有的封箱的别名借用,内存修改. 这个限制阻止了指针指向一个被释放的内存.这是另外一个编译器必须仔细确保指针合法的例子: 指向一个枚举enum的内部. As an example, let’s look at the following shape type that can represent both rectangles and circles:
如例子,shape类型表明矩形和圆周:
struct Point {x: f64, y: f64}; // as before
struct Size {w: f64, h: f64}; // as before
enum Shape {
    Circle(Point, f64),   // origin, radius
    Rectangle(Point, Size)  // upper-left, dimensions
}
Now we might write a function to compute the area of a shape. This function takes a reference to a shape, to avoid the need for copying.
现在我们写一个函数计算形状的面积.这个函数使用shape引用,避免复制的开销.
fn compute_area(shape: &Shape) -> f64 {
    match *shape {
        Circle(_, radius) => 0.5 * tau * radius * radius,
        Rectangle(_, ref size) => size.w * size.h
    }
}
The first case matches against circles. Here, the pattern extracts the radius from the shape variant and the action uses it to compute the area of the circle. (Like any up-to-date engineer, we use the tau circle constant and not that dreadfully outdated notion of pi).
第一个例子匹配circle.模式从shape变量抽取radius并用它来计算园的面积(作为一个最新潮的工程师,我们使用tau circle constan 而不是可怕过时的圆周率概念) The second match is more interesting. Here we match against a rectangle and extract its size: but rather than copy the size struct, we use a by-reference binding to create a pointer to it. In other words, a pattern binding like ref size binds the name size to a pointer of type &size into the interior of the enum.
第二个例子就比较有趣了.这里我们匹配矩形并且抽取它的尺寸size:为了避免值复制size结构,我们使用通过引用 绑定来建立一个指针指向它.换句话说,pattern绑定 ref size 绑定一个名字size作为类型&size 枚举内部的指针. To make this more clear, let's look at a diagram of memory layout in the case where shape points at a rectangle:
为了更加清晰的说明这个,我们再次用内存布局图表来说明这个例子里shape指向的矩形:
Stack             Memory

+-------+         +---------------+
| shape | ------> | rectangle(    |
+-------+         |   {x: f64,    |
| size  | -+      |    y: f64},   |
+-------+  +----> |   {w: f64,    |
                  |    h: f64})   |
                  +---------------+
Here you can see that rectangular shapes are composed of five words of memory. The first is a tag indicating which variant this enum is (rectangle, in this case). The next two words are the x and y fields for the point and the remaining two are the w and h fields for the size. The binding size is then a pointer into the inside of the shape.
你可以看到矩形形状是由5个单词的内存组成.第一个是标记表明这个枚举变量是rectangle. 下面该点的两个单词x和y字段以及size的w和h字段.绑定size 是一个指针指向shape内部。 Perhaps you can see where the danger lies: if the shape were somehow to be reassigned, perhaps to a circle, then although the memory used to store that shape value would still be valid, it would have a different type! The following diagram shows what memory would look like if code overwrote shape with a circle:
也许你可以明白危险存在在哪里了:如果形状shape被某种给重新赋值了,也许是园,虽然 内存储存shape值是合法的,它却有了一个不同的类型!,下列图表展示了内存也许可以被代码用圆覆盖shape:
Stack             Memory

+-------+         +---------------+
| shape | ------> | circle(       |
+-------+         |   {x: f64,    |
| size  | -+      |    y: f64},   |
+-------+  +----> |   f64)        |
                  |               |
                  +---------------+
As you can see, the size pointer would be pointing at a f64 instead of a struct. This is not good: dereferencing the second field of a f64 as if it were a struct with two fields would be a memory safety violation.
如你所见size指针指向f64代替了结构,这是不好的:解应用第二个字段f64将它作为有两个字段的结构, 会造成内存安全侵害。 So, in fact, for every ref binding, the compiler will impose the same rules as the ones we saw for borrowing the interior of an owned box: it must be able to guarantee that the enum will not be overwritten for the duration of the borrow. In fact, the compiler would accept the example we gave earlier. The example is safe because the shape pointer has type &Shape, which means "reference to immutable memory containing a shape". If, however, the type of that pointer were &mut Shape, then the ref binding would be ill-typed. Just as with owned boxes, the compiler will permit ref bindings into data owned by the stack frame even if the data are mutable, but otherwise it requires that the data reside in immutable memory.
因此,实际中对于每一个ref绑定,编译器将使用同样的规则如同先前借用自有的封箱内部: 它必须能担保enum枚举在被借用期间不会被覆盖.实际上,编辑器会接受我们先前的例子. 该例子是安全的因为shape指针有类型&Shape,这意味这引用到包含一个shap的不可变内存. 如果,该指针的类型是&mut Shape,那么该ref绑定是类型不正确的ill-typed.如同自有的封箱,编译器允许ref绑定到 属于堆栈框架的数据,甚至数据是可变的。除此之外它要求数据必须驻留在不可变内存内.

8 Returning references(返回引用)

So far, all of the examples we have looked at, use references in a “downward” direction. That is, a method or code block creates a reference, then uses it within the same scope. It is also possible to return references as the result of a function, but as we'll see, doing so requires some explicit annotation.
到目前为止,我们所看的所有的例子,都是在“向下”方向使用引用,就是一个方法或者一个代码块建立一个引用,然后再同一个范围内使用 引用.当然从一个函数返回一个引用也是可能的,但必须需要显式的注解. For example, we could write a subroutine like this:
如例,我们可以这样写子程序:
struct Point {x: f64, y: f64}
fn get_x<'r>(p: &'r Point) -> &'r f64 { &p.x }
Here, the function get_x() returns a pointer into the structure it was given. The type of the parameter (&'r Point) and return type (&'r f64) both use a new syntactic form that we have not seen so far. Here the identifier r names the lifetime of the pointer explicitly. So in effect, this function declares that it takes a pointer with lifetime r and returns a pointer with that same lifetime.
这里函数get_x()返回一个它使用的结构指针.类型参数(&'r Point)以及范围类型&'r f64.二者都使用新的句法形式,我们从没见过. 这里的标识 r 命名了一个显式指针生命周期.效果就是,该函数声明它使用一个生命周期是r的指针并返回一个同样生命周期的指针 In general, it is only possible to return references if they are derived from a parameter to the procedure. In that case, the pointer result will always have the same lifetime as one of the parameters; named lifetimes indicate which parameter that is.
一般来说,只有当引用是派生自过程的参数才有可能返回一个引用. 这种状况下,指针结果总是和其中一个参数有同样的生命周期;通过命名的生命周期指示符 来表明是哪一个参数 In the previous examples, function parameter types did not include a lifetime name. In those examples, the compiler simply creates a fresh name for the lifetime automatically: that is, the lifetime name is guaranteed to refer to a distinct lifetime from the lifetimes of all other parameters.
在前面的例子里,函数参数类型不包括生命周期名字.这些例子里,编译器简单 自动建立一个生命周期新名字:这个生命周期的名字用来保证引用所有其他参数不同的生命周期 Named lifetimes that appear in function signatures are conceptually the same as the other lifetimes we have seen before, but they are a bit abstract: they don’t refer to a specific expression within get_x(), but rather to some expression within the caller of get_x(). The lifetime r is actually a kind of lifetime parameter: it is defined by the caller to get_x(), just as the value for the parameter p is defined by that caller.
命名生命周期在函数签名中出现概念上和我们以前看到的其他生命周期一样,但它们有点抽象: 它们并不在函数get_x()中引用特定的表达式,而是出现在调用者调用get_x()的表达式中. 生命周期实际上是一种生命周期参数:它由调用者来定义 给函数get_x(),参数p的值是由调用者定义的。 In any case, whatever the lifetime of r is, the pointer produced by &p.x always has the same lifetime as p itself: a pointer to a field of a struct is valid as long as the struct is valid. Therefore, the compiler accepts the function get_x().
从所有情况来看,无论生命周期怎样,有&p.x产生的指针总是和p自身有同样的生命周期: 一个结构字段的指针是合法性和结构的合法性一样长.因此,编译器接受函数get_x() To emphasize this point, let’s look at a variation on the example, this time one that does not compile:
为了强调这一点,我们看看例子中的变量,此时不能被编译:
struct Point {x: f64, y: f64}
fn get_x_sh(p: @Point) -> &f64 {
    &p.x // Error reported here
}
Here, the function get_x_sh() takes a managed box as input and returns a reference. As before, the lifetime of the reference that will be returned is a parameter (specified by the caller). That means that get_x_sh() promises to return a reference that is valid for as long as the caller would like: this is subtly different from the first example, which promised to return a pointer that was valid for as long as its pointer argument was valid.
这里函数get_x_sh()使用可管理的封箱作为输入然后返回一个引用.如前所述,将被返回的引用 的生命周期是一个参数(由调用者指定).这意味着get_x_sh()承诺返回的引用只要调用者喜欢也是合法的: 这和第一个例子有点微妙的不同,它承诺返回的指针是合法的只要指针参数是合法的。 Within get_x_sh(), we see the expression &p.x which takes the address of a field of a managed box. The presence of this expression implies that the compiler must guarantee that, so long as the resulting pointer is valid, the managed box will not be reclaimed by the garbage collector. But recall that get_x_sh() also promised to return a pointer that was valid for as long as the caller wanted it to be. Clearly, get_x_sh() is not in a position to make both of these guarantees; in fact, it cannot guarantee that the pointer will remain valid at all once it returns, as the parameter p may or may not be live in the caller. Therefore, the compiler will report an error here.
在get_x_sh()函数里,我们看到表达式&p.x是从一个可管理的封箱里获取字段的地址. 这个表达式编译器必须保证。只要结果指针是合法的,可管理的封箱将不会被垃圾收集器回收. 但是再次调用get_x_sh()也承诺返回的指针也如调用者所要求的是合法的.很清晰, get_x_sh()无法做到这来年改革保证.实际上,它不能担保被返回的指针和参数p一样保持合法, 或者在调用者里不再存活因此,编译器将报告一个错误. In general, if you borrow a managed (or owned) box to create a reference, it will only be valid within the function and cannot be returned. This is why the typical way to return references is to take references as input (the only other case in which it can be legal to return a reference is if it points at a static constant).
一般的,如果你借用一个可管理的(或者自有的)封箱来建立一个引用,它仅仅在函数里合法而不能被返回. 这就是为什么返回引用的典型方法是使用引用作为输入.唯一一个例外的情况而且是合法的返回一个引用 是它指向一个静态常量)

9 Named lifetimes(命名的生命周期)

Lifetimes can be named and referenced. For example, the special lifetime 'static, which does not go out of scope, can be used to create global variables and communicate between tasks (see the manual for use cases).
生命周期可以被命名和引用.比如,特殊的生命周期'static,不用出范围,就可以用于建立全局的变量 而在任务task之间通讯(可以参考手册)l

9.1 Parameter Lifetimes(参数生命周期)

Named lifetimes allow for grouping of parameters by lifetime. For example, consider this function:
命名的生命周期允许根据生命周期来分组参数,比如,考虑这个函数:
fn select<'r, T>(shape: &'r Shape, threshold: f64,
                 a: &'r T, b: &'r T) -> &'r T {
    if compute_area(shape) > threshold {a} else {b}
}
This function takes three references and assigns each the same lifetime r. In practice, this means that, in the caller, the lifetime r will be the intersection of the lifetime of the three region parameters. This may be overly conservative, as in this example:
该函数使用三个引用并且使用同样的生命周期 r.实际中,对调用者这意味着 生命周期r将使用这三个区域参数的生命周期的交集。这或许过于保守了,如这个例子:
                                                     // -+ r
fn select_based_on_unit_circle<'r, T>(               //  |-+ B
    threshold: f64, a: &'r T, b: &'r T) -> &'r T {   //  | |
                                                     //  | |
    let shape = Circle(Point {x: 0., y: 0.}, 1.);    //  | |
    select(&shape, threshold, a, b)                  //  | |
}                                                    //  |-+
                                                     // -+
In this call to select(), the lifetime of the first parameter shape is B, the function body. Both of the second two parameters a and b share the same lifetime, r, which is a lifetime parameter of select_based_on_unit_circle(). The caller will infer the intersection of these two lifetimes as the lifetime of the returned value, and hence the return value of select() will be assigned a lifetime of B. This will in turn lead to a compilation error, because select_based_on_unit_circle() is supposed to return a value with the lifetime r.
在这个调用select(),第一个参数的生命周期是B,函数的主体。参数a和b共享同一个生命周期 r- 函数select_based_on_unit_circle()的生命周期参数.调用者将推断这两个生命周期的交集作为返回值的生命周期. 当然select()的返回值将被赋予生命周期B.这将导致编译错误:因为select_based_on_unit_circle() 假定返回值的生命周期是r. To address this, we can modify the definition of select() to distinguish the lifetime of the first parameter from the lifetime of the latter two. After all, the first parameter is not being returned. Here is how the new select() might look:
既然定位了这个问题,我们可以修改select()定义来第一个参数的生命周期来和后面其他两个参数区别开来。
fn select<'r, 'tmp, T>(shape: &'tmp Shape, threshold: f64,
                       a: &'r T, b: &'r T) -> &'r T {
    if compute_area(shape) > threshold {a} else {b}
}
Here you can see that shape's lifetime is now named tmp. The parameters a, b, and the return value all have the lifetime r. However, since the lifetime tmp is not returned, it would be more concise to just omit the named lifetime for shape altogether:
你可以看到shape的生命周期现在命名为tmp.参数a,b以及返回值有同样的生命周期。但是由于生命周期tmp不能被返回, 它可以更加简洁忽略掉shape的命名的生命周期:
fn select<'r, T>(shape: &Shape, threshold: f64,
                 a: &'r T, b: &'r T) -> &'r T {
    if compute_area(shape) > threshold {a} else {b}
}
This is equivalent to the previous definition.
这个相当于前面的定义.

9.2 Labeled Control Structures(标记的控制结构)

Named lifetime notation can also be used to control the flow of execution:
命名的生命周期符号可以用于控制执行流程:
'h: for i in range(0,10) {
    'g: loop {
        if i % 2 == 0 { continue 'h; }
        if i == 9 { break 'h; }
        break 'g;
    }
}
Note: Labelled breaks are not currently supported within while loops.
注意:标记的终端现在不支持在while和loops内部.
Named labels are hygienic and can be used safely within macros. See the macros guide section on hygiene for more details.
命名的标注是健康的可以安全的用于宏里.参看宏指引部分有关健康章节更多的细节。

10 Conclusion(总结)

So there you have it: a (relatively) brief tour of the lifetime system. For more details, we refer to the (yet to be written) reference document on references, which will explain the full notation and give more examples.
至此,你已经有了相对而言简要的生命周期系统的游历.更多的细节,我们参考(依然在写) 引用文档有关引用部分,将解释所有的符号给出更多例子.
Copyright © 2011-2014 The Rust Project Developers. Licensed under the Apache License, Version 2.0 or the MIT license, at your option.
This file may not be copied, modified, or distributed except according to those terms.